Skip to content

Commit 9574997

Browse files
committed
Resolve inherited static fields and methods
getstatic/putstatic/invokestatic referencing a subclass or implementing class now walk the hierarchy per JVMS 5.4.3.2/5.4.3.3: static fields search the class, its superinterfaces, then its superclass; static methods search the class then its superclass. The resolved member is read, written, and executed on its declaring class, and initialization triggers that declaring class (not the referencing subclass).
1 parent 07fc404 commit 9574997

21 files changed

Lines changed: 96 additions & 21 deletions

jvm/src/jvm.rs

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,10 @@ impl Jvm {
178178

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

181-
let field = class.definition.field(name, descriptor, true);
182-
if let Some(field) = field {
183-
self.ensure_initialized(&class).await?;
181+
if let Some((declaring_class, field)) = self.resolve_static_field(&class, name, descriptor) {
182+
self.ensure_initialized(&declaring_class).await?;
184183

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

199-
let mut class = self.resolve_class(class_name).await?;
200-
201-
let field = class.definition.field(name, descriptor, true);
198+
let class = self.resolve_class(class_name).await?;
202199

203-
if let Some(field) = field {
204-
self.ensure_initialized(&class).await?;
200+
if let Some((mut declaring_class, field)) = self.resolve_static_field(&class, name, descriptor) {
201+
self.ensure_initialized(&declaring_class).await?;
205202

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

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

265-
let method = class.definition.method(name, descriptor, true);
266-
267-
if let Some(method) = method {
268-
if !method.access_flags().contains(MethodAccessFlags::STATIC) {
269-
return Err(self
270-
.exception("java/lang/IncompatibleClassChangeError", &format!("{class_name}.{name}:{descriptor}"))
271-
.await);
272-
}
273-
274-
self.ensure_initialized(&class).await?;
262+
if let Some((declaring_class, method)) = self.resolve_static_method(&class, name, descriptor) {
263+
self.ensure_initialized(&declaring_class).await?;
275264

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

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

807+
// JVMS 5.4.3.2 field resolution: search the class, then its superinterfaces, then its superclass
808+
fn resolve_static_field(&self, class: &Class, name: &str, descriptor: &str) -> Option<(Class, Box<dyn Field>)> {
809+
if let Some(field) = class.definition.field(name, descriptor, true) {
810+
return Some((class.clone(), field));
811+
}
812+
813+
for interface in class.definition.interface_names() {
814+
if let Some(interface_class) = self.get_class(&interface)
815+
&& let Some(found) = self.resolve_static_field(&interface_class, name, descriptor)
816+
{
817+
return Some(found);
818+
}
819+
}
820+
821+
let super_class = self.get_class(&class.definition.super_class_name()?)?;
822+
self.resolve_static_field(&super_class, name, descriptor)
823+
}
824+
825+
// JVMS 5.4.3.3 method resolution for static methods; interfaces have no static methods in this runtime
826+
fn resolve_static_method(&self, class: &Class, name: &str, descriptor: &str) -> Option<(Class, Box<dyn Method>)> {
827+
if let Some(method) = class.definition.method(name, descriptor, true) {
828+
return Some((class.clone(), method));
829+
}
830+
831+
let super_class = self.get_class(&class.definition.super_class_name()?)?;
832+
self.resolve_static_method(&super_class, name, descriptor)
833+
}
834+
818835
pub(crate) fn find_field(&self, class: &dyn ClassDefinition, name: &str, descriptor: &str) -> Result<Option<Box<dyn Field>>> {
819836
let field = class.field(name, descriptor, false);
820837

test_data/StaticInherit$Base.class

422 Bytes
Binary file not shown.
332 Bytes
Binary file not shown.

test_data/StaticInherit$Impl.class

326 Bytes
Binary file not shown.

test_data/StaticInherit$Sub.class

296 Bytes
Binary file not shown.

test_data/StaticInherit.class

748 Bytes
Binary file not shown.

test_data/StaticInherit.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
7
2+
9
3+
11
540 Bytes
Binary file not shown.
519 Bytes
Binary file not shown.

test_data/StaticInitTrigger.class

639 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)