Skip to content

Commit 7566fd1

Browse files
committed
runtime/native: stub jvm.h methods
These are the methods that the runtime provides to other native libraries. They're used by the OpenJDK native libraries, and seem to be loaded eagerly, so a bunch of stubs were necessary. None of the stubs are hit yet, since the runtime still has a preference for the VM builtin methods.
1 parent 15f5c2f commit 7566fd1

File tree

31 files changed

+1336
-69
lines changed

31 files changed

+1336
-69
lines changed

jni/src/env/vm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ impl super::JniEnv {
1515
return Err(JniError::Unknown);
1616
}
1717

18-
Ok(unsafe { JavaVm::from_raw(vm) })
18+
Ok(unsafe { JavaVm::from_raw(unsafe { *vm }) })
1919
}
2020
}

jni/src/java_vm.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::env::JniEnv;
99
use crate::error::{JniError, Result};
1010
use crate::version::JniVersion;
1111

12+
use std::cell::UnsafeCell;
1213
use std::ffi::c_void;
1314
use std::path::PathBuf;
1415

@@ -120,7 +121,7 @@ impl JavaVmBuilder {
120121
}
121122

122123
let java_vm = JavaVm {
123-
inner: javavm_raw,
124+
inner: UnsafeCell::new(unsafe { *javavm_raw }),
124125
_libjvm: Some(libjvm),
125126
};
126127
let jni_env = unsafe { JniEnv::from_raw(jni_env_raw.cast::<JNIEnv>()) };
@@ -140,15 +141,15 @@ fn default_libjvm_path() -> Option<PathBuf> {
140141
///
141142
/// See [`JavaVmBuilder`].
142143
pub struct JavaVm {
143-
inner: *mut jni_sys::JavaVM,
144+
inner: UnsafeCell<jni_sys::JavaVM>,
144145
// Not used outside of the original load, just kept here to prevent unloading.
145146
// Optional since it's also used in libjvm, where it, of course, isn't applicable.
146147
_libjvm: Option<platform::libs::Library>,
147148
}
148149

149150
impl PartialEq for JavaVm {
150151
fn eq(&self, other: &Self) -> bool {
151-
self.inner == other.inner
152+
self.inner.get() == other.inner.get()
152153
}
153154
}
154155

@@ -166,7 +167,7 @@ impl JavaVm {
166167
let ret;
167168
unsafe {
168169
let invoke_interface = self.as_invoke_interface();
169-
ret = ((*invoke_interface).DestroyJavaVM)(self.inner);
170+
ret = ((*invoke_interface).DestroyJavaVM)(self.inner.get());
170171
}
171172

172173
if let Some(err) = JniError::from_jint(ret) {
@@ -188,7 +189,8 @@ impl JavaVm {
188189
args_ptr = args.raw().cast_mut();
189190
}
190191

191-
ret = ((*invoke_interface).AttachCurrentThread)(self.inner, &raw mut env, args_ptr);
192+
ret =
193+
((*invoke_interface).AttachCurrentThread)(self.inner.get(), &raw mut env, args_ptr);
192194
}
193195

194196
if let Some(err) = JniError::from_jint(ret) {
@@ -221,7 +223,7 @@ impl JavaVm {
221223
let ret;
222224
unsafe {
223225
let invoke_interface = self.as_invoke_interface();
224-
ret = ((*invoke_interface).GetEnv)(self.inner, &raw mut env, version.into());
226+
ret = ((*invoke_interface).GetEnv)(self.inner.get(), &raw mut env, version.into());
225227
}
226228

227229
if let Some(err) = JniError::from_jint(ret) {
@@ -236,23 +238,23 @@ impl JavaVm {
236238
}
237239

238240
unsafe fn as_invoke_interface(&self) -> *const jni_sys::JNIInvokeInterface_ {
239-
self.inner as _
241+
unsafe { *self.inner.get() }
240242
}
241243
}
242244

243245
impl JavaVm {
244-
pub const fn raw(&self) -> *const jni_sys::JavaVM {
245-
self.inner.cast_const()
246+
pub const fn raw(&self) -> *mut jni_sys::JavaVM {
247+
self.inner.get()
246248
}
247249

248250
/// Create a [`JavaVm`] from a raw pointer
249251
///
250252
/// # Safety
251253
///
252254
/// The caller *must* ensure that the pointer provided was obtained from the VM.
253-
pub const unsafe fn from_raw(ptr: *mut jni_sys::JavaVM) -> Self {
255+
pub const unsafe fn from_raw(ptr: jni_sys::JavaVM) -> Self {
254256
Self {
255-
inner: ptr,
257+
inner: UnsafeCell::new(ptr),
256258
_libjvm: None,
257259
}
258260
}

native/macros/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ edition.workspace = true
77
license.workspace = true
88

99
[dependencies]
10-
syn = { workspace = true, features = ["full", "parsing", "proc-macro", "printing"] }
10+
syn = { workspace = true, features = ["full", "parsing", "proc-macro", "printing", "clone-impls"] }
1111
quote.workspace = true
1212
proc-macro2.workspace = true
1313

native/macros/src/call.rs

Lines changed: 121 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use proc_macro2::{Ident, Span};
22
use quote::{ToTokens, quote, quote_spanned};
33
use syn::spanned::Spanned;
44
use syn::{
5-
Abi, FnArg, GenericArgument, ItemFn, Pat, PatIdent, Path, PathArguments, ReturnType, Type,
6-
TypePath,
5+
Abi, FnArg, GenericArgument, ItemFn, Pat, PatIdent, PatType, Path, PathArguments, ReturnType,
6+
Type, TypePath,
77
};
88

99
// jni_sys types
@@ -176,6 +176,34 @@ parameter_types!(
176176
]
177177
);
178178

179+
enum ParameterType {
180+
Strict(SafeJniWrapperType),
181+
Loose(Box<Type>),
182+
}
183+
184+
impl ParameterType {
185+
fn to_raw(&self) -> proc_macro2::TokenStream {
186+
match self {
187+
ParameterType::Strict(inner) => inner.to_raw(),
188+
ParameterType::Loose(inner) => inner.to_token_stream(),
189+
}
190+
}
191+
192+
fn safe_conversion_fn(&self, param_name: Ident) -> proc_macro2::TokenStream {
193+
match self {
194+
ParameterType::Strict(inner) => inner.safe_conversion_fn(param_name),
195+
ParameterType::Loose(_inner) => param_name.to_token_stream(),
196+
}
197+
}
198+
199+
fn raw_conversion_fn(&self, param_name: Ident) -> proc_macro2::TokenStream {
200+
match self {
201+
ParameterType::Strict(inner) => inner.raw_conversion_fn(param_name),
202+
ParameterType::Loose(_inner) => param_name.to_token_stream(),
203+
}
204+
}
205+
}
206+
179207
pub enum Error {
180208
MissingAbi,
181209
BadAbi,
@@ -189,7 +217,7 @@ impl Error {
189217
pub fn into_syn(self, span: Span) -> syn::Error {
190218
match self {
191219
Error::MissingAbi => syn::Error::new(span, "Must specify an ABI"),
192-
Error::BadAbi => syn::Error::new(span, "Must specify \"system\" ABI"),
220+
Error::BadAbi => syn::Error::new(span, "Must specify valid ABI"),
193221
Error::MissingEnv => syn::Error::new(span, "First parameter must be a JniEnv"),
194222
Error::HasReceiver => syn::Error::new(span, "JNI functions must be freestanding"),
195223
Error::BadParameterType(ty) => syn::Error::new(
@@ -210,16 +238,16 @@ pub struct JniFn {
210238
pub errors: Vec<(Error, Span)>,
211239
}
212240

213-
pub fn generate(input: &ItemFn) -> JniFn {
241+
pub fn generate(input: &ItemFn, no_env: bool, no_strict_types: bool) -> JniFn {
214242
let mut errors = Vec::new();
215243
validate_abi(&mut errors, input);
216-
let params = validate_params(&mut errors, input);
217-
let return_ty = validate_return(&mut errors, input);
244+
let params = validate_params(&mut errors, input, no_env, no_strict_types);
245+
let return_ty = validate_return(&mut errors, input, no_strict_types);
218246

219247
let fn_name = &input.sig.ident;
220248
let raw_mod_name = Ident::new(&format!("raw_{}", fn_name), Span::call_site());
221249

222-
let extern_fn_def = generate_extern_fn(input, &params, return_ty);
250+
let extern_fn_def = generate_extern_fn(input, &params, return_ty, no_env);
223251
let extern_fn = quote! {
224252
mod #raw_mod_name {
225253
use super::*;
@@ -249,28 +277,59 @@ fn validate_abi(errors: &mut Vec<(Error, Span)>, fun: &ItemFn) {
249277
return;
250278
};
251279

252-
if name.value() != "system" {
280+
if name.value() != "system" && name.value() != "C" {
253281
errors.push((Error::BadAbi, fun.sig.span()));
254282
}
255283
}
256284

257285
fn validate_params(
258286
errors: &mut Vec<(Error, Span)>,
259287
fun: &ItemFn,
260-
) -> Vec<(Ident, SafeJniWrapperType)> {
288+
no_env: bool,
289+
no_strict_types: bool,
290+
) -> Vec<(Ident, ParameterType)> {
291+
fn parse_type(
292+
fun: &ItemFn,
293+
no_env: bool,
294+
index: usize,
295+
param: &FnArg,
296+
arg: &PatType,
297+
) -> Result<Option<SafeJniWrapperType>, (Error, Span)> {
298+
let Type::Path(TypePath { path, .. }) = &*arg.ty else {
299+
return Err((
300+
Error::BadParameterType(arg.ty.to_token_stream().to_string()),
301+
arg.ty.span(),
302+
));
303+
};
304+
305+
let Some((path_str, _optional)) = path_str(path) else {
306+
return Err((
307+
Error::BadParameterType(arg.ty.to_token_stream().to_string()),
308+
param.span(),
309+
));
310+
};
311+
if index == 0 && !no_env {
312+
const JNI_ENV_PATHS: &[&str] = &["JniEnv", "jni::env::JniEnv"];
313+
314+
if !JNI_ENV_PATHS.contains(&path_str.as_str()) {
315+
return Err((Error::MissingEnv, fun.sig.span()));
316+
}
317+
318+
// Implicit
319+
return Ok(None);
320+
}
321+
322+
match SafeJniWrapperType::from_str(&path_str, false) {
323+
Some(parsed) => Ok(Some(parsed)),
324+
None => Err((Error::BadParameterType(path_str), param.span())),
325+
}
326+
}
327+
261328
let mut params = Vec::new();
262329
for (index, param) in fun.sig.inputs.iter().enumerate() {
263330
match param {
264331
FnArg::Receiver(receiver) => errors.push((Error::HasReceiver, receiver.span())),
265332
FnArg::Typed(arg) => {
266-
let Type::Path(TypePath { path, .. }) = &*arg.ty else {
267-
errors.push((
268-
Error::BadParameterType(arg.ty.to_token_stream().to_string()),
269-
arg.ty.span(),
270-
));
271-
continue;
272-
};
273-
274333
let Pat::Ident(PatIdent { ident, .. }) = &*arg.pat else {
275334
errors.push((
276335
Error::BadParameterType(arg.ty.to_token_stream().to_string()),
@@ -279,42 +338,38 @@ fn validate_params(
279338
continue;
280339
};
281340

282-
let Some((path_str, _optional)) = path_str(path) else {
283-
errors.push((
284-
Error::BadParameterType(arg.ty.to_token_stream().to_string()),
285-
param.span(),
286-
));
287-
continue;
288-
};
289-
if index == 0 {
290-
const JNI_ENV_PATHS: &[&str] = &["JniEnv", "jni::env::JniEnv"];
291-
292-
if !JNI_ENV_PATHS.contains(&path_str.as_str()) {
293-
errors.push((Error::MissingEnv, fun.sig.span()));
294-
continue;
295-
}
341+
match parse_type(fun, no_env, index, param, arg) {
342+
Ok(Some(parsed)) => params.push((ident.clone(), ParameterType::Strict(parsed))),
343+
Ok(None) => {},
344+
Err(e) => {
345+
if no_strict_types {
346+
params.push((ident.clone(), ParameterType::Loose(arg.ty.clone())));
347+
continue;
348+
}
296349

297-
continue;
350+
errors.push(e);
351+
},
298352
}
299-
300-
let Some(parsed) = SafeJniWrapperType::from_str(&path_str, false) else {
301-
errors.push((Error::BadParameterType(path_str), param.span()));
302-
continue;
303-
};
304-
305-
params.push((ident.clone(), parsed));
306353
},
307354
}
308355
}
309356

310357
params
311358
}
312359

313-
fn validate_return(errors: &mut Vec<(Error, Span)>, fun: &ItemFn) -> Option<SafeJniWrapperType> {
360+
fn validate_return(
361+
errors: &mut Vec<(Error, Span)>,
362+
fun: &ItemFn,
363+
no_strict_types: bool,
364+
) -> Option<ParameterType> {
314365
let ReturnType::Type(_, ty) = &fun.sig.output else {
315366
return None;
316367
};
317368

369+
if no_strict_types {
370+
return Some(ParameterType::Loose(ty.clone()));
371+
}
372+
318373
let Type::Path(TypePath { path, .. }) = &**ty else {
319374
errors.push((
320375
Error::BadReturnType(ty.to_token_stream().to_string()),
@@ -335,7 +390,7 @@ fn validate_return(errors: &mut Vec<(Error, Span)>, fun: &ItemFn) -> Option<Safe
335390
return None;
336391
};
337392

338-
Some(parsed)
393+
Some(ParameterType::Strict(parsed))
339394
}
340395

341396
fn path_str(path: &Path) -> Option<(String, bool)> {
@@ -375,22 +430,38 @@ fn path_str(path: &Path) -> Option<(String, bool)> {
375430

376431
fn generate_extern_fn(
377432
fun: &ItemFn,
378-
params: &[(Ident, SafeJniWrapperType)],
379-
return_type: Option<SafeJniWrapperType>,
433+
params: &[(Ident, ParameterType)],
434+
return_type: Option<ParameterType>,
435+
no_env: bool,
380436
) -> proc_macro2::TokenStream {
381437
let fn_name = &fun.sig.ident;
382438

383-
let sys_params = params.iter().map(|(param, parsed_ty)| {
439+
let mut sys_params = Vec::new();
440+
if !no_env {
441+
sys_params.push(quote! { env: *mut ::jni::sys::JNIEnv });
442+
}
443+
444+
sys_params.extend(params.iter().map(|(param, parsed_ty)| {
384445
let ty = parsed_ty.to_raw();
385446
quote! { #param: #ty }
386-
});
447+
}));
448+
449+
let mut arg_conversions = Vec::new();
450+
if !no_env {
451+
arg_conversions.push(quote! { let env = unsafe { ::jni::env::JniEnv::from_raw(env) }; });
452+
}
387453

388-
let arg_conversions = params.iter().map(|(param, parsed_ty)| {
454+
arg_conversions.extend(params.iter().map(|(param, parsed_ty)| {
389455
let conversion = parsed_ty.safe_conversion_fn(param.clone());
390456
quote! { let #param = #conversion; }
391-
});
457+
}));
458+
459+
let mut all_param_names = Vec::new();
460+
if !no_env {
461+
all_param_names.push(Ident::new("env", Span::call_site()));
462+
}
392463

393-
let all_param_names = params.iter().map(|(param, _)| param);
464+
all_param_names.extend(params.iter().map(|(param, _)| param.clone()));
394465

395466
let result_ident = Ident::new("result", Span::call_site());
396467

@@ -408,11 +479,10 @@ fn generate_extern_fn(
408479
quote! {
409480
#[unsafe(no_mangle)]
410481
#[allow(non_snake_case)]
411-
pub unsafe extern "system" fn #fn_name(env: *mut ::jni::sys::JNIEnv, #(#sys_params),*) #ret {
412-
let env = unsafe { ::jni::env::JniEnv::from_raw(env) };
482+
pub unsafe extern "system" fn #fn_name(#(#sys_params),*) #ret {
413483
#(#arg_conversions)*
414484

415-
let #result_ident = super::#fn_name(env, #(#all_param_names),*);
485+
let #result_ident = super::#fn_name(#(#all_param_names),*);
416486
#to_raw_conversion
417487
}
418488
}

0 commit comments

Comments
 (0)