Skip to content

Commit

Permalink
Improvements an bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
hextriclosan committed Oct 3, 2024
1 parent 2d0467d commit 93dd9df
Show file tree
Hide file tree
Showing 14 changed files with 147 additions and 12 deletions.
11 changes: 10 additions & 1 deletion tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ fn should_do_extreme_stack_operations() {
let last_frame_value = vm
.run("samples.arithmetics.extremestack.ints.ExtremeStackInt")
.unwrap();
assert_eq!(454, get_int(last_frame_value))
assert_eq!(528, get_int(last_frame_value))
}

#[test]
Expand Down Expand Up @@ -189,6 +189,15 @@ fn should_do_inherited_static_fields() {
assert_eq!(128, get_int(last_frame_value))
}

#[test]
fn should_do_inherited_instance_fields() {
let mut vm = VM::new("std");
let last_frame_value = vm
.run("samples.inheritance.instancefield.InheritanceInstanceField")
.unwrap();
assert_eq!(128, get_int(last_frame_value))
}

#[test]
fn should_do_trivial_interfaces() {
let mut vm = VM::new("std");
Expand Down
8 changes: 4 additions & 4 deletions tests/test_data/ExtremeStackInt.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ public static void main(String[] args) {
int combinedRecursionResult = factorialPlusFibonacci(5);
//System.out.println("combinedRecursionResult=" + combinedRecursionResult);

int result = nestedResult + loopResult + combinedRecursionResult; // 454
int result = nestedResult + loopResult + combinedRecursionResult; // 528
//System.out.println("result=" + result);
}

// Method with nested operations and method calls
private static int nestedCalculations(int n) {
int result = 0;
for (int i = 0; i < n; i++) {
result += multiplyAndAdd(i, n - i);
result += multiplyAndAddAndBitAndUShiftRight(i, n - i);
}
return result * 2 - n; // Final operation after loop
}

// Helper method for nestedCalculations
private static int multiplyAndAdd(int x, int y) {
return (x * y) + (x - y); // Simple arithmetic operations
private static int multiplyAndAddAndBitAndUShiftRight(int x, int y) {
return (x * y) + (x - y) + (y & x) + (y >>> x); // Simple arithmetic operations
}

// Method with loop, conditions, and nested operations
Expand Down
56 changes: 56 additions & 0 deletions tests/test_data/InheritanceInstanceField.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package samples.inheritance.instancefield;

public class InheritanceInstanceField {
public static void main(String[] args) {
Child child = new Child();
int sum1 = // sum must be 14
child.getChildOnlyField() // 5 from Child
+ child.getParentField() // 3 from Parent (absent in Child, is taken from Parent)
+ child.getGrandParentField() // 4 from Parent (Parent shadows GrandParent)
+ child.getGrandParentOnlyField(); // 2 from GrandParent (nor Child neither Parent have it)

child.setGrandParentOnlyField(102);

int sum2 = // sum must be 114
child.getChildOnlyField() // 5 from Child
+ child.getParentField() // 3 from Parent (absent in Child, is taken from Parent)
+ child.getGrandParentField() // 4 from Parent (Parent shadows GrandParent)
+ child.getGrandParentOnlyField(); // 102 from modified GrandParent (nor Child neither Parent have it)

int result = sum1 + sum2; // sum must be 128
}
}

class GrandParent {
protected int grandParentField = 1;
protected int grandParentOnlyField = 2;
}

class Parent extends GrandParent {
protected int parentField = 3;
protected int grandParentField = 4;
}

class Child extends Parent {
private int childOnlyField = 5;

public int getChildOnlyField() {
return childOnlyField;
}

public int getParentField() {
return parentField;
}

public int getGrandParentField() {
return grandParentField;
}

public int getGrandParentOnlyField() {
return grandParentOnlyField;
}

public void setGrandParentOnlyField(int grandParentOnlyField) {
this.grandParentOnlyField = grandParentOnlyField;
}
}
7 changes: 5 additions & 2 deletions tests/test_data/InstanceFieldsUserInts.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ public class InstanceFieldsUserInts {
public static void main(String[] args) {
int first = 11;
int second = 10000;
InstanceFields[] instances = new InstanceFields[] { new InstanceFields(), new InstanceFields(), new InstanceFields() };
InstanceFields one = null;
one = new InstanceFields();
InstanceFields[] instances = new InstanceFields[] { one, new InstanceFields(), new InstanceFields() };
instances[0].sub(first, second);
instances[1].add(first, second);
instances[2].mul(first, second);
int result = instances[0].getResultSub() + instances[1].getResultAdd() + instances[2].getResultMul();

int result = (one != instances[1] ? instances[0].getResultSub() : 0) + instances[1].getResultAdd() + instances[2].getResultMul();
}
}

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
54 changes: 50 additions & 4 deletions vm/src/execution_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ impl Engine {
current_class_name = stack_frame.current_class_name().to_string();

match stack_frame.get_bytecode_byte() {
ACONST_NULL => {
stack_frame.push(0);
stack_frame.incr_pc();
println!("ACONST_NULL");
}
ICONST_0 => {
stack_frame.push(0);
stack_frame.incr_pc();
Expand Down Expand Up @@ -586,6 +591,27 @@ impl Engine {
stack_frame.incr_pc();
println!("LREM -> {a} % {b} = {result}");
}
IUSHR => {
let b = stack_frame.pop() as u32;
let a = stack_frame.pop() as u32;

let b_trunc = b & 0b00011111u32;
let result = a >> b_trunc;
stack_frame.push(result as i32);

stack_frame.incr_pc();
println!("IUSHR -> {a} % {b} = {result}");
}
IAND => {
let b = stack_frame.pop();
let a = stack_frame.pop();

let result = a & b;
stack_frame.push(result);

stack_frame.incr_pc();
println!("IAND -> {a} & {b} = {result}");
}
IINC => {
stack_frame.incr_pc();
let index = stack_frame.get_bytecode_byte() as usize;
Expand Down Expand Up @@ -636,6 +662,12 @@ impl Engine {
stack_frame.advance_pc(if value != 0 { offset } else { 3 });
println!("IFNE -> value={value}, offset={offset}");
}
IFLT => {
let value = stack_frame.pop();
let offset = Self::get_two_bytes_ahead(stack_frame);
stack_frame.advance_pc(if value < 0 { offset } else { 3 });
println!("IFLT -> value={value}, offset={offset}");
}
IFGE => {
let value = stack_frame.pop();
let offset = Self::get_two_bytes_ahead(stack_frame);
Expand Down Expand Up @@ -672,6 +704,9 @@ impl Engine {
IF_ICMPLE => {
Self::branch(|a: i32, b| a <= b, stack_frame, "IF_ICMPLE");
}
IF_ACMPEQ => {
Self::branch(|a: i32, b| a == b, stack_frame, "IF_ACMPEQ");
}
GOTO => {
let offset = Self::get_two_bytes_ahead(stack_frame);
stack_frame.advance_pc(offset);
Expand Down Expand Up @@ -811,15 +846,15 @@ impl Engine {
.ok_or_else(|| Error::new_constant_pool(&format!("Error getting full field info by index {fieldref_constpool_index}")))?;

let field_name_type = format!("{field_name}:{field_descriptor}");
let rc = self.method_area.borrow().get(&class_name)?;
let type_descriptor = rc
.instance_field_descriptor(&field_name_type)
let method_area = self.method_area.borrow();
let type_descriptor = method_area
.lookup_for_field_descriptor(&class_name, &field_name_type)
.ok_or_else(|| {
Error::new_constant_pool(&format!(
"Error getting type descriptor for {class_name}.{field_name_type}"
))
})?;
let len = get_length(type_descriptor);
let len = get_length(&type_descriptor);

let mut value = Vec::with_capacity(len);
for _ in 0..len {
Expand Down Expand Up @@ -1079,6 +1114,17 @@ impl Engine {
stack_frame.incr_pc();
println!("ARRAYLENGTH -> arrayref={arrayref}, len={len}");
}
CHECKCAST => {
let class_constpool_index = Self::extract_two_bytes(stack_frame);
stack_frame.incr_pc();

let objectref = stack_frame.pop();
// todo: implementation here
stack_frame.push(objectref);

println!("CHECKCAST -> class_constpool_index={class_constpool_index}, objectref={objectref}");
todo!("add implementation");
}
IFNULL => { //todo: this one is opposite to IFNE ops code
let value = stack_frame.pop();
let offset = Self::get_two_bytes_ahead(stack_frame);
Expand Down
4 changes: 4 additions & 0 deletions vm/src/method_area/java_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ impl JavaClass {
.map(|(name, descriptor)| (name.clone(), Field::new(descriptor.to_owned())))
.collect()
}

pub fn this_class_name(&self) -> &str {
&self.this_class_name
}
}

impl Methods {
Expand Down
19 changes: 18 additions & 1 deletion vm/src/method_area/method_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ impl MethodArea {
fully_qualified_class_name.to_string(),
Rc::clone(&java_class),
);
println!("<CLASS LOADED> -> {}", java_class.this_class_name());

Ok(java_class)
}
Expand Down Expand Up @@ -180,7 +181,7 @@ impl MethodArea {

let code_context = if !method_info
.access_flags()
.contains(MethodFlags::ACC_ABSTRACT)
.intersects(MethodFlags::ACC_ABSTRACT|MethodFlags::ACC_NATIVE)
{
AttributesHelper::new(method_info.attributes())
.get_code()
Expand Down Expand Up @@ -287,6 +288,22 @@ impl MethodArea {
}
}

pub fn lookup_for_field_descriptor(
&self,
class_name: &str,
field_name_type: &str,
) -> Option<TypeDescriptor> {
let rc = self.get(class_name).ok()?;

if let Some(type_descriptor) = rc.instance_field_descriptor(field_name_type) {
Some(type_descriptor.clone())
} else {
let parent_class_name = rc.parent().clone()?;

self.lookup_for_field_descriptor(&parent_class_name, field_name_type)
}
}

pub fn create_instance_with_default_fields(&self, class_name: &str) -> JavaInstance {
let mut instance_fields_hierarchy = IndexMap::new();
self.lookup_and_fill_instance_fields_hierarchy(class_name, &mut instance_fields_hierarchy);
Expand Down

0 comments on commit 93dd9df

Please sign in to comment.