diff --git a/src/class.rs b/src/class.rs index 2710acb..cc2d502 100644 --- a/src/class.rs +++ b/src/class.rs @@ -28,7 +28,8 @@ pub fn get_class(vm: &mut Vm, calling_class_name: Option<&str>, class_name: &str // not pretty...sorry if let Some(calling_class_name) = calling_class_name { if class_name == calling_class_name { // works around the situation that static initializer needs a ref to the class it's in - return Ok(CLASSDEFS.get(class_name.into()).unwrap().clone()); // in that case the class is guaranteed to be here + panic!(); + // return Ok(CLASSDEFS.get(class_name.into()).unwrap().clone()); // in that case the class is guaranteed to be here } } @@ -42,6 +43,8 @@ pub fn get_class(vm: &mut Vm, calling_class_name: Option<&str>, class_name: &str if let Some(super_class_name) = super_class_name { if let Ok(super_class) = get_class(vm, Some(class_name), &super_class_name) { class.super_class = Some(super_class); + } else { + unreachable!() } } @@ -57,11 +60,16 @@ pub fn get_class(vm: &mut Vm, calling_class_name: Option<&str>, class_name: &str // the problem is pretty fundamental: method (clinit) should be called before the class is returned, // but the executing code needs a reference to itself. So get_class is called recursively, but clinit must be called exactly once! // putting the call to clinit in the closure above is way nicer, but the signature change (wrap it in Arc) - if new_class.borrow().methods.contains_key("()V") { + //update: this is probably not needed anymore because of the check in PUTSTATIC + + //somehow this clone needs to be there before clinit is called, even though the newclass ref remains in scope + let clone = new_class.clone(); + + if new_class.clone().borrow().methods.contains_key("()V") { vm.execute_class(new_class.clone(), "()V", vec![]).unwrap(); } - Ok(new_class.clone()) + Ok(clone) } } @@ -125,11 +133,11 @@ impl Class { } pub(crate) fn n_object_fields(&self) -> usize { - self.object_field_mapping.iter().map(|(_,v)|v.len()).reduce(|acc, e| acc + e).unwrap() + self.object_field_mapping.iter().map(|(_, v)| v.len()).reduce(|acc, e| acc + e).unwrap() } pub(crate) fn n_static_fields(&self) -> usize { - self.static_field_mapping.iter().map(|(_,v)|v.len()).reduce(|acc, e| acc + e).unwrap() + self.static_field_mapping.iter().map(|(_, v)| v.len()).reduce(|acc, e| acc + e).unwrap() } // Create a mapping per field(name) to an index in the storage vector that contains the instance data. @@ -194,7 +202,6 @@ impl Class { ); //name => (type,index) *object_field_map_index += 1; } - } (this_fields, static_fields) } @@ -242,7 +249,7 @@ impl Class { "D" => Value::F64(0.0), _ => Value::Null, }; - println!("{} = {:?}", name, value ); + println!("{} = {:?}", name, value); field_data[*index] = Some(value.into()); } } @@ -540,7 +547,7 @@ pub enum Value { BOOL(bool), CHAR(char), Ref(Arc>), - Utf8(String) + Utf8(String), } impl Value { diff --git a/src/heap.rs b/src/heap.rs index cbf2707..b00281e 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -1,12 +1,12 @@ use std::cell::{RefCell, UnsafeCell}; use std::fmt; +use std::fmt::{Debug, Formatter}; use std::sync::Arc; use crate::class::{Class, Type, UnsafeValue, Value}; use crate::heap::ObjectRef::{IntArray, ObjectArray}; // can contain object or array -#[derive(Debug)] pub enum ObjectRef { ByteArray(Vec), ShortArray(Vec), @@ -30,6 +30,23 @@ impl ObjectRef { } } +impl Debug for ObjectRef{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + ObjectRef::BooleanArray(d) => write!(f, "[Z;{}]", d.len()), + ObjectRef::ByteArray(d) => write!(f, "[B;{}]", d.len()), + ObjectRef::CharArray(d) => write!(f, "[C;{}]", d.len()), + ObjectRef::DoubleArray(d) => write!(f, "[D;{}]", d.len()), + ObjectRef::FloatArray(d) => write!(f, "[F;{}]", d.len()), + ObjectRef::IntArray(d) => write!(f, "[I;{}]", d.len()), + ObjectRef::LongArray(d) => write!(f, "[J;{}]", d.len()), + ObjectRef::ObjectArray(t, d) => write!(f,"[L{};{}]", t.borrow().name,d.len()), + ObjectRef::ShortArray( d) => write!(f, "[S;{}]", d.len()), + ObjectRef::Object( r) => write!(f,"{}{{ {:?} }}", r.class.borrow().name, r.data), + } + } +} + // trying to implement efficient object instance storage pub struct Object { // locked: bool, diff --git a/src/vm.rs b/src/vm.rs index a7cf744..f4e15be 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -15,7 +15,7 @@ use crate::native::invoke_native; use crate::opcodes::*; #[derive(Debug)] -struct StackFrame { +pub(crate) struct StackFrame { at: String, data: Vec, } @@ -50,7 +50,7 @@ impl StackFrame { pub struct Vm { pub classpath: Vec, heap: Heap, - stackframes: Vec, + pub(crate) stackframes: Vec, } #[cfg(target_family = "unix")] @@ -133,6 +133,7 @@ impl Vm { self.current_frame().push(Value::I32(0)); } ICONST_1 => { + println!("ICONST_1"); self.current_frame().push(Value::I32(1)); } ICONST_2 => { @@ -218,7 +219,7 @@ impl Vm { self.current_frame().push(Value::F32(*f)); } _ => { - panic!("unexpected") + unreachable!() } } } @@ -233,7 +234,7 @@ impl Vm { self.current_frame().push(Value::I64(*l)); } _ => { - panic!("unexpected") + unreachable!() } } } @@ -342,6 +343,16 @@ impl Vm { let value = self.current_frame().pop()?; borrow.static_data[*val_index] = Some(value); } + unsafe { + for v in &borrow.static_data { + let v = &*v.as_ref().unwrap().get(); + if let Value::Ref(vv) = v { + println!("{:?}", &*vv.get()) + } else { + println!("{:?}", *v); + } + } + } } GETFIELD => unsafe { let borrow = this_class.borrow(); @@ -359,7 +370,11 @@ impl Vm { if let ObjectRef::Object(ref mut object) = &mut *instance.get() { let value = object.get(class_name, field_name); self.current_frame().push_arc(Arc::clone(value)); + } else { + unreachable!() } + } else { + unreachable!() } }, PUTFIELD => unsafe { @@ -379,6 +394,8 @@ impl Vm { if let ObjectRef::Object(ref mut object) = &mut *instance.get() { object.set(class_name, field_name, value); } + } else { + unreachable!() } }, INVOKEVIRTUAL | INVOKESPECIAL => unsafe { @@ -406,6 +423,8 @@ impl Vm { } } println!("stack {} at {}", self.current_frame().len(), self.current_frame().at) + } else { + unreachable!() } }, INVOKESTATIC => unsafe { @@ -429,6 +448,8 @@ impl Vm { self.current_frame().push_arc(returnvalue.clone()); } } + } else { + unreachable!() } }, NEW => { @@ -445,7 +466,7 @@ impl Vm { self.current_frame().push(Value::Ref(Arc::clone(&object))); self.heap.new_object(object); } - ANEWARRAY => unsafe{ + ANEWARRAY => unsafe { println!("ANEWARRAY"); let class_index = &read_u16(&code.opcodes, pc); let borrow = this_class.borrow(); @@ -453,17 +474,16 @@ impl Vm { let class_name = borrow.cp_utf8(class_name_index).unwrap(); let arraytype = get_class(self, Some(&borrow.name), class_name)?; let count = self.current_frame().pop()?; - if let Value::I32(count) = *count.get(){ // why does pop()?.get() give weird results? + if let Value::I32(count) = *count.get() { // why does pop()?.get() give weird results? let array = ObjectRef::new_object_array(arraytype, count as usize); let array = Arc::new(UnsafeCell::new(array)); self.current_frame().push(Value::Ref(Arc::clone(&array))); - println!("{}",self.current_frame().len()); + println!("{}", self.current_frame().len()); self.heap.new_object(array); } else { panic!(); } - } //TODO implement all opcodes @@ -478,43 +498,45 @@ impl Vm { } unsafe fn array_load(&mut self) -> Result<(), Error> { - if let Value::I32(index) = &*self.current_frame().pop()?.get() { + let value = self.current_frame().pop()?; + + if let Value::I32(index) = &*value.get() { let index = *index as usize; - let arrayref = &*self.current_frame().pop()?.get(); - if let Value::Null = arrayref { + let arrayref = self.current_frame().pop()?; + if let Value::Null = &*arrayref.get() { return Err(anyhow!("NullpointerException")); } - if let Value::Ref(ref objectref) = arrayref { + if let Value::Ref(objectref) = &*arrayref.get() { match &*objectref.get() { - ObjectRef::ByteArray(ref array) => { + ObjectRef::ByteArray(array) => { self.current_frame().push(Value::I32(array[index] as i32)); } - ObjectRef::ShortArray(ref array) => { + ObjectRef::ShortArray(array) => { self.current_frame().push(Value::I32(array[index] as i32)); } - ObjectRef::IntArray(ref array) => { + ObjectRef::IntArray(array) => { self.current_frame().push(Value::I32(array[index])); } - ObjectRef::BooleanArray(ref array) => { + ObjectRef::BooleanArray(array) => { self.current_frame().push(Value::I32(array[index] as i32)); } - ObjectRef::CharArray(ref array) => { + ObjectRef::CharArray(array) => { self.current_frame().push(Value::CHAR(array[index])); } - ObjectRef::LongArray(ref array) => { + ObjectRef::LongArray(array) => { self.current_frame().push(Value::I64(array[index])); } - ObjectRef::FloatArray(ref array) => { + ObjectRef::FloatArray(array) => { self.current_frame().push(Value::F32(array[index])); } - ObjectRef::DoubleArray(ref array) => { + ObjectRef::DoubleArray(array) => { self.current_frame().push(Value::F64(array[index])); } - ObjectRef::ObjectArray(_arraytype, ref data) => { + ObjectRef::ObjectArray(_arraytype, data) => { self.current_frame() - .push(Value::Ref(data[index].clone())); + .push(Value::Ref(data[index].clone())); } - ObjectRef::Object(_) => {} //throw error? + ObjectRef::Object(_) => { panic!("should be array") } //throw error? } } } @@ -523,66 +545,86 @@ impl Vm { unsafe fn array_store(&mut self) -> Result<(), Error> { let value = self.current_frame().pop()?; - let index = &mut *self.current_frame().pop()?.get(); - let mut arrayref = &mut *self.current_frame().pop()?.get(); + let index = &*self.current_frame().pop()?; + let mut arrayref = &mut self.current_frame().pop()?; - if let Value::Null = arrayref { + if let Value::Null = &*arrayref.get() { return Err(anyhow!("NullpointerException")); } - if let Value::I32(index) = index { - if let Value::Ref(ref mut objectref) = arrayref { + if let Value::I32(index) = &*index.get() { + if let Value::Ref(ref mut objectref) = &mut *arrayref.get() { match &mut *objectref.get() { ObjectRef::ByteArray(ref mut array) => { if let Value::I32(value) = *value.get() { // is i32 correct? array[*index as usize] = value as i8; + } else { + unreachable!() } } ObjectRef::ShortArray(ref mut array) => { if let Value::I32(value) = *value.get() { // is i32 correct? array[*index as usize] = value as i16; + } else { + unreachable!() } } ObjectRef::IntArray(ref mut array) => { if let Value::I32(value) = *value.get() { array[*index as usize] = value; + } else { + unreachable!() } } ObjectRef::BooleanArray(ref mut array) => { if let Value::I32(value) = *value.get() { array[*index as usize] = value > 0; + } else { + unreachable!() } } ObjectRef::CharArray(ref mut array) => { if let Value::I32(value) = *value.get() { array[*index as usize] = char::from_u32_unchecked(value as u32); + } else { + unreachable!() } } ObjectRef::LongArray(ref mut array) => { if let Value::I64(value) = *value.get() { array[*index as usize] = value; + } else { + unreachable!() } } ObjectRef::FloatArray(ref mut array) => { if let Value::F32(value) = *value.get() { array[*index as usize] = value + } else { + unreachable!() } } ObjectRef::DoubleArray(ref mut array) => { if let Value::F64(value) = *value.get() { array[*index as usize] = value + } else { + unreachable!() } } ObjectRef::ObjectArray(arraytype, ref mut array) => { if let Value::Ref(ref value) = *value.get() { array[*index as usize] = value.clone(); + } else { + unreachable!() } } ObjectRef::Object(_) => {} //throw error? } } + } else { + unreachable!() } Ok(()) } diff --git a/tests/Main.class b/tests/Main.class index 7d29e53..b03b41f 100644 Binary files a/tests/Main.class and b/tests/Main.class differ diff --git a/tests/Main.java b/tests/Main.java index cb3d6d5..1c2e17e 100644 --- a/tests/Main.java +++ b/tests/Main.java @@ -1,14 +1,14 @@ public class Main { - final static int a; + final static String a; static{ - a=1; + a=""; } public static void main(String[] args){ FloatBean f = new FloatBean(); f.setValue(42F); - + System.out.println(a); } }