Skip to content

Commit

Permalink
Basic support for int arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
hextriclosan committed Sep 7, 2024
1 parent 6b08645 commit fe3a390
Show file tree
Hide file tree
Showing 8 changed files with 394 additions and 9 deletions.
7 changes: 7 additions & 0 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,10 @@ fn should_do_calculate_fibonacci_recursively() {
let last_frame_value = vm.run("FibonacciRecursive").unwrap();
assert_eq!(55, last_frame_value.unwrap())
}

#[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())
}
Binary file added tests/test_data/Array.class
Binary file not shown.
120 changes: 120 additions & 0 deletions tests/test_data/Array.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
public class Array {

public static void main(String[] args) {
// 1. Initialize two arrays with different sizes
int[] numbers1 = {5, 3, 8, 12, 7};
int[] numbers2 = {14, 22, 16, 9};

// 2. Combine two arrays dynamically
int[] 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
int secondLargest = findSecondLargest(combinedArray);

// 7. Reverse the combined array
reverseArray(combinedArray);


// 8. Shift array elements to the left by 11 positions
shiftLeft(combinedArray, 11);

int result = combinedArray[0] + secondLargest;
}

// Method to combine two arrays into one dynamically
private static int[] combineArrays(int[] array1, int[] array2) {
int newLength = array1.length + array2.length;
int[] result = new int[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(int[] 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 int[] resizeArray(int[] array, int newSize) {
int[] newArray = new int[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 int findSecondLargest(int[] array) {
int largest = Integer.MIN_VALUE;
int secondLargest = Integer.MIN_VALUE;

for (int 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(int[] array) {
int start = 0;
int end = array.length - 1;
while (start < end) {
int 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(int[] array, int positions) {
int length = array.length;
int[] temp = new int[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];
}
}
}
172 changes: 171 additions & 1 deletion vm/src/execution_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::util::get_class_name_by_cpool_class_index;
use crate::util::{get_class_name_by_cpool_class_index, get_cpool_integer};

pub(crate) struct Engine<'a> {
method_area: &'a MethodArea,
Expand Down Expand Up @@ -80,6 +80,24 @@ impl<'a> Engine<'a> {

stack_frame.incr_pc();
}
LDC => {
stack_frame.incr_pc();
let cpoolindex = stack_frame.get_bytecode_byte() as usize;

let java_class = self
.method_area
.loaded_classes
.get(current_class_name.as_str())
.unwrap();

// todo add support of other types
let value = get_cpool_integer(&java_class.class_file, cpoolindex).unwrap();

stack_frame.push(value);

stack_frame.incr_pc();
println!("LDC -> cpoolindex={cpoolindex}, value={value}");
}
ILOAD => {
println!("ILOAD");
stack_frame.incr_pc();
Expand All @@ -90,6 +108,16 @@ impl<'a> Engine<'a> {

stack_frame.incr_pc();
}
ALOAD => {
stack_frame.incr_pc();
let index = stack_frame.get_bytecode_byte() as usize;

let objectref = stack_frame.get_local(index);
stack_frame.push(objectref);

stack_frame.incr_pc();
println!("ALOAD -> index={index}, objectref={objectref}");
}
ILOAD_0 => {
println!("ILOAD_0");
let val = stack_frame.get_local(0);
Expand Down Expand Up @@ -125,13 +153,38 @@ impl<'a> Engine<'a> {
stack_frame.incr_pc();
println!("ALOAD_0 -> reference={reference}");
}
ALOAD_1 => {
let reference = stack_frame.get_local(1);
stack_frame.push(reference);

stack_frame.incr_pc();
println!("ALOAD_1 -> reference={reference}");
}
ALOAD_2 => {
let reference = stack_frame.get_local(2);
stack_frame.push(reference);

stack_frame.incr_pc();
println!("ALOAD_2 -> reference={reference}");
}
ALOAD_3 => {
let reference = stack_frame.get_local(3);
stack_frame.push(reference);

stack_frame.incr_pc();
println!("ALOAD_3 -> reference={reference}");
}
IALOAD => {
let index = stack_frame.pop();
let arrayref = stack_frame.pop();

let value = self.heap.get_array_value(arrayref, index)?;

stack_frame.push(value);

stack_frame.incr_pc();
println!("IALOAD -> arrayref={arrayref}, index={index}, value={value}");
}
ISTORE => {
println!("ISTORE");
stack_frame.incr_pc();
Expand Down Expand Up @@ -182,13 +235,44 @@ impl<'a> Engine<'a> {

stack_frame.incr_pc();
}
ASTORE_0 => {
println!("ASTORE_0");
let objectref = stack_frame.pop();
stack_frame.set_local(0, objectref);

stack_frame.incr_pc();
}
ASTORE_1 => {
println!("ASTORE_1");
let objectref = stack_frame.pop();
stack_frame.set_local(1, objectref);

stack_frame.incr_pc();
}
ASTORE_2 => {
println!("ASTORE_2");
let objectref = stack_frame.pop();
stack_frame.set_local(2, objectref);

stack_frame.incr_pc();
}
ASTORE_3 => {
println!("ASTORE_3");
let objectref = stack_frame.pop();
stack_frame.set_local(3, objectref);

stack_frame.incr_pc();
}
IASTORE => {
let value = stack_frame.pop();
let index = stack_frame.pop();
let arrayref = stack_frame.pop();

self.heap.set_array_value(arrayref, index, value)?;

stack_frame.incr_pc();
println!("IASTORE -> arrayref={arrayref}, index={index}, value={value}");
}
POP => {
stack_frame.pop();

Expand All @@ -203,6 +287,17 @@ impl<'a> Engine<'a> {
stack_frame.incr_pc();
println!("DUP -> {val}");
}
DUP2 => {
let val1 = stack_frame.pop();
let val2 = stack_frame.pop();
stack_frame.push(val2);
stack_frame.push(val1);
stack_frame.push(val2);
stack_frame.push(val1);

stack_frame.incr_pc();
println!("DUP2 -> {val1} {val2}");
}
IADD => {
let b = stack_frame.pop();
let a = stack_frame.pop();
Expand Down Expand Up @@ -230,6 +325,15 @@ impl<'a> Engine<'a> {
stack_frame.incr_pc();
println!("IMUL -> {a} * {b} = {result}");
}
IDIV => {
let b = stack_frame.pop();
let a = stack_frame.pop();
let result = a / b; //todo add check for ArithmeticException here
stack_frame.push(result);

stack_frame.incr_pc();
println!("IDIV -> {a} / {b} = {result}");
}
IREM => {
println!("IREM");
let b = stack_frame.pop();
Expand Down Expand Up @@ -282,6 +386,22 @@ impl<'a> Engine<'a> {
stack_frame.advance_pc(3);
}
}
IF_ICMPEQ => {
println!("IF_ICMPEQ");

let value2 = stack_frame.pop();
let value1 = stack_frame.pop();

let branchbyte1 = stack_frame.get_bytecode_byte_1() as u16;
let branchbyte2 = stack_frame.get_bytecode_byte_2() as u16;
let offset = ((branchbyte1 << 8) | branchbyte2) as i16;

if value1 == value2 {
stack_frame.advance_pc(offset);
} else {
stack_frame.advance_pc(3);
}
}
IF_ICMPNE => {
println!("IF_ICMPNE");

Expand Down Expand Up @@ -346,6 +466,22 @@ impl<'a> Engine<'a> {
stack_frame.advance_pc(3);
}
}
IF_ICMPLE => {
println!("IF_ICMPLE");

let value2 = stack_frame.pop();
let value1 = stack_frame.pop();

let branchbyte1 = stack_frame.get_bytecode_byte_1() as u16;
let branchbyte2 = stack_frame.get_bytecode_byte_2() as u16;
let offset = ((branchbyte1 << 8) | branchbyte2) as i16;

if value1 <= value2 {
stack_frame.advance_pc(offset);
} else {
stack_frame.advance_pc(3);
}
}
GOTO => {
println!("GOTO");

Expand All @@ -367,6 +503,19 @@ impl<'a> Engine<'a> {
.ok_or(Error::new_execution("Error getting stack last value"))?
.push(ret);
}
ARETURN => {
println!(
"ARETURN -> locals={:?}, operand_stack={:?}",
stack_frame.locals, stack_frame.operand_stack
);
let objref = stack_frame.pop();

stack_frames.pop();
stack_frames
.last_mut()
.ok_or(Error::new_execution("Error getting stack last value"))?
.push(objref);
}
RETURN => {
println!(
"RETURN -> locals={:?}, operand_stack={:?}",
Expand Down Expand Up @@ -648,6 +797,27 @@ impl<'a> Engine<'a> {
println!("NEW -> class={class_constpool_index}, reference={instanceref}");
stack_frame.incr_pc();
}
NEWARRAY => {
stack_frame.incr_pc();
let atype = stack_frame.get_bytecode_byte();

let length = stack_frame.pop();

let arrayref = self.heap.create_array(length);
stack_frame.push(arrayref);

stack_frame.incr_pc();
println!("NEWARRAY -> atype={atype}, length={length}, arrayref={arrayref}");
}
ARRAYLENGTH => {
let arrayref = stack_frame.pop();

let len = self.heap.get_array_len(arrayref)?;
stack_frame.push(len);

stack_frame.incr_pc();
println!("ARRAYLENGTH -> arrayref={arrayref}, len={len}");
}
_ => unreachable!("{}", format! {"xxx = {}", stack_frame.get_bytecode_byte()}),
}
}
Expand Down
Loading

0 comments on commit fe3a390

Please sign in to comment.