Skip to content

Commit 4d00f21

Browse files
committed
Fix instance field resolution and storage across inheritance
1 parent 21f54ff commit 4d00f21

10 files changed

Lines changed: 109 additions & 29 deletions

File tree

‎jvm-bytecode/src/class_definition.rs‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ impl ClassDefinitionImpl {
8383
.map(|x| MethodImpl::from_method_proto(x, context.clone()))
8484
.collect::<Vec<_>>();
8585

86-
let fields = proto.fields.into_iter().map(FieldImpl::from_field_proto).collect::<Vec<_>>();
86+
let fields = proto
87+
.fields
88+
.into_iter()
89+
.map(|field| FieldImpl::from_field_proto(proto.name, field))
90+
.collect::<Vec<_>>();
8791

8892
let interfaces = proto.interfaces.into_iter().map(|x| x.to_string()).collect();
8993

@@ -111,7 +115,7 @@ impl ClassDefinitionImpl {
111115
_ => None,
112116
});
113117

114-
let field = FieldImpl::from_field_info(field_info);
118+
let field = FieldImpl::from_field_info(&class.this_class, field_info);
115119
if let Some(x) = constant
116120
&& field.access_flags().contains(FieldAccessFlags::STATIC)
117121
{

‎jvm-bytecode/src/field.rs‎

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use jvm_types::FieldAccessFlags;
1111

1212
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
1313
struct FieldInner {
14+
declaring_class: String,
1415
name: String,
1516
descriptor: String,
1617
access_flags: FieldAccessFlags,
@@ -22,28 +23,23 @@ pub struct FieldImpl {
2223
}
2324

2425
impl FieldImpl {
25-
pub fn new(name: &str, descriptor: &str, access_flags: FieldAccessFlags) -> Self {
26+
pub fn new(declaring_class: &str, name: &str, descriptor: &str, access_flags: FieldAccessFlags) -> Self {
2627
Self {
2728
inner: Arc::new(FieldInner {
29+
declaring_class: declaring_class.to_string(),
2830
name: name.to_string(),
2931
descriptor: descriptor.to_string(),
3032
access_flags,
3133
}),
3234
}
3335
}
3436

35-
pub fn from_field_proto(proto: JavaFieldProto) -> Self {
36-
Self::new(&proto.name, &proto.descriptor, proto.access_flags)
37+
pub fn from_field_proto(declaring_class: &str, proto: JavaFieldProto) -> Self {
38+
Self::new(declaring_class, &proto.name, &proto.descriptor, proto.access_flags)
3739
}
3840

39-
pub fn from_field_info(field_info: FieldInfo) -> Self {
40-
Self {
41-
inner: Arc::new(FieldInner {
42-
name: field_info.name.to_string(),
43-
descriptor: field_info.descriptor.to_string(),
44-
access_flags: field_info.access_flags,
45-
}),
46-
}
41+
pub fn from_field_info(declaring_class: &str, field_info: FieldInfo) -> Self {
42+
Self::new(declaring_class, &field_info.name, &field_info.descriptor, field_info.access_flags)
4743
}
4844
}
4945

‎jvm-bytecode/src/interpreter.rs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ impl Interpreter {
445445
return Err(jvm.exception("java/lang/NullPointerException", "null").await);
446446
}
447447

448-
let value = jvm.get_field(&instance.unwrap(), &x.name, &x.descriptor).await?;
448+
let value = jvm.get_field_from_class(&instance.unwrap(), &x.class, &x.name, &x.descriptor).await?;
449449

450450
stack_frame.operand_stack.push(Self::to_stack_frame_type(value));
451451
}
@@ -921,7 +921,8 @@ impl Interpreter {
921921

922922
let value = Self::to_field_type(&x.descriptor, value);
923923

924-
jvm.put_field(instance.as_mut().unwrap(), &x.name, &x.descriptor, value).await?;
924+
jvm.put_field_from_class(instance.as_mut().unwrap(), &x.class, &x.name, &x.descriptor, value)
925+
.await?;
925926
}
926927
Opcode::Putstatic(x) => {
927928
let x = x.as_field_ref();

‎jvm/src/jvm.rs‎

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,23 @@ impl Jvm {
265265
where
266266
T: From<JavaValue>,
267267
{
268-
tracing::trace!("Get field {}.{name}:{descriptor}", instance.class_definition().name());
268+
self.get_field_from_class(instance, &instance.class_definition().name(), name, descriptor)
269+
.await
270+
}
269271

270-
let field = self.find_field(&*instance.class_definition(), name, descriptor)?;
272+
pub async fn get_field_from_class<T>(&self, instance: &Box<dyn ClassInstance>, class_name: &str, name: &str, descriptor: &str) -> Result<T>
273+
where
274+
T: From<JavaValue>,
275+
{
276+
tracing::trace!("Get field {class_name}.{name}:{descriptor}");
271277

272-
if let Some(field) = field {
278+
let class = self.resolve_class(class_name).await?;
279+
if let Some((_, field)) = self.resolve_field(&class, name, descriptor) {
280+
if field.access_flags().contains(FieldAccessFlags::STATIC) {
281+
return Err(self
282+
.exception("java/lang/IncompatibleClassChangeError", &format!("{class_name}.{name}:{descriptor}"))
283+
.await);
284+
}
273285
let value = instance.get_field(&*field)?;
274286
if let JavaValue::Object(Some(instance)) = &value {
275287
let thread_id = (self.inner.get_current_thread_id)();
@@ -285,10 +297,7 @@ impl Jvm {
285297
Ok(value.into())
286298
} else {
287299
Err(self
288-
.exception(
289-
"java/lang/NoSuchFieldError",
290-
&format!("{}.{}:{}", instance.class_definition().name(), name, descriptor),
291-
)
300+
.exception("java/lang/NoSuchFieldError", &format!("{class_name}.{name}:{descriptor}"))
292301
.await)
293302
}
294303
}
@@ -297,18 +306,34 @@ impl Jvm {
297306
where
298307
T: Into<JavaValue> + Debug,
299308
{
300-
tracing::trace!("Put field {}.{name}:{descriptor} = {value:?}", instance.class_definition().name());
309+
self.put_field_from_class(instance, &instance.class_definition().name(), name, descriptor, value)
310+
.await
311+
}
301312

302-
let field = self.find_field(&*instance.class_definition(), name, descriptor)?;
313+
pub async fn put_field_from_class<T>(
314+
&self,
315+
instance: &mut Box<dyn ClassInstance>,
316+
class_name: &str,
317+
name: &str,
318+
descriptor: &str,
319+
value: T,
320+
) -> Result<()>
321+
where
322+
T: Into<JavaValue> + Debug,
323+
{
324+
tracing::trace!("Put field {class_name}.{name}:{descriptor} = {value:?}");
303325

304-
if let Some(field) = field {
326+
let class = self.resolve_class(class_name).await?;
327+
if let Some((_, field)) = self.resolve_field(&class, name, descriptor) {
328+
if field.access_flags().contains(FieldAccessFlags::STATIC) {
329+
return Err(self
330+
.exception("java/lang/IncompatibleClassChangeError", &format!("{class_name}.{name}:{descriptor}"))
331+
.await);
332+
}
305333
instance.put_field(&*field, value.into())
306334
} else {
307335
Err(self
308-
.exception(
309-
"java/lang/NoSuchFieldError",
310-
&format!("{}.{}:{}", instance.class_definition().name(), name, descriptor),
311-
)
336+
.exception("java/lang/NoSuchFieldError", &format!("{class_name}.{name}:{descriptor}"))
312337
.await)
313338
}
314339
}

‎test-data/Field$Base.class‎

507 Bytes
Binary file not shown.

‎test-data/Field$Derived.class‎

472 Bytes
Binary file not shown.

‎test-data/Field$Leaf.class‎

253 Bytes
Binary file not shown.

‎test-data/Field.class‎

548 Bytes
Binary file not shown.

‎test-data/Field.txt‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
1
22
test1
33
1234
4+
false
5+
true
6+
31
7+
42
8+
parent
9+
child
10+
22
11+
11

‎test-data/src/Field.java‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
11
class Field {
2+
static class Base {
3+
private boolean active = true;
4+
public int value = 11;
5+
public Object reference = "base";
6+
7+
void clear() {
8+
active = false;
9+
}
10+
11+
boolean baseActive() {
12+
return active;
13+
}
14+
}
15+
16+
static class Derived extends Base {
17+
private boolean active = true;
18+
public int value = 22;
19+
public Object reference = "derived";
20+
21+
boolean derivedActive() {
22+
return active;
23+
}
24+
}
25+
26+
static class Leaf extends Derived {
27+
}
28+
229
public int int_field;
330
public String string_field;
431
public long long_field;
@@ -15,5 +42,24 @@ public static void main(String[] args) {
1542
System.out.println(field.int_field);
1643
System.out.println(field.string_field);
1744
System.out.println(field.static_field);
45+
46+
Derived child = new Derived();
47+
Base parent = child;
48+
parent.clear();
49+
System.out.println(parent.baseActive());
50+
System.out.println(child.derivedActive());
51+
52+
parent.value = 31;
53+
child.value = 42;
54+
parent.reference = "parent";
55+
child.reference = "child";
56+
System.out.println(parent.value);
57+
System.out.println(child.value);
58+
System.out.println(parent.reference);
59+
System.out.println(child.reference);
60+
61+
Leaf leaf = new Leaf();
62+
System.out.println(leaf.value);
63+
System.out.println(((Base) leaf).value);
1864
}
1965
}

0 commit comments

Comments
 (0)