diff --git a/src/class.rs b/src/class.rs index d11c6d1..d1788a6 100644 --- a/src/class.rs +++ b/src/class.rs @@ -1,7 +1,6 @@ use std::cell::{RefCell, UnsafeCell}; use std::collections::HashMap; use std::fmt; -use std::hash::Hash; use std::rc::Rc; use std::sync::Arc; @@ -20,55 +19,49 @@ static mut CLASSDEFS: Lazy>>> = Lazy::new(|| // gets the Class from cache, or reads it from classpath, // then parses the binary data into a Class struct // Vm keeps ownership of the class and hands out Arc references to it -pub fn get_class(vm: &mut Vm, calling_class_name: Option<&str>, class_name: &str) -> Result>, Error> { +pub fn get_class(vm: &mut Vm, _calling_class_name: Option<&str>, class_name: &str) -> Result>, Error> { println!("get_class {}", class_name); unsafe { // 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 - panic!(); - // return Ok(CLASSDEFS.get(class_name.into()).unwrap().clone()); // in that case the class is guaranteed to be here - } - } + // 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 + // } + // } - let new_class = CLASSDEFS.entry(class_name.into()).or_insert_with(|| { + let class = CLASSDEFS.entry(class_name.into()).or_insert_with(|| { println!("read class {} ", class_name); let resolved_path = find_class(&vm.classpath, class_name).unwrap(); // println!("full path {}", resolved_path); let bytecode = read_bytecode(resolved_path).unwrap(); - let mut class = load_class(bytecode).unwrap(); - let super_class_name = class.super_class_name.as_ref(); - 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!() + let class = load_class(bytecode).unwrap(); + Arc::new(RefCell::new(class)) + }); + + let clone = class.clone(); + let clone2 = class.clone(); + if !class.borrow().inited { + let super_class_name = class.borrow().super_class_name.as_ref().map(|n| n.to_owned()); + { + if let Some(super_class_name) = super_class_name { + if let Ok(super_class) = get_class(vm, Some(class_name), &super_class_name) { + class.borrow_mut().super_class = Some(super_class); + } else { + unreachable!() + } } } - let class = Arc::new(RefCell::new(class)); Class::initialize_fields(class.clone()); - class - }); + let clinit = clone.borrow().methods.contains_key("()V"); + if clinit{ + vm.execute_class(class.clone(), "()V", vec![]).unwrap(); + } - - // calling clinit before the end of this function has been a PITA - // 1. infinite recursion - // panic after second borrow. - // 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) - //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(); + clone.borrow_mut().inited = true; } - - Ok(clone) + Ok(clone2) } } @@ -89,6 +82,7 @@ pub struct Class { pub fields: HashMap, pub methods: HashMap>, pub attributes: HashMap, + pub inited: bool, pub(crate) object_field_mapping: HashMap>, // first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index) pub(crate) static_field_mapping: HashMap>, @@ -125,6 +119,7 @@ impl Class { fields, methods, attributes, + inited: false, object_field_mapping: HashMap::new(), static_field_mapping: HashMap::new(), static_data: vec![], @@ -565,17 +560,18 @@ pub type UnsafeValue = Arc>; pub type UnsafeRef = Arc>; -pub fn unsafe_ref(object: ObjectRef) -> UnsafeRef{ - return Arc::new(UnsafeCell::new(object)) +pub fn unsafe_ref(object: ObjectRef) -> UnsafeRef { + return Arc::new(UnsafeCell::new(object)); } -pub fn unsafe_val(val: Value) -> UnsafeValue{ - return Arc::new(UnsafeCell::new(val)) +pub fn unsafe_val(val: Value) -> UnsafeValue { + return Arc::new(UnsafeCell::new(val)); } -pub fn type_ref(class: Class) -> Type{ - return Arc::new(RefCell::new(class)) +pub fn type_ref(class: Class) -> Type { + return Arc::new(RefCell::new(class)); } + pub type Type = Arc>; unsafe impl Send for Value {} diff --git a/src/io.rs b/src/io.rs index a929a62..073e662 100644 --- a/src/io.rs +++ b/src/io.rs @@ -9,7 +9,10 @@ use std::io::Read; /// * [jar/zip]#[package_path]/[class].class /// * [dir]/[package_path]/[class].class pub fn find_class(classpath: &Vec, class_name: &str) -> Result { - if class_name.starts_with("java/") { + if class_name.starts_with("java") + || class_name.starts_with("sun/") + || class_name.starts_with("com/sun/") + || class_name.starts_with("jdk/") { let mut path: String = "jmods/java.base.jmod#classes/".into(); path.push_str(class_name); path.push_str(".class"); diff --git a/src/vm.rs b/src/vm.rs index f913ef2..b1dae04 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -321,42 +321,32 @@ impl Vm { let that_borrow = that.borrow(); let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap(); println!("get static field {}", name); - self.current_frame().push_ref(borrow.static_data.get(*val_index).unwrap().as_ref().unwrap().clone()); + self.current_frame().push_ref(that_borrow.static_data.get(*val_index).unwrap().as_ref().unwrap().clone()); } PUTSTATIC => { println!("PUTSTATIC"); let mut borrow = this_class.borrow_mut(); let cp_index = read_u16(&code.opcodes, pc); - let (class_index, field_name_and_type_index) = - borrow.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid - let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap(); - let (name) = borrow.cp_utf8(name_index).unwrap(); - let class_name_index = borrow.cp_class_ref(class_index).unwrap(); - println!("field {}", name); - let that_class_name = borrow.cp_utf8(class_name_index).unwrap(); + // let (class_index, field_name_and_type_index) = + // borrow.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid + // let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap(); + // let (name) = borrow.cp_utf8(name_index).unwrap(); + // let class_name_index = borrow.cp_class_ref(class_index).unwrap(); + // println!("field {}", name); + // let that_class_name = borrow.cp_utf8(class_name_index).unwrap(); - if &borrow.name == that_class_name {// may have to apply this in GETSTATIC too - let (_, val_index) = borrow.static_field_mapping.get(that_class_name).unwrap().get(name).as_ref().unwrap(); - let val_index = *val_index; - let value = self.current_frame().pop()?; - borrow.static_data[val_index] = Some(value); - } else { - let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?; - let that_borrow = that.borrow(); // if already borrowed, then that_class == this_class - let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap(); - 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); - } - } - } + // if &borrow.name == that_class_name {// may have to apply this in GETSTATIC too + // let (_, val_index) = borrow.static_field_mapping.get(that_class_name).unwrap().get(name).as_ref().unwrap(); + // let val_index = *val_index; + // let value = self.current_frame().pop()?; + // borrow.static_data[val_index] = Some(value); + // } else { + // let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?; + // let that_borrow = that.borrow(); // if already borrowed, then that_class == this_class + // let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap(); + // let value = self.current_frame().pop()?; + // borrow.static_data[*val_index] = Some(value); + // } } GETFIELD => unsafe { let borrow = this_class.borrow(); @@ -414,7 +404,7 @@ impl Vm { args.insert(0, copy(self.current_frame().pop()?)); } args.insert(0, self.current_frame().pop()?); - let mut return_value = self.execute( + let return_value = self.execute( Some(this_class.borrow().name.as_str()), &invocation.class_name, &invocation.method.name, @@ -432,6 +422,7 @@ impl Vm { } }, INVOKESTATIC => unsafe { + println!("INVOKESTATIC"); let cp_index = read_u16(&code.opcodes, pc); if let Some(invocation) = get_signature_for_invoke(&method.constant_pool, cp_index) @@ -440,7 +431,7 @@ impl Vm { for _ in 0..invocation.method.num_args { args.insert(0, copy(self.current_frame().pop()?)); } - let mut returnvalue = self.execute( + let returnvalue = self.execute( Some(this_class.borrow().name.as_str()), &invocation.class_name, &invocation.method.name, @@ -680,14 +671,14 @@ unsafe fn copy(value: UnsafeValue) -> UnsafeValue { unsafe_val(match (&*value.get()) { Void => Void, Null => Null, - BOOL(b)=> BOOL(*b), - CHAR(c)=> CHAR(*c), - I32(i)=> I32(*i), - I64(l)=> I64(*l), - F32(f)=> F32(*f), - F64(d)=> F64(*d), - Ref(r)=> Ref(r.clone()), - Utf8(s)=> Utf8(s.to_owned()), + BOOL(b) => BOOL(*b), + CHAR(c) => CHAR(*c), + I32(i) => I32(*i), + I64(l) => I64(*l), + F32(f) => F32(*f), + F64(d) => F64(*d), + Ref(r) => Ref(r.clone()), + Utf8(s) => Utf8(s.to_owned()), }) } @@ -719,6 +710,7 @@ fn get_hum_args(signature: &str) -> usize { while chars[i] != ';' { i += 1; } + i += 1; num += 1; } else if chars[i] == ')' { break;