Skip to content

Commit a82d2be

Browse files
committed
Refactor Env API; Optimize casting and fix local reference leaks
1 parent 1989162 commit a82d2be

File tree

9 files changed

+326
-267
lines changed

9 files changed

+326
-267
lines changed

java-spaghetti-gen/src/emit_rust/fields.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,7 @@ impl<'a> Field<'a> {
173173
writeln!(
174174
out,
175175
"{indent} \
176-
let __jni_field = __FIELD.get_or_init(|| \
177-
::java_spaghetti::JFieldID::from_raw(__jni_env.require_{}field(__jni_class, {}, {}))\
178-
).as_raw();",
176+
let __jni_field = *__FIELD.get_or_init(|| __jni_env.require_{}field(__jni_class, {}, {}));",
179177
if self.java.is_static() { "static_" } else { "" },
180178
StrEmitter(self.java.name()),
181179
StrEmitter(FieldSigWriter(self.java.descriptor()))
@@ -228,9 +226,7 @@ impl<'a> Field<'a> {
228226
writeln!(
229227
out,
230228
"{indent} \
231-
let __jni_field = __FIELD.get_or_init(|| \
232-
::java_spaghetti::JFieldID::from_raw(__jni_env.require_{}field(__jni_class, {}, {}))\
233-
).as_raw();",
229+
let __jni_field = *__FIELD.get_or_init(|| __jni_env.require_{}field(__jni_class, {}, {}));",
234230
if self.java.is_static() { "static_" } else { "" },
235231
StrEmitter(self.java.name()),
236232
StrEmitter(FieldSigWriter(self.java.descriptor()))

java-spaghetti-gen/src/emit_rust/methods.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,7 @@ impl<'a> Method<'a> {
224224
writeln!(
225225
out,
226226
"{indent} \
227-
let __jni_method = __METHOD.get_or_init(|| \
228-
::java_spaghetti::JMethodID::from_raw(__jni_env.require_{}method(__jni_class, {}, {}))\
229-
).as_raw();",
227+
let __jni_method = *__METHOD.get_or_init(|| __jni_env.require_{}method(__jni_class, {}, {}));",
230228
if self.java.is_static() { "static_" } else { "" },
231229
StrEmitter(self.java.name()),
232230
StrEmitter(MethodSigWriter(self.java.descriptor()))

java-spaghetti-gen/src/emit_rust/structs.rs

+15-13
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,22 @@ impl Struct {
119119
let rust_name = &self.rust.struct_name;
120120
writeln!(out, "{attributes}{visibility} enum {rust_name}{{}}")?;
121121
if !self.java.is_static() {
122-
writeln!(out, "unsafe impl ::java_spaghetti::ReferenceType for {rust_name} {{}}")?;
122+
writeln!(
123+
out,
124+
"unsafe impl ::java_spaghetti::ReferenceType for {rust_name} {{\
125+
\n fn jni_get_class(__jni_env: ::java_spaghetti::Env) -> &'static ::java_spaghetti::JClass {{\
126+
\n Self::__class_global_ref(__jni_env)\
127+
\n }}\
128+
\n}}",
129+
)?;
123130
}
124131
writeln!(
125132
out,
126133
"unsafe impl ::java_spaghetti::JniType for {rust_name} {{\
127-
\n fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {{\
128-
\n callback({})\
129-
\n }}\
130-
\n}}",
134+
\n fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {{\
135+
\n callback({})\
136+
\n }}\
137+
\n}}",
131138
StrEmitter(self.java.path().as_str()),
132139
)?;
133140

@@ -156,15 +163,10 @@ impl Struct {
156163
writeln!(
157164
out,
158165
"\
159-
\nfn __class_global_ref(__jni_env: ::java_spaghetti::Env) -> ::java_spaghetti::sys::jobject {{\
160-
\n static __CLASS: ::std::sync::OnceLock<::java_spaghetti::Global<{}>> = ::std::sync::OnceLock::new();\
161-
\n __CLASS.get_or_init(|| unsafe {{\
162-
\n ::java_spaghetti::Local::from_raw(__jni_env, __jni_env.require_class({})).as_global()\
163-
\n }}).as_raw()\
166+
\nfn __class_global_ref(__jni_env: ::java_spaghetti::Env) -> &'static ::java_spaghetti::JClass {{\
167+
\n static _CLASS: ::std::sync::OnceLock<::java_spaghetti::JClass> = ::std::sync::OnceLock::new();\
168+
\n _CLASS.get_or_init(|| unsafe {{ __jni_env.require_class({}) }})\
164169
\n}}",
165-
context
166-
.java_to_rust_path(Id("java/lang/Object"), &self.rust.mod_)
167-
.unwrap(),
168170
StrEmitter(self.java.path().as_str()),
169171
)?;
170172

java-spaghetti/src/array.rs

+33-16
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use std::marker::PhantomData;
22
use std::ops::{Bound, RangeBounds};
33
use std::ptr::null_mut;
4+
use std::sync::OnceLock;
45

56
use jni_sys::*;
67

7-
use crate::{AsArg, Env, JniType, Local, Ref, ReferenceType, ThrowableType};
8+
use crate::{AsArg, Env, JClass, JniType, Local, Ref, ReferenceType, ThrowableType};
89

910
/// A Java Array of some POD-like type such as bool, jbyte, jchar, jshort, jint, jlong, jfloat, or jdouble.
1011
///
@@ -43,6 +44,11 @@ where
4344
array
4445
}
4546

47+
/// Uses env.GetArrayLength to get the length of the java array, returns true if it is 0.
48+
fn is_empty(self: &Ref<'_, Self>) -> bool {
49+
self.len() == 0
50+
}
51+
4652
/// Uses env.GetArrayLength + env.Get{Type}ArrayRegion to read the contents of the java array from range into a new Vec.
4753
fn get_region_as_vec(self: &Ref<'_, Self>, range: impl RangeBounds<usize>) -> Vec<T> {
4854
let len = self.len();
@@ -80,7 +86,12 @@ macro_rules! primitive_array {
8086
/// A [PrimitiveArray] implementation.
8187
pub enum $name {}
8288

83-
unsafe impl ReferenceType for $name {}
89+
unsafe impl ReferenceType for $name {
90+
fn jni_get_class(env: Env) -> &'static JClass {
91+
static CLASS_CACHE: OnceLock<JClass> = OnceLock::new();
92+
CLASS_CACHE.get_or_init(|| Self::static_with_jni_type(|t| unsafe { env.require_class(t) }))
93+
}
94+
}
8495
unsafe impl JniType for $name {
8596
fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
8697
callback($type_str)
@@ -89,7 +100,7 @@ macro_rules! primitive_array {
89100

90101
impl PrimitiveArray<$type> for $name {
91102
fn new<'env>(env: Env<'env>, size: usize) -> Local<'env, Self> {
92-
assert!(size <= std::i32::MAX as usize); // jsize == jint == i32
103+
assert!(size <= i32::MAX as usize); // jsize == jint == i32
93104
let size = size as jsize;
94105
let jnienv = env.as_raw();
95106
unsafe {
@@ -116,8 +127,8 @@ macro_rules! primitive_array {
116127
}
117128

118129
fn get_region(self: &Ref<'_, Self>, start: usize, elements: &mut [$type]) {
119-
assert!(start <= std::i32::MAX as usize); // jsize == jint == i32
120-
assert!(elements.len() <= std::i32::MAX as usize); // jsize == jint == i32
130+
assert!(start <= i32::MAX as usize); // jsize == jint == i32
131+
assert!(elements.len() <= i32::MAX as usize); // jsize == jint == i32
121132
let self_len = self.len() as jsize;
122133
let elements_len = elements.len() as jsize;
123134

@@ -139,8 +150,8 @@ macro_rules! primitive_array {
139150
}
140151

141152
fn set_region(self: &Ref<'_, Self>, start: usize, elements: &[$type]) {
142-
assert!(start <= std::i32::MAX as usize); // jsize == jint == i32
143-
assert!(elements.len() <= std::i32::MAX as usize); // jsize == jint == i32
153+
assert!(start <= i32::MAX as usize); // jsize == jint == i32
154+
assert!(elements.len() <= i32::MAX as usize); // jsize == jint == i32
144155
let self_len = self.len() as jsize;
145156
let elements_len = elements.len() as jsize;
146157

@@ -178,7 +189,12 @@ primitive_array! { DoubleArray, "[D\0", jdouble { NewDoubleArray SetDoubleArra
178189
/// See also [PrimitiveArray] for arrays of reference types.
179190
pub struct ObjectArray<T: ReferenceType, E: ThrowableType>(core::convert::Infallible, PhantomData<(T, E)>);
180191

181-
unsafe impl<T: ReferenceType, E: ThrowableType> ReferenceType for ObjectArray<T, E> {}
192+
unsafe impl<T: ReferenceType, E: ThrowableType> ReferenceType for ObjectArray<T, E> {
193+
fn jni_get_class(env: Env) -> &'static JClass {
194+
static CLASS_CACHE: OnceLock<JClass> = OnceLock::new();
195+
CLASS_CACHE.get_or_init(|| Self::static_with_jni_type(|t| unsafe { env.require_class(t) }))
196+
}
197+
}
182198

183199
unsafe impl<T: ReferenceType, E: ThrowableType> JniType for ObjectArray<T, E> {
184200
fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
@@ -188,8 +204,8 @@ unsafe impl<T: ReferenceType, E: ThrowableType> JniType for ObjectArray<T, E> {
188204

189205
impl<T: ReferenceType, E: ThrowableType> ObjectArray<T, E> {
190206
pub fn new<'env>(env: Env<'env>, size: usize) -> Local<'env, Self> {
191-
assert!(size <= std::i32::MAX as usize); // jsize == jint == i32
192-
let class = T::static_with_jni_type(|t| unsafe { env.require_class(t) });
207+
assert!(size <= i32::MAX as usize); // jsize == jint == i32
208+
let class = T::jni_get_class(env).as_raw();
193209
let size = size as jsize;
194210

195211
let object = unsafe {
@@ -210,10 +226,7 @@ impl<T: ReferenceType, E: ThrowableType> ObjectArray<T, E> {
210226
}
211227
}
212228

213-
pub fn new_from<'env>(
214-
env: Env<'env>,
215-
elements: impl ExactSizeIterator + Iterator<Item = impl AsArg<T>>,
216-
) -> Local<'env, Self> {
229+
pub fn new_from<'env>(env: Env<'env>, elements: impl ExactSizeIterator<Item = impl AsArg<T>>) -> Local<'env, Self> {
217230
let size = elements.len();
218231
let array = Self::new(env, size);
219232
let env = array.env().as_raw();
@@ -229,9 +242,13 @@ impl<T: ReferenceType, E: ThrowableType> ObjectArray<T, E> {
229242
unsafe { ((**env).v1_2.GetArrayLength)(env, self.as_raw()) as usize }
230243
}
231244

245+
pub fn is_empty(self: &Ref<'_, Self>) -> bool {
246+
self.len() == 0
247+
}
248+
232249
/// XXX: Expose this via std::ops::Index
233250
pub fn get<'env>(self: &Ref<'env, Self>, index: usize) -> Result<Option<Local<'env, T>>, Local<'env, E>> {
234-
assert!(index <= std::i32::MAX as usize); // jsize == jint == i32 XXX: Should maybe be treated as an exception?
251+
assert!(index <= i32::MAX as usize); // jsize == jint == i32 XXX: Should maybe be treated as an exception?
235252
let index = index as jsize;
236253
let env = self.env();
237254
let result = unsafe {
@@ -248,7 +265,7 @@ impl<T: ReferenceType, E: ThrowableType> ObjectArray<T, E> {
248265

249266
/// XXX: I don't think there's a way to expose this via std::ops::IndexMut sadly?
250267
pub fn set<'env>(self: &Ref<'env, Self>, index: usize, value: impl AsArg<T>) -> Result<(), Local<'env, E>> {
251-
assert!(index <= std::i32::MAX as usize); // jsize == jint == i32 XXX: Should maybe be treated as an exception?
268+
assert!(index <= i32::MAX as usize); // jsize == jint == i32 XXX: Should maybe be treated as an exception?
252269
let index = index as jsize;
253270
let env = self.env();
254271
unsafe {

0 commit comments

Comments
 (0)