Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
59 changes: 38 additions & 21 deletions jvm/src/jvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,10 @@ impl Jvm {

let class = self.resolve_class(class_name).await?;

let field = class.definition.field(name, descriptor, true);
if let Some(field) = field {
self.ensure_initialized(&class).await?;
if let Some((declaring_class, field)) = self.resolve_static_field(&class, name, descriptor) {
self.ensure_initialized(&declaring_class).await?;

Ok(class.definition.get_static_field(&*field)?.into())
Ok(declaring_class.definition.get_static_field(&*field)?.into())
} else {
Err(self
.exception("java/lang/NoSuchFieldError", &format!("{class_name}.{name}:{descriptor}"))
Expand All @@ -196,14 +195,12 @@ impl Jvm {
{
tracing::trace!("Put static field {}.{}:{} = {:?}", class_name, name, descriptor, value);

let mut class = self.resolve_class(class_name).await?;

let field = class.definition.field(name, descriptor, true);
let class = self.resolve_class(class_name).await?;

if let Some(field) = field {
self.ensure_initialized(&class).await?;
if let Some((mut declaring_class, field)) = self.resolve_static_field(&class, name, descriptor) {
self.ensure_initialized(&declaring_class).await?;

class.definition.put_static_field(&*field, value.into())
declaring_class.definition.put_static_field(&*field, value.into())
} else {
Err(self
.exception("java/lang/NoSuchFieldError", &format!("{class_name}.{name}:{descriptor}"))
Expand Down Expand Up @@ -262,18 +259,10 @@ impl Jvm {

let class = self.resolve_class(class_name).await?;

let method = class.definition.method(name, descriptor, true);

if let Some(method) = method {
if !method.access_flags().contains(MethodAccessFlags::STATIC) {
return Err(self
.exception("java/lang/IncompatibleClassChangeError", &format!("{class_name}.{name}:{descriptor}"))
.await);
}

self.ensure_initialized(&class).await?;
if let Some((declaring_class, method)) = self.resolve_static_method(&class, name, descriptor) {
self.ensure_initialized(&declaring_class).await?;

Ok(self.execute_method(&class, None, &method, args).await?.into())
Ok(self.execute_method(&declaring_class, None, &method, args).await?.into())
} else {
tracing::error!("No such method: {}.{}:{}", class_name, name, descriptor);

Expand Down Expand Up @@ -815,6 +804,34 @@ impl Jvm {
monitors.entry(key).or_insert_with(|| Arc::new(Event::new())).clone()
}

// JVMS 5.4.3.2 field resolution: search the class, then its superinterfaces, then its superclass
fn resolve_static_field(&self, class: &Class, name: &str, descriptor: &str) -> Option<(Class, Box<dyn Field>)> {
if let Some(field) = class.definition.field(name, descriptor, true) {
Comment thread
dlunch marked this conversation as resolved.
Outdated
return Some((class.clone(), field));
}

for interface in class.definition.interface_names() {
if let Some(interface_class) = self.get_class(&interface)
&& let Some(found) = self.resolve_static_field(&interface_class, name, descriptor)
{
return Some(found);
}
}

let super_class = self.get_class(&class.definition.super_class_name()?)?;
self.resolve_static_field(&super_class, name, descriptor)
}

// JVMS 5.4.3.3 method resolution for static methods; interfaces have no static methods in this runtime
fn resolve_static_method(&self, class: &Class, name: &str, descriptor: &str) -> Option<(Class, Box<dyn Method>)> {
if let Some(method) = class.definition.method(name, descriptor, true) {
return Some((class.clone(), method));
}

let super_class = self.get_class(&class.definition.super_class_name()?)?;
self.resolve_static_method(&super_class, name, descriptor)
}

pub(crate) fn find_field(&self, class: &dyn ClassDefinition, name: &str, descriptor: &str) -> Result<Option<Box<dyn Field>>> {
let field = class.field(name, descriptor, false);

Expand Down
Binary file added test_data/StaticInherit$Base.class
Binary file not shown.
Binary file added test_data/StaticInherit$IConst.class
Binary file not shown.
Binary file added test_data/StaticInherit$Impl.class
Binary file not shown.
Binary file added test_data/StaticInherit$Sub.class
Binary file not shown.
Binary file added test_data/StaticInherit.class
Binary file not shown.
3 changes: 3 additions & 0 deletions test_data/StaticInherit.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
7
9
11
Binary file added test_data/StaticInitTrigger$Base.class
Binary file not shown.
Binary file added test_data/StaticInitTrigger$Sub.class
Binary file not shown.
Binary file added test_data/StaticInitTrigger.class
Binary file not shown.
4 changes: 4 additions & 0 deletions test_data/StaticInitTrigger.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
start
base-init
7
end
Binary file added test_data/src/StaticInherit$Base.class
Binary file not shown.
Binary file added test_data/src/StaticInherit$IConst.class
Binary file not shown.
Binary file added test_data/src/StaticInherit$Impl.class
Binary file not shown.
Binary file added test_data/src/StaticInherit$Sub.class
Binary file not shown.
Binary file added test_data/src/StaticInherit.class
Binary file not shown.
29 changes: 29 additions & 0 deletions test_data/src/StaticInherit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
public class StaticInherit {
static class Base {
static int field = 7;

static int method() {
return 9;
}
}

static class Sub extends Base {
}

static int compute() {
return 11;
}

interface IConst {
int IC = compute();
}

static class Impl implements IConst {
}

public static void main(String[] args) {
System.out.println(Sub.field);
System.out.println(Sub.method());
System.out.println(Impl.IC);
}
}
Binary file added test_data/src/StaticInitTrigger$Base.class
Binary file not shown.
Binary file added test_data/src/StaticInitTrigger$Sub.class
Binary file not shown.
Binary file added test_data/src/StaticInitTrigger.class
Binary file not shown.
22 changes: 22 additions & 0 deletions test_data/src/StaticInitTrigger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
public class StaticInitTrigger {
static class Base {
static int field = 7;

static {
System.out.println("base-init");
}
}

static class Sub extends Base {
static {
System.out.println("sub-init");
}
}

public static void main(String[] args) {
System.out.println("start");
// accessing an inherited static field initializes only the declaring class (Base), not Sub
System.out.println(Sub.field);
System.out.println("end");
}
}
Loading