Skip to content

Commit 7617a5a

Browse files
committed
Add JNI-style global references
1 parent 258cd4e commit 7617a5a

8 files changed

Lines changed: 352 additions & 16 deletions

File tree

java_runtime/src/classes/java/lang/thread.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::time::Duration;
33

44
use java_class_proto::{JavaFieldProto, JavaMethodProto};
55
use java_constants::{FieldAccessFlags, MethodAccessFlags};
6-
use jvm::{ClassInstanceRef, Jvm, Result, runtime::JavaLangString};
6+
use jvm::{ClassInstanceRef, GlobalRef, Jvm, Result, runtime::JavaLangString};
77

88
use crate::{
99
RuntimeClassProto, RuntimeContext, SpawnCallback,
@@ -191,7 +191,7 @@ impl Thread {
191191
struct ThreadStartProxy {
192192
jvm: Jvm,
193193
thread_id: i32,
194-
this: ClassInstanceRef<Thread>,
194+
this: GlobalRef<Thread>,
195195
}
196196

197197
#[async_trait::async_trait]
@@ -226,7 +226,7 @@ impl Thread {
226226
}
227227
}
228228

229-
let mut this = self.this.clone();
229+
let mut this = (*self.this).clone();
230230
let cleanup = if let Err(error) = self.jvm.monitor_enter(&self.this).await {
231231
Err(error)
232232
} else {
@@ -253,12 +253,16 @@ impl Thread {
253253

254254
let id: i32 = jvm.invoke_virtual(&this, "hashCode", "()I", ()).await?;
255255

256+
let this = match jvm.new_global_ref(&this) {
257+
Some(this) => this,
258+
None => return Err(jvm.exception("java/lang/NullPointerException", "thread is null").await),
259+
};
256260
context.spawn(
257261
jvm,
258262
Box::new(ThreadStartProxy {
259263
jvm: jvm.clone(),
260264
thread_id: id,
261-
this: this.clone(),
265+
this,
262266
}),
263267
);
264268

jvm/src/garbage_collector.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::{ClassDefinition, ClassInstance, Field, JavaValue, Jvm, class_loader:
88
pub fn determine_garbage(
99
jvm: &Jvm,
1010
threads: &BTreeMap<u64, JvmThread>,
11+
global_references: &BTreeMap<u64, Box<dyn ClassInstance>>,
1112
all_class_instances: &HashSet<Box<dyn ClassInstance>>,
1213
classes: &BTreeMap<String, Class>,
1314
interned_strings: &[Box<dyn ClassInstance>],
@@ -30,6 +31,10 @@ pub fn determine_garbage(
3031
find_reachable_objects(jvm, x, &mut reachable_objects);
3132
});
3233

34+
global_references.values().for_each(|object| {
35+
find_reachable_objects(jvm, object, &mut reachable_objects);
36+
});
37+
3338
interned_strings.iter().for_each(|x| {
3439
find_reachable_objects(jvm, x, &mut reachable_objects);
3540
});

jvm/src/global_ref.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use alloc::{boxed::Box, collections::BTreeMap, sync::Arc};
2+
use core::{ops::Deref, sync::atomic::AtomicU64};
3+
4+
use parking_lot::RwLock;
5+
6+
use crate::{ClassInstance, ClassInstanceRef};
7+
8+
pub(crate) struct GlobalReferences {
9+
pub(crate) next_id: AtomicU64,
10+
pub(crate) objects: RwLock<BTreeMap<u64, Box<dyn ClassInstance>>>,
11+
}
12+
13+
pub struct GlobalRef<T> {
14+
pub(crate) references: Arc<GlobalReferences>,
15+
pub(crate) id: u64,
16+
pub(crate) reference: ClassInstanceRef<T>,
17+
}
18+
19+
impl<T> Deref for GlobalRef<T> {
20+
type Target = ClassInstanceRef<T>;
21+
22+
fn deref(&self) -> &Self::Target {
23+
&self.reference
24+
}
25+
}
26+
27+
impl<T> Drop for GlobalRef<T> {
28+
fn drop(&mut self) {
29+
self.references.objects.write().remove(&self.id);
30+
}
31+
}

jvm/src/jvm.rs

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use alloc::{borrow::ToOwned, boxed::Box, collections::BTreeMap, format, string::
44
use core::{
55
fmt::Debug,
66
iter,
7-
sync::atomic::{AtomicBool, Ordering},
7+
sync::atomic::{AtomicBool, AtomicU64, Ordering},
88
};
99

1010
use dyn_clone::clone_box;
@@ -17,13 +17,14 @@ use crate::{
1717
Result,
1818
array_class_instance::{ArrayRawBuffer, ArrayRawBufferMut},
1919
class_definition::ClassDefinition,
20-
class_instance::ClassInstance,
20+
class_instance::{ClassInstance, ClassInstanceRef},
2121
class_loader::{
2222
BootstrapClassLoader, BootstrapClassLoaderWrapper, Class, ClassLoaderWrapper, InitState, InitializationAction, JavaClassLoaderWrapper,
2323
},
2424
error::JavaError,
2525
field::Field,
2626
garbage_collector::determine_garbage,
27+
global_ref::{GlobalRef, GlobalReferences},
2728
invoke_arg::InvokeArg,
2829
method::Method,
2930
monitor::{Monitor, MonitorWait, MonitorWaitTimeout},
@@ -36,6 +37,7 @@ use crate::{
3637
struct JvmInner {
3738
classes: RwLock<BTreeMap<String, Class>>,
3839
threads: RwLock<BTreeMap<u64, JvmThread>>,
40+
global_references: Arc<GlobalReferences>,
3941
all_objects: RwLock<HashSet<Box<dyn ClassInstance>>>,
4042
string_pool: RwLock<BTreeMap<Vec<u16>, Box<dyn ClassInstance>>>,
4143
monitors: RwLock<BTreeMap<usize, Arc<Monitor>>>,
@@ -59,6 +61,10 @@ impl Jvm {
5961
inner: Arc::new(JvmInner {
6062
classes: RwLock::new(BTreeMap::new()),
6163
threads: RwLock::new(BTreeMap::new()),
64+
global_references: Arc::new(GlobalReferences {
65+
next_id: AtomicU64::new(0),
66+
objects: RwLock::new(BTreeMap::new()),
67+
}),
6268
all_objects: RwLock::new(HashSet::new()),
6369
string_pool: RwLock::new(BTreeMap::new()),
6470
monitors: RwLock::new(BTreeMap::new()),
@@ -107,6 +113,16 @@ impl Jvm {
107113

108114
jvm.inner.bootstrapping.store(false, Ordering::Relaxed);
109115

116+
let thread_id = (jvm.inner.get_current_thread_id)();
117+
jvm.inner
118+
.threads
119+
.write()
120+
.get_mut(&thread_id)
121+
.unwrap()
122+
.top_frame_mut()
123+
.local_variables_mut()
124+
.clear();
125+
110126
Ok(jvm)
111127
}
112128

@@ -188,7 +204,19 @@ impl Jvm {
188204

189205
self.ensure_initialized(&declaring_class).await?;
190206

191-
Ok(declaring_class.definition.get_static_field(&*field)?.into())
207+
let value = declaring_class.definition.get_static_field(&*field)?;
208+
if let JavaValue::Object(Some(instance)) = &value {
209+
let thread_id = (self.inner.get_current_thread_id)();
210+
self.inner
211+
.threads
212+
.write()
213+
.get_mut(&thread_id)
214+
.unwrap()
215+
.top_frame_mut()
216+
.local_variables_mut()
217+
.push(instance.clone());
218+
}
219+
Ok(value.into())
192220
} else {
193221
Err(self
194222
.exception("java/lang/NoSuchFieldError", &format!("{class_name}.{name}:{descriptor}"))
@@ -230,7 +258,19 @@ impl Jvm {
230258
let field = self.find_field(&*instance.class_definition(), name, descriptor)?;
231259

232260
if let Some(field) = field {
233-
Ok(instance.get_field(&*field)?.into())
261+
let value = instance.get_field(&*field)?;
262+
if let JavaValue::Object(Some(instance)) = &value {
263+
let thread_id = (self.inner.get_current_thread_id)();
264+
self.inner
265+
.threads
266+
.write()
267+
.get_mut(&thread_id)
268+
.unwrap()
269+
.top_frame_mut()
270+
.local_variables_mut()
271+
.push(instance.clone());
272+
}
273+
Ok(value.into())
234274
} else {
235275
Err(self
236276
.exception(
@@ -407,6 +447,15 @@ impl Jvm {
407447
if let Some(array) = array {
408448
let values = array.load(offset, count)?;
409449

450+
let thread_id = (self.inner.get_current_thread_id)();
451+
let mut threads = self.inner.threads.write();
452+
let local_variables = threads.get_mut(&thread_id).unwrap().top_frame_mut().local_variables_mut();
453+
values.iter().for_each(|value| {
454+
if let JavaValue::Object(Some(instance)) = value {
455+
local_variables.push(instance.clone());
456+
}
457+
});
458+
410459
Ok(iter::IntoIterator::into_iter(values).map(|x| x.into()).collect::<Vec<_>>())
411460
} else {
412461
Err(self.exception("java/lang/IllegalArgumentException", "Not an array").await)
@@ -761,11 +810,12 @@ impl Jvm {
761810

762811
let garbage = {
763812
let threads = self.inner.threads.read();
813+
let global_references = self.inner.global_references.objects.read();
764814
let all_objects = self.inner.all_objects.read();
765815
let classes = self.inner.classes.read();
766816
let interned_strings = self.interned_strings();
767817

768-
determine_garbage(self, &threads, &all_objects, &classes, &interned_strings)
818+
determine_garbage(self, &threads, &global_references, &all_objects, &classes, &interned_strings)
769819
};
770820

771821
let garbage_count = garbage.len();
@@ -888,6 +938,18 @@ impl Jvm {
888938
Ok(())
889939
}
890940

941+
pub fn new_global_ref<T>(&self, reference: &ClassInstanceRef<T>) -> Option<GlobalRef<T>> {
942+
let instance = reference.instance.as_ref()?.clone();
943+
let id = self.inner.global_references.next_id.fetch_add(1, Ordering::Relaxed);
944+
self.inner.global_references.objects.write().insert(id, instance);
945+
946+
Some(GlobalRef {
947+
references: self.inner.global_references.clone(),
948+
id,
949+
reference: reference.clone(),
950+
})
951+
}
952+
891953
pub fn detach_thread(&self) -> Result<()> {
892954
let thread_id = (self.inner.get_current_thread_id)();
893955
self.inner.threads.write().remove(&thread_id);
@@ -1043,13 +1105,25 @@ impl Jvm {
10431105
.write()
10441106
.get_mut(&thread_id)
10451107
.unwrap()
1046-
.push_java_frame(class, class_instance, &method_str);
1108+
.push_java_frame(class, class_instance, &method_str, &args);
10471109

10481110
let result = method.run(self, args).await;
10491111

10501112
tracing::trace!("Execute result: {result:?}");
10511113

1052-
self.inner.threads.write().get_mut(&thread_id).unwrap().pop_frame();
1114+
let returned_reference = match &result {
1115+
Ok(JavaValue::Object(Some(instance))) => Some(instance.clone()),
1116+
Err(JavaError::JavaException(exception)) => Some(exception.clone()),
1117+
_ => None,
1118+
};
1119+
{
1120+
let mut threads = self.inner.threads.write();
1121+
let thread = threads.get_mut(&thread_id).unwrap();
1122+
thread.pop_frame();
1123+
if let Some(returned_reference) = returned_reference {
1124+
thread.top_frame_mut().local_variables_mut().push(returned_reference);
1125+
}
1126+
}
10531127

10541128
if let Some(object) = &synchronized_object
10551129
&& let Err(error) = self.monitor_exit(object).await

jvm/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod class_loader;
1010
mod error;
1111
mod field;
1212
mod garbage_collector;
13+
mod global_ref;
1314
mod invoke_arg;
1415
mod jvm;
1516
mod method;
@@ -38,6 +39,7 @@ pub use self::{
3839
class_loader::BootstrapClassLoader,
3940
error::JavaError,
4041
field::Field,
42+
global_ref::GlobalRef,
4143
jvm::Jvm,
4244
method::Method,
4345
monitor::{MonitorWait, MonitorWaitTimeout},

jvm/src/thread.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use alloc::{
44
vec::Vec,
55
};
66

7-
use crate::{ClassInstance, class_loader::Class};
7+
use crate::{ClassInstance, JavaValue, class_loader::Class};
88

99
pub enum StackFrame {
1010
Java(JavaStackFrame),
@@ -49,12 +49,18 @@ impl JvmThread {
4949
self.java_thread = Some(java_thread);
5050
}
5151

52-
pub fn push_java_frame(&mut self, class: &Class, class_instance: Option<Box<dyn ClassInstance>>, method: &str) {
52+
pub fn push_java_frame(&mut self, class: &Class, class_instance: Option<Box<dyn ClassInstance>>, method: &str, args: &[JavaValue]) {
5353
self.stack.push(StackFrame::Java(JavaStackFrame {
5454
class: class.clone(),
5555
class_instance,
5656
method: method.to_string(),
57-
local_variables: Vec::new(),
57+
local_variables: args
58+
.iter()
59+
.filter_map(|arg| match arg {
60+
JavaValue::Object(Some(instance)) => Some(instance.clone()),
61+
_ => None,
62+
})
63+
.collect(),
5864
}));
5965
}
6066

0 commit comments

Comments
 (0)