Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion classfile/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ pub enum AttributeInfo {
MethodParameters(Vec<u8>), // TODO
NestMembers(Vec<u8>), // TODO
NestHost(Vec<u8>), // TODO
Unknown(Arc<String>, Vec<u8>),
}

impl AttributeInfo {
Expand All @@ -170,7 +171,8 @@ impl AttributeInfo {
"MethodParameters" => AttributeInfo::MethodParameters(info.to_vec()),
"NestMembers" => AttributeInfo::NestMembers(info.to_vec()),
"NestHost" => AttributeInfo::NestHost(info.to_vec()),
_ => return Err(nom::Err::Error(nom::error_position!(info, nom::error::ErrorKind::Switch))),
// unrecognized attributes must be silently ignored (JVMS 4.7.1)
_ => AttributeInfo::Unknown(name.clone(), info.to_vec()),
})
},
)
Expand Down
8 changes: 3 additions & 5 deletions java_runtime/src/classes/java/lang/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ impl Thread {
async fn call(&self) -> Result<()> {
tracing::trace!("Thread start");

self.jvm.attach_thread()?;
self.jvm.attach_thread(self.this.instance.clone()).await?;

let result: Result<()> = self.jvm.invoke_virtual(&self.this, "run", "()V", []).await;

Expand Down Expand Up @@ -202,10 +202,8 @@ impl Thread {
}

async fn current_thread(jvm: &Jvm, _: &mut RuntimeContext) -> Result<ClassInstanceRef<Self>> {
tracing::warn!("stub java.lang.Thread::currentThread()");
tracing::debug!("java.lang.Thread::currentThread()");

let thread = jvm.new_class("java/lang/Thread", "(Z)V", (true,)).await?;

Ok(thread.into())
Ok(jvm.current_java_thread().into())
}
}
4 changes: 2 additions & 2 deletions java_runtime/tests/classes/java/lang/test_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async fn test_wait() -> Result<()> {
#[async_trait::async_trait]
impl SpawnCallback for Notifier {
async fn call(&self) -> Result<()> {
self.jvm.attach_thread()?;
self.jvm.attach_thread(None).await?;

self.runtime.sleep(Duration::from_millis(100)).await;
self.notified.store(true, Ordering::Relaxed);
Expand Down Expand Up @@ -77,7 +77,7 @@ async fn test_wait_timeout() -> Result<()> {
#[async_trait::async_trait]
impl SpawnCallback for Notifier {
async fn call(&self) -> Result<()> {
self.jvm.attach_thread()?;
self.jvm.attach_thread(None).await?;

self.runtime.sleep(Duration::from_millis(1000)).await;
self.notified.store(true, Ordering::Relaxed);
Expand Down
4 changes: 4 additions & 0 deletions jvm/src/garbage_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ pub fn determine_garbage(
find_reachable_objects(jvm, x, &mut reachable_objects);
});

threads.values().filter_map(|thread| thread.java_thread()).for_each(|x| {
find_reachable_objects(jvm, x, &mut reachable_objects);
});

interned_strings.iter().for_each(|x| {
find_reachable_objects(jvm, x, &mut reachable_objects);
});
Expand Down
17 changes: 15 additions & 2 deletions jvm/src/jvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl Jvm {
}

// init startup thread
jvm.attach_thread()?;
jvm.attach_thread(None).await?;

// set java class for bootstrap classes
let classes = jvm.inner.classes.read().values().cloned().collect::<Vec<_>>();
Expand Down Expand Up @@ -822,11 +822,19 @@ impl Jvm {
Ok(())
}

pub fn attach_thread(&self) -> Result<()> {
// every attached thread owns a java/lang/Thread instance; pass the instance for threads
// started from java (Thread.start), or None to create one
pub async fn attach_thread(&self, java_thread: Option<Box<dyn ClassInstance>>) -> Result<()> {
let thread_id = (self.inner.get_current_thread_id)();
self.inner.threads.write().insert(thread_id, JvmThread::new());
self.push_native_frame();

let java_thread = match java_thread {
Some(x) => x,
None => self.new_class("java/lang/Thread", "(Z)V", (true,)).await?,
};
self.inner.threads.write().get_mut(&thread_id).unwrap().set_java_thread(java_thread);

Ok(())
}

Expand All @@ -837,6 +845,11 @@ impl Jvm {
Ok(())
}

pub fn current_java_thread(&self) -> Box<dyn ClassInstance> {
let thread_id = (self.inner.get_current_thread_id)();
self.inner.threads.read().get(&thread_id).unwrap().java_thread().unwrap().clone()
}
Comment thread
dlunch marked this conversation as resolved.

// TODO we need safe, ergonomic api..
pub fn push_native_frame(&self) {
let thread_id = (self.inner.get_current_thread_id)();
Expand Down
15 changes: 14 additions & 1 deletion jvm/src/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,24 @@ impl StackFrame {

pub struct JvmThread {
stack: Vec<StackFrame>,
java_thread: Option<Box<dyn ClassInstance>>,
}

impl JvmThread {
pub fn new() -> Self {
Self { stack: Vec::new() }
Self {
stack: Vec::new(),
java_thread: None,
}
}

#[allow(clippy::borrowed_box)] // same as jvm.rs; callers pass it to &Box-taking apis
pub fn java_thread(&self) -> Option<&Box<dyn ClassInstance>> {
self.java_thread.as_ref()
}

pub fn set_java_thread(&mut self, java_thread: Box<dyn ClassInstance>) {
self.java_thread = Some(java_thread);
}

pub fn push_java_frame(&mut self, class: &Class, class_instance: Option<Box<dyn ClassInstance>>, method: &str) {
Expand Down
Binary file added test_data/CurrentThread$1.class
Binary file not shown.
Binary file added test_data/CurrentThread.class
Binary file not shown.
3 changes: 3 additions & 0 deletions test_data/CurrentThread.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
true
true
false
18 changes: 18 additions & 0 deletions test_data/src/CurrentThread.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
public class CurrentThread {
public static void main(String[] args) throws Exception {
Thread a = Thread.currentThread();
Thread b = Thread.currentThread();
System.out.println(a == b);

final Thread[] seen = new Thread[1];
Thread t = new Thread(new Runnable() {
public void run() {
seen[0] = Thread.currentThread();
}
});
t.start();
t.join();
System.out.println(seen[0] == t);
System.out.println(seen[0] == a);
}
}