diff --git a/src/main.rs b/src/main.rs index bba57ed7..03b20720 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,7 +47,7 @@ fn main() { }; println!( - "\nresult={}", - result.map_or_else(|| "".to_string(), |v| v.to_string()) + "\nresult={:?}", + result.map_or_else(|| vec![], |v| v) ); } diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 27c20a83..620896b1 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -4,7 +4,7 @@ use vm::vm::VM; fn should_do_adding() { let vm = VM::new(vec!["tests/test_data/Adder.class"], "tests/test_data/std").unwrap(); let last_frame_value = vm.run("Adder").unwrap(); - assert_eq!(55, last_frame_value.unwrap()) + assert_eq!(55, get_int(last_frame_value)) } #[test] @@ -15,21 +15,32 @@ fn should_do_adding_with_longs() { ) .unwrap(); let last_frame_value = vm.run("AdderLong").unwrap(); - assert_eq!(1_000_000_000, last_frame_value.unwrap()) + assert_eq!(171798691900, get_long(last_frame_value)) +} + +#[test] +fn should_do_adding_with_negative_longs() { + let vm = VM::new( + vec!["tests/test_data/AdderNegativeLong.class"], + "tests/test_data/std", + ) + .unwrap(); + let last_frame_value = vm.run("AdderNegativeLong").unwrap(); + assert_eq!(-1990000000000000, get_long(last_frame_value)) } #[test] fn should_do_subtraction() { let vm = VM::new(vec!["tests/test_data/Sub.class"], "tests/test_data/std").unwrap(); let last_frame_value = vm.run("Sub").unwrap(); - assert_eq!(-999, last_frame_value.unwrap()) + assert_eq!(-999, get_int(last_frame_value)) } #[test] fn should_do_subtraction_with_longs() { let vm = VM::new(vec!["tests/test_data/SubLong.class"], "tests/test_data/std").unwrap(); let last_frame_value = vm.run("SubLong").unwrap(); - assert_eq!(1_000_000_000, last_frame_value.unwrap()) + assert_eq!(-1_000_000_000, get_long(last_frame_value)) } #[test] @@ -43,7 +54,21 @@ fn should_write_read_instance_fields() { ) .unwrap(); let last_frame_value = vm.run("InstanceFieldsUser").unwrap(); - assert_eq!(110022, last_frame_value.unwrap()) + assert_eq!(110022, get_int(last_frame_value)) +} + +#[test] +fn should_write_read_instance_fields_with_longs() { + let vm = VM::new( + vec![ + "tests/test_data/InstanceFieldsUserLong.class", + "tests/test_data/InstanceFieldsLong.class", + ], + "tests/test_data/std", + ) + .unwrap(); + let last_frame_value = vm.run("InstanceFieldsUserLong").unwrap(); + assert_eq!(4_380_866_642_760, get_long(last_frame_value)) } #[test] @@ -57,7 +82,7 @@ fn should_write_read_static_fields() { ) .unwrap(); let last_frame_value = vm.run("StaticFieldsUser").unwrap(); - assert_eq!(110022, last_frame_value.unwrap()) + assert_eq!(110022, get_int(last_frame_value)) } #[test] @@ -68,7 +93,18 @@ fn should_do_extreme_stack_operations() { ) .unwrap(); let last_frame_value = vm.run("ExtremeStackTest").unwrap(); - assert_eq!(454, last_frame_value.unwrap()) + assert_eq!(454, get_int(last_frame_value)) +} + +#[test] +fn should_do_extreme_stack_operations_with_longs() { + let vm = VM::new( + vec!["tests/test_data/ExtremeStackTestLong.class"], + "tests/test_data/std", + ) + .unwrap(); + let last_frame_value = vm.run("ExtremeStackTestLong").unwrap(); + assert_eq!(454, get_long(last_frame_value)) } #[test] @@ -79,7 +115,7 @@ fn should_do_calculate_fibonacci_iteratively() { ) .unwrap(); let last_frame_value = vm.run("FibonacciIterative").unwrap(); - assert_eq!(55, last_frame_value.unwrap()) + assert_eq!(55, get_int(last_frame_value)) } #[test] @@ -90,14 +126,21 @@ fn should_do_calculate_fibonacci_recursively() { ) .unwrap(); let last_frame_value = vm.run("FibonacciRecursive").unwrap(); - assert_eq!(55, last_frame_value.unwrap()) + assert_eq!(55, get_int(last_frame_value)) } #[test] fn should_do_arrays() { let vm = VM::new(vec!["tests/test_data/Array.class"], "tests/test_data/std").unwrap(); let last_frame_value = vm.run("Array").unwrap(); - assert_eq!(740, last_frame_value.unwrap()) + assert_eq!(740, get_int(last_frame_value)) +} + +#[test] +fn should_do_arrays_with_longs() { + let vm = VM::new(vec!["tests/test_data/ArrayLong.class"], "tests/test_data/std").unwrap(); + let last_frame_value = vm.run("ArrayLong").unwrap(); + assert_eq!(233646220932000, get_long(last_frame_value)) } #[test] @@ -108,7 +151,7 @@ fn should_do_class_static_initialization() { ) .unwrap(); let last_frame_value = vm.run("StaticInitialization").unwrap(); - assert_eq!(257, last_frame_value.unwrap()) + assert_eq!(257, get_int(last_frame_value)) } #[ignore] @@ -124,5 +167,19 @@ fn should_do_class_static_initialization_multiple_classes() { ) .unwrap(); let last_frame_value = vm.run("StaticInitializationUser").unwrap(); - assert_eq!(350, last_frame_value.unwrap()) + assert_eq!(350, get_int(last_frame_value)) +} + +fn get_int(locals: Option>) -> i32 { + *locals.unwrap().last().unwrap() +} + +fn get_long(locals_opt: Option>) -> i64 { + let locals = locals_opt.unwrap(); + + let two = &locals[locals.len().saturating_sub(2)..]; + let low = two[0]; + let high = two[1]; + + ((high as i64) << 32) | (low as i64) } diff --git a/tests/test_data/AdderLong.class b/tests/test_data/AdderLong.class index 9a5e0535..5a058967 100644 Binary files a/tests/test_data/AdderLong.class and b/tests/test_data/AdderLong.class differ diff --git a/tests/test_data/AdderLong.java b/tests/test_data/AdderLong.java index 7125f447..c0031ec3 100644 --- a/tests/test_data/AdderLong.java +++ b/tests/test_data/AdderLong.java @@ -1,9 +1,11 @@ -//javac -g -parameters Adder.java public class AdderLong { public static void main(String[] args) { - long result = add(100_000_000_000L, -99_000_000_000L); + long result = add( + 42_949_672_980L/*h=10,l=20*/, + 128_849_018_920L/*h=30,l=40*/ + ); } private static long add(long a, long b) { diff --git a/tests/test_data/AdderNegativeLong.class b/tests/test_data/AdderNegativeLong.class new file mode 100644 index 00000000..cccfddd1 Binary files /dev/null and b/tests/test_data/AdderNegativeLong.class differ diff --git a/tests/test_data/AdderNegativeLong.java b/tests/test_data/AdderNegativeLong.java new file mode 100644 index 00000000..0f9f2b4c --- /dev/null +++ b/tests/test_data/AdderNegativeLong.java @@ -0,0 +1,12 @@ + +public class AdderNegativeLong { + + public static void main(String[] args) { + long result = add(-1_000_000_000_000_000L, -990_000_000_000_000L); + } + + private static long add(long a, long b) { + return a + b; + } + +} diff --git a/tests/test_data/ArrayLong.class b/tests/test_data/ArrayLong.class new file mode 100644 index 00000000..d3045d43 Binary files /dev/null and b/tests/test_data/ArrayLong.class differ diff --git a/tests/test_data/ArrayLong.java b/tests/test_data/ArrayLong.java new file mode 100644 index 00000000..91a108b4 --- /dev/null +++ b/tests/test_data/ArrayLong.java @@ -0,0 +1,134 @@ +public class ArrayLong { + + public static void main(String[] args) { + long result = calculate(); + } + + private static long calculate() { + // 1. Initialize two arrays with different sizes + long[] numbers1 = { + 42_949_672_980l/*h=10,l=20*/, + 128_849_018_920l/*h=30,l=40*/, + 214_748_364_860l/*h=50,l=60*/, + 300_647_710_800l/*h=70,l=80*/ + }; + long[] numbers2 = { + 386_547_056_740l/*h=90,l=100*/, + 472_446_402_680l/*h=110,l=120*/, + 558_345_748_620l/*h=130,l=140*/, + 644_245_094_560l/*h=150,l=160*/ + }; + + // 2. Combine two arrays dynamically + long[] combinedArray = combineArrays(numbers1, numbers2); + + // 3. Modify the combined array by squaring even numbers + squareEvenNumbers(combinedArray); + + // 4. Double the size of the combined array dynamically + combinedArray = resizeArray(combinedArray, combinedArray.length * 2); + + // 5. Fill the new half of the array with values + for (int i = combinedArray.length / 2; i < combinedArray.length; i++) { + combinedArray[i] = i * 2; // Fill new slots with multiples of 2 + } + + // 6. Find the second largest element in the combined array + long secondLargest = findSecondLargest(combinedArray); + + // 7. Reverse the combined array + reverseArray(combinedArray); + + + // 8. Shift array elements to the left by 11 positions + shiftLeft(combinedArray, 11); + + return combinedArray[0] + secondLargest; + } + + // Method to combine two arrays into one dynamically + private static long[] combineArrays(long[] array1, long[] array2) { + int newLength = array1.length + array2.length; + long[] result = new long[newLength]; + + // Copy elements from the first array + for (int i = 0; i < array1.length; i++) { + result[i] = array1[i]; + } + + // Copy elements from the second array + for (int i = 0; i < array2.length; i++) { + result[array1.length + i] = array2[i]; + } + + return result; + } + + // Method to square even numbers in the array + private static void squareEvenNumbers(long[] array) { + for (int i = 0; i < array.length; i++) { + if (array[i] % 2 == 0) { + array[i] = array[i] * array[i]; + } + } + } + + // Method to resize the array dynamically + private static long[] resizeArray(long[] array, int newSize) { + long[] newArray = new long[newSize]; + for (int i = 0; i < array.length; i++) { + newArray[i] = array[i]; + } + return newArray; + } + + // Method to find the second largest element in the array + private static long findSecondLargest(long[] array) { + long largest = Long.MIN_VALUE; + long secondLargest = Long.MIN_VALUE; + + for (long num : array) { + if (num > largest) { + secondLargest = largest; + largest = num; + } else if (num > secondLargest && num != largest) { + secondLargest = num; + } + } + return secondLargest; + } + + // Method to reverse the array in place + private static void reverseArray(long[] array) { + int start = 0; + int end = array.length - 1; + while (start < end) { + long temp = array[start]; + array[start] = array[end]; + array[end] = temp; + start++; + end--; + } + } + + // Method to shift the array elements to the left by a given number of positions + private static void shiftLeft(long[] array, int positions) { + int length = array.length; + long[] temp = new long[positions]; + + // Store the first 'positions' elements in a temporary array + for (int i = 0; i < positions; i++) { + temp[i] = array[i]; + } + + // Shift the remaining elements to the left + for (int i = positions; i < length; i++) { + array[i - positions] = array[i]; + } + + // Place the stored elements at the end + for (int i = 0; i < positions; i++) { + array[length - positions + i] = temp[i]; + } + } +} diff --git a/tests/test_data/ExtremeStackTestLong.class b/tests/test_data/ExtremeStackTestLong.class new file mode 100644 index 00000000..e728a6d9 Binary files /dev/null and b/tests/test_data/ExtremeStackTestLong.class differ diff --git a/tests/test_data/ExtremeStackTestLong.java b/tests/test_data/ExtremeStackTestLong.java new file mode 100644 index 00000000..05122c7e --- /dev/null +++ b/tests/test_data/ExtremeStackTestLong.java @@ -0,0 +1,69 @@ + +public class ExtremeStackTestLong { + + public static void main(String[] args) { + // Test nested operations and method calls + long nestedResult = nestedCalculations(10); + //System.out.println("nestedResult=" + nestedResult); + + // Test loop operations with complex conditions + long loopResult = complexLoop(5); + //System.out.println("loopResult=" + loopResult); + + // Test combined recursive methods + long combinedRecursionResult = factorialPlusFibonacci(5); + //System.out.println("combinedRecursionResult=" + combinedRecursionResult); + + long result = nestedResult + loopResult + combinedRecursionResult; + //System.out.println("result=" + result); + } + + // Method with nested operations and method calls + private static long nestedCalculations(long n) { + long result = 0; + for (long i = 0; i < n; i++) { + result += multiplyAndAdd(i, n - i); + } + return result * 2 - n; // Final operation after loop + } + + // Helper method for nestedCalculations + private static long multiplyAndAdd(long x, long y) { + return (x * y) + (x - y); // Simple arithmetic operations + } + + // Method with loop, conditions, and nested operations + private static long complexLoop(long n) { + long result = 1; + for (long i = 1; i <= n; i++) { + if (i % 2 == 0) { + result *= i; // Multiply for even numbers + } else { + result += i; // Add for odd numbers + } + result -= (i % 3 == 0) ? 1 : 0; // Subtract 1 if divisible by 3 + } + return result; + } + + // Method combining recursion from factorial and Fibonacci + private static long factorialPlusFibonacci(long n) { + return factorial(n) + fibonacci(n); + } + + // Recursive method to calculate factorial + private static long factorial(long n) { + if (n <= 1) { + return 1; + } + return n * factorial(n - 1); + } + + // Recursive method to calculate the nth Fibonacci number + private static long fibonacci(long n) { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); + } +} diff --git a/tests/test_data/InstanceFieldsLong.class b/tests/test_data/InstanceFieldsLong.class new file mode 100644 index 00000000..a3c1354b Binary files /dev/null and b/tests/test_data/InstanceFieldsLong.class differ diff --git a/tests/test_data/InstanceFieldsLong.java b/tests/test_data/InstanceFieldsLong.java new file mode 100644 index 00000000..a2a963e6 --- /dev/null +++ b/tests/test_data/InstanceFieldsLong.java @@ -0,0 +1,31 @@ + +public class InstanceFieldsLong { + + private long resultSub; + private long resultAdd; + private long resultMul; + + public void sub(long first, long second) { + resultSub = first - second; + } + + public void add(long first, long second) { + resultAdd = first + second; + } + + public void mul(long first, long second) { + resultMul = first * second; + } + + public long getResultSub() { + return resultSub; + } + + public long getResultAdd() { + return resultAdd; + } + + public long getResultMul() { + return resultMul; + } +} diff --git a/tests/test_data/InstanceFieldsUserLong.class b/tests/test_data/InstanceFieldsUserLong.class new file mode 100644 index 00000000..ad64c5a5 Binary files /dev/null and b/tests/test_data/InstanceFieldsUserLong.class differ diff --git a/tests/test_data/InstanceFieldsUserLong.java b/tests/test_data/InstanceFieldsUserLong.java new file mode 100644 index 00000000..2c0f45d9 --- /dev/null +++ b/tests/test_data/InstanceFieldsUserLong.java @@ -0,0 +1,12 @@ + +public class InstanceFieldsUserLong { + public static void main(String[] args) { + long first = 42_949_672_980L/*h=10,l=20*/; + long second = 128_849_018_920L/*h=30,l=40*/; + InstanceFieldsLong[] instances = new InstanceFieldsLong[] { new InstanceFieldsLong(), new InstanceFieldsLong(), new InstanceFieldsLong() }; + instances[0].sub(first, second); + instances[1].add(first, second); + instances[2].mul(first, second); + long result = instances[0].getResultSub() + instances[1].getResultAdd() + instances[2].getResultMul(); + } +} diff --git a/tests/test_data/SubLong.class b/tests/test_data/SubLong.class index 59a5c46f..ceb43214 100644 Binary files a/tests/test_data/SubLong.class and b/tests/test_data/SubLong.class differ diff --git a/tests/test_data/SubLong.java b/tests/test_data/SubLong.java index 0200a669..571de9ce 100644 --- a/tests/test_data/SubLong.java +++ b/tests/test_data/SubLong.java @@ -1,9 +1,14 @@ public class SubLong { - private static long first = 100_000_000_000L; - private static long second = 99_000_000_000L; + private static long first; + private static long second; + + static { + first = 100_000_000_000L; + second = 99_000_000_000L; + } public static void main(String[] args) { - long result = first - second; + long result = second - first; } } diff --git a/vm/src/execution_engine/engine.rs b/vm/src/execution_engine/engine.rs index c019d12d..ae2ea31b 100644 --- a/vm/src/execution_engine/engine.rs +++ b/vm/src/execution_engine/engine.rs @@ -4,7 +4,7 @@ use crate::heap::heap::Heap; use crate::heap::java_instance::JavaInstance; use crate::method_area::java_method::JavaMethod; use crate::method_area::method_area::MethodArea; -use crate::stack::stack_frame::StackFrame; +use crate::stack::stack_frame::{i32toi64, StackFrame}; use crate::util::{ get_class_name_by_cpool_class_index, get_cpool_integer, get_cpool_long_double, Primitive, }; @@ -16,9 +16,9 @@ pub(crate) struct Engine<'a> { } impl<'a> Engine<'a> { - pub(crate) fn execute(&mut self, method: &JavaMethod) -> crate::error::Result> { + pub(crate) fn execute(&mut self, method: &JavaMethod) -> crate::error::Result>> { let mut stack_frames = vec![method.new_stack_frame()]; - let mut last_value: Option = None; + let mut last_value: Option> = None; let mut current_class_name: String; while !stack_frames.is_empty() { @@ -64,6 +64,11 @@ impl<'a> Engine<'a> { stack_frame.incr_pc(); println!("LCONST_0"); } + LCONST_1 => { + stack_frame.push_i64(1i64); + stack_frame.incr_pc(); + println!("LCONST_1"); + } BIPUSH => { stack_frame.incr_pc(); let value = stack_frame.get_bytecode_byte() as i32; @@ -126,6 +131,18 @@ impl<'a> Engine<'a> { stack_frame.incr_pc(); println!("ILOAD -> pos={pos}, value={value}"); } + LLOAD => { + stack_frame.incr_pc(); + let pos = stack_frame.get_bytecode_byte() as usize; + + let (low, high, value) = stack_frame.get_two_bytes_from_local(pos); + + stack_frame.push(low); + stack_frame.push(high); + + stack_frame.incr_pc(); + println!("LLOAD -> pos={pos}, value={value}"); + } ALOAD => { stack_frame.incr_pc(); let index = stack_frame.get_bytecode_byte() as usize; @@ -162,10 +179,7 @@ impl<'a> Engine<'a> { println!("ILOAD_3 -> value={value}"); } LLOAD_0 => { - let high = stack_frame.get_local(0); - let low = stack_frame.get_local(1); - - let value = ((high as i64) << 32) | (low as i64); + let (low, high, value) = stack_frame.get_two_bytes_from_local(0); stack_frame.push(low); stack_frame.push(high); @@ -173,11 +187,17 @@ impl<'a> Engine<'a> { stack_frame.incr_pc(); println!("LLOAD_0 -> value={value}"); } - LLOAD_2 => { - let high = stack_frame.get_local(2); - let low = stack_frame.get_local(3); + LLOAD_1 => { + let (low, high, value) = stack_frame.get_two_bytes_from_local(1); - let value = ((high as i64) << 32) | (low as i64); + stack_frame.push(low); + stack_frame.push(high); + + stack_frame.incr_pc(); + println!("LLOAD_1 -> value={value}"); + } + LLOAD_2 => { + let (low, high, value) = stack_frame.get_two_bytes_from_local(2); stack_frame.push(low); stack_frame.push(high); @@ -185,6 +205,15 @@ impl<'a> Engine<'a> { stack_frame.incr_pc(); println!("LLOAD_2 -> value={value}"); } + LLOAD_3 => { + let (low, high, value) = stack_frame.get_two_bytes_from_local(3); + + stack_frame.push(low); + stack_frame.push(high); + + stack_frame.incr_pc(); + println!("LLOAD_3 -> value={value}"); + } ALOAD_0 => { let reference = stack_frame.get_local(0); stack_frame.push(reference); @@ -214,18 +243,31 @@ impl<'a> Engine<'a> { let arrayref = stack_frame.pop(); let value = self.heap.get_array_value(arrayref, index)?; - stack_frame.push(value); + stack_frame.push(value[0]); + stack_frame.incr_pc(); + println!("IALOAD -> arrayref={arrayref}, index={index}, value={}", value[0]); + } + LALOAD => { + let index = stack_frame.pop(); + let arrayref = stack_frame.pop(); + let value = self.heap.get_array_value(arrayref, index)?; + + let high = value[0]; + let low = value[1]; + + stack_frame.push(low); + stack_frame.push(high); stack_frame.incr_pc(); - println!("IALOAD -> arrayref={arrayref}, index={index}, value={value}"); + println!("LALOAD -> arrayref={arrayref}, index={index}, value={value:?}"); } AALOAD => { let index = stack_frame.pop(); let arrayref = stack_frame.pop(); let objref = self.heap.get_array_value(arrayref, index)?; - stack_frame.push(objref); + stack_frame.push(objref[0]); stack_frame.incr_pc(); - println!("AALOAD -> arrayref={arrayref}, index={index}, objref={objref}"); + println!("AALOAD -> arrayref={arrayref}, index={index}, objref={}", objref[0]); } ISTORE => { stack_frame.incr_pc(); @@ -236,6 +278,19 @@ impl<'a> Engine<'a> { stack_frame.incr_pc(); println!("ISTORE -> pos={pos}, value={value}"); } + LSTORE => { + stack_frame.incr_pc(); + let pos = stack_frame.get_bytecode_byte() as usize; + let high = stack_frame.pop(); + let low = stack_frame.pop(); + + stack_frame.set_local(pos, low); + stack_frame.set_local(pos+1, high); + + stack_frame.incr_pc(); + let value = i32toi64(high, low); + println!("LSTORE -> value={value}"); + } ASTORE => { stack_frame.incr_pc(); let index = stack_frame.get_bytecode_byte() as usize; @@ -279,13 +334,35 @@ impl<'a> Engine<'a> { let high = stack_frame.pop(); let low = stack_frame.pop(); - stack_frame.set_local(1, high); - stack_frame.set_local(2, low); + stack_frame.set_local(1, low); + stack_frame.set_local(2, high); stack_frame.incr_pc(); let value = ((high as i64) << 32) | (low as i64); println!("LSTORE_1 -> value={value}"); } + LSTORE_2 => { + let high = stack_frame.pop(); + let low = stack_frame.pop(); + + stack_frame.set_local(2, low); + stack_frame.set_local(3, high); + + stack_frame.incr_pc(); + let value = ((high as i64) << 32) | (low as i64); + println!("LSTORE_2 -> value={value}"); + } + LSTORE_3 => { + let high = stack_frame.pop(); + let low = stack_frame.pop(); + + stack_frame.set_local(3, low); + stack_frame.set_local(4, high); + + stack_frame.incr_pc(); + let value = ((high as i64) << 32) | (low as i64); + println!("LSTORE_3 -> value={value}"); + } ASTORE_0 => { let objectref = stack_frame.pop(); stack_frame.set_local(0, objectref); @@ -319,17 +396,30 @@ impl<'a> Engine<'a> { let index = stack_frame.pop(); let arrayref = stack_frame.pop(); - self.heap.set_array_value(arrayref, index, value)?; + self.heap.set_array_value(arrayref, index, vec![value])?; stack_frame.incr_pc(); println!("IASTORE -> arrayref={arrayref}, index={index}, value={value}"); } + LASTORE => { + let high = stack_frame.pop(); + let low = stack_frame.pop(); + + let value = vec![high, low]; + let index = stack_frame.pop(); + let arrayref = stack_frame.pop(); + + self.heap.set_array_value(arrayref, index, value.clone())?; + + stack_frame.incr_pc(); + println!("LASTORE -> arrayref={arrayref}, index={index}, value={value:?}"); + } AASTORE => { let objref = stack_frame.pop(); let index = stack_frame.pop(); let arrayref = stack_frame.pop(); - self.heap.set_array_value(arrayref, index, objref)?; + self.heap.set_array_value(arrayref, index, vec![objref])?; stack_frame.incr_pc(); println!("AASTORE -> arrayref={arrayref}, index={index}, objref={objref}"); @@ -369,20 +459,12 @@ impl<'a> Engine<'a> { println!("IADD -> {a} + {b} = {result}"); } LADD => { - let b_high = stack_frame.pop() as i64; - let b_low = stack_frame.pop() as i64; + let b = stack_frame.pop_i64(); + let a = stack_frame.pop_i64(); - let a_high = stack_frame.pop() as i64; - let a_low = stack_frame.pop() as i64; - - let b = (b_high << 32) | b_low; - let a = (a_high << 32) | a_low; let result = a + b; - let result_low = result as i32; - let result_high = (result >> 32) as i32; - stack_frame.push(result_low); - stack_frame.push(result_high); + stack_frame.push_i64(result); stack_frame.incr_pc(); println!("LADD -> {a} + {b} = {result}"); @@ -397,20 +479,12 @@ impl<'a> Engine<'a> { println!("ISUB -> {a} - {b} = {result}"); } LSUB => { - let b_high = stack_frame.pop() as i64; - let b_low = stack_frame.pop() as i64; - - let a_high = stack_frame.pop() as i64; - let a_low = stack_frame.pop() as i64; + let b = stack_frame.pop_i64(); + let a = stack_frame.pop_i64(); - let b = (b_high << 32) | b_low; - let a = (a_high << 32) | a_low; let result = a - b; - let result_low = result as i32; - let result_high = (result >> 32) as i32; - stack_frame.push(result_low); - stack_frame.push(result_high); + stack_frame.push_i64(result); stack_frame.incr_pc(); println!("LSUB -> {a} - {b} = {result}"); @@ -424,6 +498,17 @@ impl<'a> Engine<'a> { stack_frame.incr_pc(); println!("IMUL -> {a} * {b} = {result}"); } + LMUL => { + let b = stack_frame.pop_i64(); + let a = stack_frame.pop_i64(); + + let result = b.wrapping_mul(a); + + stack_frame.push_i64(result); + + stack_frame.incr_pc(); + println!("LMUL -> {a} * {b} = {result}"); + } IDIV => { let b = stack_frame.pop(); let a = stack_frame.pop(); @@ -442,6 +527,17 @@ impl<'a> Engine<'a> { stack_frame.incr_pc(); println!("IREM -> {a} % {b} = {result}"); } + LREM => { + let b = stack_frame.pop_i64(); + let a = stack_frame.pop_i64(); + + let result = a % b; + + stack_frame.push_i64(result); + + stack_frame.incr_pc(); + println!("LREM -> {a} % {b} = {result}"); + } IINC => { stack_frame.incr_pc(); let index = stack_frame.get_bytecode_byte() as usize; @@ -456,6 +552,30 @@ impl<'a> Engine<'a> { stack_frame.incr_pc(); println!("IINC -> {current_val} + {const_val} = {new_val}"); } + I2L => { + let low = stack_frame.pop(); + + stack_frame.push(low); + stack_frame.push(0); + + stack_frame.incr_pc(); + println!("I2L -> {low}L"); + } + LCMP => { + let b = stack_frame.pop_i64(); + let a = stack_frame.pop_i64(); + + if a > b { + stack_frame.push(1); + } else if a < b { + stack_frame.push(-1); + } else { + stack_frame.push(0); + } + + stack_frame.incr_pc(); + println!("LCMP -> {a} ? {b}"); + } IFEQ => { let value = stack_frame.pop(); let offset = Self::get_two_bytes_ahead(stack_frame); @@ -468,6 +588,24 @@ impl<'a> Engine<'a> { stack_frame.advance_pc(if value != 0 { offset } else { 3 }); println!("IFNE -> value={value}, offset={offset}"); } + IFGE => { + 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!("IFGE -> value={value}, offset={offset}"); + } + IFGT => { + 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!("IFGT -> value={value}, offset={offset}"); + } + IFLE => { + 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!("IFLE -> value={value}, offset={offset}"); + } IF_ICMPEQ => { Self::branch(|a: i32, b| a == b, stack_frame, "IF_ICMPEQ"); } @@ -511,8 +649,7 @@ impl<'a> Engine<'a> { frame.push(ret_low); frame.push(ret_high); - let ret = ((ret_high as i64) << 32) | (ret_low as i64); - + let ret = i32toi64(ret_high, ret_low); println!("LRETURN -> ret={ret}"); } ARETURN => { @@ -523,16 +660,16 @@ impl<'a> Engine<'a> { .last_mut() .ok_or(Error::new_execution("Error getting stack last value"))? .push(objref); - println!("IRETURN -> objref={objref}"); + println!("ARETURN -> objref={objref}"); } RETURN => { println!("RETURN -> stack_frame.locals={:?}", stack_frame.locals); - last_value = stack_frames + last_value = Some(stack_frames .last() .ok_or(Error::new_execution("Error getting stack last value"))? .locals - .last() - .copied(); + .clone()); + stack_frames.pop(); // Return from method, pop the current frame // add more logic here } @@ -562,15 +699,9 @@ impl<'a> Engine<'a> { .unwrap() .borrow(); - field.raw_value().iter().for_each(|x| stack_frame.push(*x)); + field.raw_value().iter().rev().for_each(|x| stack_frame.push(*x)); - let value_as_string = field - .raw_value() - .iter() - .map(|x| x.to_string()) - .collect::>() - .join(","); - println!("GETSTATIC -> {class_name}.{field_name} is {value_as_string}"); + println!("GETSTATIC -> {class_name}.{field_name} is {:?}", field.raw_value()); stack_frame.incr_pc(); } PUTSTATIC => { @@ -608,16 +739,10 @@ impl<'a> Engine<'a> { value.push(stack_frame.pop()); } - let value_as_string = value - .iter() - .map(|x| x.to_string()) - .collect::>() - .join(","); - self.method_area - .set_static_field_value(&class_name, &field_name, value)?; + .set_static_field_value(&class_name, &field_name, value.clone())?; - println!("PUTSTATIC -> {class_name}.{field_name} = {value_as_string}"); + println!("PUTSTATIC -> {class_name}.{field_name} = {value:?}"); stack_frame.incr_pc(); } GETFIELD => { @@ -640,15 +765,10 @@ impl<'a> Engine<'a> { .heap .get_object_field_value(objectref, field_name.as_str())?; - value.iter().for_each(|x| stack_frame.push(*x)); + value.iter().rev().for_each(|x| stack_frame.push(*x)); stack_frame.incr_pc(); - let value_as_string = value - .iter() - .map(|x| x.to_string()) - .collect::>() - .join(","); - println!("GETFIELD -> objectref={objectref}, class_name={class_name}, field_name={field_name}, value={value_as_string}"); + println!("GETFIELD -> objectref={objectref}, class_name={class_name}, field_name={field_name}, value={value:?}"); } PUTFIELD => { let fieldref_constpool_index = Self::extract_two_bytes(stack_frame); @@ -688,12 +808,7 @@ impl<'a> Engine<'a> { value.clone(), )?; - let value_as_string = value - .iter() - .map(|x| x.to_string()) - .collect::>() - .join(","); - println!("PUTFIELD -> objectref={objectref}, class_name={class_name}, field_name={field_name} value={value_as_string}"); + println!("PUTFIELD -> objectref={objectref}, class_name={class_name}, field_name={field_name} value={value:?}"); stack_frame.incr_pc(); } INVOKEVIRTUAL => { diff --git a/vm/src/heap/heap.rs b/vm/src/heap/heap.rs index 58a8b759..92ccb85f 100644 --- a/vm/src/heap/heap.rs +++ b/vm/src/heap/heap.rs @@ -59,7 +59,7 @@ impl<'a> Heap<'a> { self.next_id } - pub(crate) fn get_array_value(&self, arrayref: i32, index: i32) -> crate::error::Result { + pub(crate) fn get_array_value(&self, arrayref: i32, index: i32) -> crate::error::Result<&Vec> { if let Some(Arr(arr)) = self.data.get(&arrayref) { arr.get_value(index) } else { @@ -71,7 +71,7 @@ impl<'a> Heap<'a> { &mut self, arrayref: i32, index: i32, - value: i32, + value: Vec, ) -> crate::error::Result<()> { if let Some(Arr(arr)) = self.data.get_mut(&arrayref) { arr.set_value(index, value) diff --git a/vm/src/heap/java_instance.rs b/vm/src/heap/java_instance.rs index 21f41793..5ae7a23a 100644 --- a/vm/src/heap/java_instance.rs +++ b/vm/src/heap/java_instance.rs @@ -13,25 +13,25 @@ pub(crate) struct JavaInstance<'a> { #[derive(Debug)] pub(crate) struct Array { - data: Vec, + data: Vec>, } impl Array { pub fn new(len: i32) -> Self { Self { - data: vec![0; len as usize], + data: vec![vec![0,0]; len as usize], //todo: use either 1 or 2 elements vector for corresponding type } } - pub fn get_value(&self, index: i32) -> crate::error::Result { + pub fn get_value(&self, index: i32) -> crate::error::Result<&Vec> { if let Some(arr_value) = self.data.get(index as usize) { - Ok(*arr_value) + Ok(arr_value) } else { Err(Error::new_execution("error getting array value")) } } - pub fn set_value(&mut self, index: i32, value: i32) -> crate::error::Result<()> { + pub fn set_value(&mut self, index: i32, value: Vec) -> crate::error::Result<()> { if let Some(arr_value) = self.data.get_mut(index as usize) { *arr_value = value; Ok(()) diff --git a/vm/src/stack/stack_frame.rs b/vm/src/stack/stack_frame.rs index 532dc0bb..8880c3c9 100644 --- a/vm/src/stack/stack_frame.rs +++ b/vm/src/stack/stack_frame.rs @@ -54,8 +54,16 @@ impl<'a> StackFrame<'a> { let low = value as i32; let high = (value >> 32) as i32; - self.push(high); self.push(low); + self.push(high); + } + + + pub fn pop_i64(&mut self) -> i64 { + let high = self.pop(); + let low = self.pop(); + + i32toi64(high, low) } pub fn pop(&mut self) -> i32 { @@ -70,7 +78,23 @@ impl<'a> StackFrame<'a> { *self.locals.get(index).unwrap() } + pub fn get_two_bytes_from_local(&mut self, index: usize) -> (i32, i32, i64) { + let low = self.get_local(index); + let high = self.get_local(index + 1); + + let value = i32toi64(high, low); + + (low, high, value) + } + pub fn current_class_name(&self) -> &str { &self.current_class_name } } + +pub fn i32toi64(high: i32, low: i32) -> i64 { + let high_converted = (high as i64) << 32; + let low_converted = low as u32/*to prevent sign extension*/ as i64; + + high_converted | low_converted +} diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 9e370854..029a4850 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -12,7 +12,7 @@ impl VM { Ok(Self { class_loader }) } - pub fn run(&self, main_class_name: &str) -> crate::error::Result> { + pub fn run(&self, main_class_name: &str) -> crate::error::Result>> { let main_method = self .class_loader .method_area()