diff --git a/jmods/java.base.jar b/jmods/java.base.jar deleted file mode 100644 index 528778a..0000000 Binary files a/jmods/java.base.jar and /dev/null differ diff --git a/src/class.rs b/src/class.rs index 76e78cf..14152db 100644 --- a/src/class.rs +++ b/src/class.rs @@ -1,126 +1,10 @@ -use std::cell::{RefCell, UnsafeCell}; -use std::collections::HashMap; -use std::fmt; -use std::rc::Rc; -use std::sync::Arc; +use std::collections::{HashMap, LinkedList}; -use anyhow::Error; -use log::info; -use once_cell::sync::Lazy; +use crate::class::ObjectRef::*; -use crate::classloader::{CpEntry, load_class}; -use crate::heap::{ObjectRef}; -use crate::io::{find_class, read_bytecode, read_u16}; -use crate::vm::Vm; +pub type ClassId = usize; -//trying to be ready for multithreaded as much as possible, using Arc's and all, but it will still require (a lot of) extra work -pub static mut CLASSDEFS: Lazy>>> = Lazy::new(|| HashMap::new()); -//TODO add mutex.. -pub static mut CLASSES: Lazy> = Lazy::new(|| HashMap::new()); //TODO add mutex.. - -// 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(crate) fn get_class( - vm: &mut Vm, - class_name: &str, -) -> Result>, Error> { - info!("get_class {}", class_name); - - unsafe { - 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(); - let bytecode = read_bytecode(resolved_path).unwrap(); - let class = load_class(bytecode).unwrap(); - Arc::new(RefCell::new(class)) - }); - - - let clone = class.clone(); - let inited = class.borrow().inited; - if !inited { - // not sure why I have to create the clones first - let clone2 = class.clone(); - let clone3 = class.clone(); - let clone4 = class.clone(); - let mut some_class = class.clone(); - - if class_name != "java/lang/Class" { - let klazz = get_class(vm, "java/lang/Class")?; - let mut class_instance = Vm::new_instance(klazz); - class_instance.set(&"java/lang/Class".to_owned(), &"name".to_owned(), Value::Utf8(class_name.into())); - CLASSES.insert(class_name.into(), Value::Ref(unsafe_ref(ObjectRef::Object(Box::new(class_instance))))); - } - - // must not enter here twice! - clone2.borrow_mut().inited = true; - - let mut supers = vec![]; - if class_name != "java/lang/Class" { - loop { - let super_class_name = some_class - .clone() - .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, &super_class_name) { - supers.push(super_class.clone()); - some_class = super_class.clone(); - clone4.borrow_mut().super_class = Some(super_class); - } else { - break; - } - } else { - break; - } - } - } - } - - Class::initialize_fields(clone3, supers); - let clinit = clone2.borrow().methods.contains_key("()V"); - let name = &clone2.borrow().name.to_owned(); - if clinit { - vm.execute_special(name, "()V", vec![]).unwrap(); - } - } - Ok(clone) - } -} - -/// the class definition as read from the class file + derived values -// TODO implement call to static initializers -#[derive(Debug)] -pub struct Class { - pub minor_version: u16, - pub major_version: u16, - pub constant_pool: Rc>, - pub access_flags: u16, - pub name: String, - pub super_class_name: Option, - pub super_class: Option, - pub super_classes: Vec, - pub interface_indices: Vec, - pub interfaces: Vec, - pub fields: HashMap, - pub methods: HashMap>, - pub attributes: HashMap, - pub inited: bool, - - // lookup index and type from the name - pub(crate) object_field_mapping: HashMap>, - pub(crate) static_field_mapping: HashMap>, - // static fields - pub(crate) static_data: Vec, -} - -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct TypeIndex { pub type_name: String, pub index: usize, @@ -135,43 +19,23 @@ impl TypeIndex { } } +// could move classdef into here. Saves one hashmap lookup +// have to look at ownership though +#[derive(Debug, Clone)] +pub struct Class { + pub id: ClassId, + pub initialized: bool, + pub name: String, + pub superclass: Option, + pub parents: LinkedList, + pub interfaces: Vec, + // lookup index and type from the name + pub(crate) object_field_mapping: HashMap>, + pub(crate) static_field_mapping: HashMap>, + // pub(crate) static_field_data: Vec, +} + impl Class { - pub fn new( - minor_version: u16, - major_version: u16, - constant_pool: Rc>, - access_flags: u16, - this_class: u16, - super_class_index: u16, - interface_indices: Vec, - fields: HashMap, - methods: HashMap>, - attributes: HashMap, - ) -> Self { - let name = Class::class_name(this_class, constant_pool.clone()).unwrap(); - let super_class_name = Class::class_name(super_class_index, constant_pool.clone()); - - Self { - major_version, - minor_version, - constant_pool, - access_flags, - name, - super_class_name, - super_class: None, // has to be instantiated later, because it involves classloading. maybe not store it here - super_classes: vec![], - interface_indices, - interfaces: vec![], // same - fields, - methods, - attributes, - inited: false, - object_field_mapping: HashMap::new(), - static_field_mapping: HashMap::new(), - static_data: vec![], - } - } - pub(crate) fn n_object_fields(&self) -> usize { self.object_field_mapping .iter() @@ -179,448 +43,8 @@ impl Class { .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() - } - - // Create a mapping per field(name) to an index in the storage vector that contains the instance data. - // When a field is stored, first the index will be looked up, using the qualified name (from the FieldRef) - // The qualified name is the combination of class name and field name. - // The class name is needed as part of the key to separate class from superclass fields - // (duplicates in the singular field name are allowed). - // This way `this.a` can be differentiated from `super.a`. - // - // this method looks up this and super classes and calls map_fields for each. - pub fn initialize_fields(class: Arc>, super_classes: Vec>>) { - let mut this_field_mapping = HashMap::new(); - let mut static_field_mapping = HashMap::new(); - let mut object_field_map_index: usize = 0; - let mut static_field_map_index: usize = 0; - - Class::add_field_mappings( - &mut this_field_mapping, - &mut static_field_mapping, - class.clone(), - &mut object_field_map_index, - &mut static_field_map_index, - ); - - class.borrow_mut().object_field_mapping = this_field_mapping; - class.borrow_mut().static_field_mapping = static_field_mapping; - - let static_data = Class::set_field_data(class.clone()); - class.borrow_mut().static_data = static_data; - } - - /// for all static and non-static fields on the class compute an index - /// the result of this function is that the class object contains mappings - /// from the field name to the index. This index will be used to store the - /// actual data later in a Vector. - fn add_field_mappings( - this_field_mapping: &mut HashMap>, - static_field_mapping: &mut HashMap>, - class: Arc>, - object_field_map_index: &mut usize, - static_field_map_index: &mut usize, - ) { - let (o, s) = Class::map_fields( - class.clone(), - object_field_map_index, - static_field_map_index, - ); - let borrow = class.borrow(); - let name = &borrow.name; - this_field_mapping.insert(name.to_owned(), o); - static_field_mapping.insert(name.to_owned(), s); - - // // same for super class - // if let Some(super_class) = class.borrow().super_class.as_ref() { - // Class::add_field_mappings( - // this_field_mapping, - // static_field_mapping, - // super_class.clone(), - // object_field_map_index, - // static_field_map_index, - // ); - // } - for c in &class.borrow().super_classes { - Class::add_field_mappings( - this_field_mapping, - static_field_mapping, - c.clone(), - object_field_map_index, - static_field_map_index, - ); - } - } - - // part of the initialize procedure - /// here the actual indices are created - fn map_fields( - class: Arc>, - object_field_map_index: &mut usize, - static_field_map_index: &mut usize, - ) -> ( - HashMap, - HashMap, - ) { - let mut this_fields = HashMap::new(); //fields in class are stored per class and every superclass. - let mut static_fields = HashMap::new(); //fields in class are stored per class and every superclass. - - for (name, field) in &class.borrow().fields { - if field.is(Modifier::Static) { - static_fields.insert( - name.to_owned(), - TypeIndex::new(field.type_of().to_owned(), *static_field_map_index), - ); - *static_field_map_index += 1; - } else { - this_fields.insert( - name.to_owned(), - TypeIndex::new(field.type_of().to_owned(), *object_field_map_index), - ); //name => (type,index) - *object_field_map_index += 1; - } - } - (this_fields, static_fields) - } - - /// the bytecode version - pub fn get_version(&self) -> (u16, u16) { - (self.major_version, self.minor_version) - } - - /// get a method by signature - pub fn get_method(&self, name: &str) -> Option<&Rc> { - self.methods.get(name) - } - - /// get the class name - fn class_name( - super_class_index: u16, - constant_pool: Rc>, - ) -> Option { - if super_class_index == 0 { - None - } else if let CpEntry::ClassRef(name_index) = constant_pool.get(&super_class_index).unwrap() - { - if let CpEntry::Utf8(name) = constant_pool.get(name_index).unwrap() { - Some(name.to_owned()) - } else { - None - } - } else { - None - } - } - - /// creates default values for every field, ie null for objects, 0 for integers etc - /// this is the step before the constructor/static initializer can be called to set hardcoded - /// or computed values. - pub(crate) fn set_field_data(class: Arc>) -> Vec { - let mut field_data = vec![Value::Null; class.borrow().n_static_fields()]; - - for (_, this_class) in &class.borrow().static_field_mapping { - for (_name, type_index) in this_class { - let value = match type_index.type_name.as_str() { - "Z" => Value::BOOL(false), - "B" => Value::I32(0), - "S" => Value::I32(0), - "I" => Value::I32(0), - "J" => Value::I64(0), - "F" => Value::F32(0.0), - "D" => Value::F64(0.0), - _ => Value::Null, - }; - // println!("{} = {:?}", name, value); - field_data[type_index.index] = value.into(); - } - } - - field_data - } - - // convienence methods for data from the constantpool - - pub fn cp_field_ref(&self, index: &u16) -> (&u16, &u16) { - if let CpEntry::Fieldref(class_index, name_and_type_index) = - self.constant_pool.get(index).unwrap() - { - (class_index, name_and_type_index) - } else { - unreachable!("should be field") - } - } - - /// both methodRef and InterfaceMethodRef - /// returns (class_index, name_and_type_index) - pub fn cp_method_ref(&self, index: &u16) -> (&u16, &u16) { - if let CpEntry::MethodRef(class_index, name_and_type_index) - | CpEntry::InterfaceMethodref(class_index, name_and_type_index) = - self.constant_pool.get(index).unwrap() - { - (class_index, name_and_type_index) - } else { - unreachable!("should be method") - } - } - - pub fn cp_class_ref(&self, index: &u16) -> &u16 { - if let CpEntry::ClassRef(name_index) = self.constant_pool.get(index).unwrap() { - name_index - } else { - unreachable!("should be class entry") - } - } - - pub fn cp_utf8(&self, index: &u16) -> &String { - if let CpEntry::Utf8(utf8) = self.constant_pool.get(index).unwrap() { - utf8 - } else { - unreachable!("should be utf8 entry") - } - } - - pub fn cp_name_and_type(&self, index: &u16) -> (&u16, &u16) { - if let CpEntry::NameAndType(name_index, type_index) = self.constant_pool.get(index).unwrap() - { - (name_index, type_index) - } else { - unreachable!("should be name_and_type entry") - } - } } -unsafe impl Send for Class {} - -unsafe impl Sync for Class {} - -pub struct Method { - pub(crate) constant_pool: Rc>, - access_flags: u16, - name_index: u16, - descriptor_index: u16, - pub(crate) attributes: HashMap, -} - -impl fmt::Debug for Method { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Method {{access_flags: {}, name_index: {}, descriptor_index: {}, attributes: {:?} }}", - self.access_flags, self.name_index, self.descriptor_index, self.attributes - ) - } -} - -impl Method { - pub fn new( - constant_pool: Rc>, - access_flags: u16, - name_index: u16, - descriptor_index: u16, - attributes: HashMap, - ) -> Self { - Method { - constant_pool, - access_flags, - name_index, - descriptor_index, - attributes, - } - } - - pub fn name(&self) -> String { - let mut full_name = String::new(); - if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.name_index).unwrap() { - full_name.push_str(s); - } - if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.descriptor_index).unwrap() { - full_name.push_str(s); - } - - full_name - } - - pub fn is(&self, modifier: Modifier) -> bool { - let m = modifier as u16; - (self.access_flags & m) == m - } -} - -pub struct Field { - constant_pool: Rc>, - access_flags: u16, - pub(crate) name_index: u16, - descriptor_index: u16, - attributes: HashMap, - _index: u16, -} - -impl fmt::Debug for Field { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Field {{access_flags: {}, name_index: {}, descriptor_index: {}, attributes: {:?} }}", - self.access_flags, self.name_index, self.descriptor_index, self.attributes - ) - } -} - -impl Field { - pub fn new( - constant_pool: Rc>, - access_flags: u16, - name_index: u16, - descriptor_index: u16, - attributes: HashMap, - field_index: u16, - ) -> Self { - Field { - constant_pool, - access_flags, - name_index, - descriptor_index, - attributes, - _index: field_index, - } - } - - pub fn is(&self, modifier: Modifier) -> bool { - let modifier = modifier as u16; - self.access_flags & modifier == modifier - } - - pub fn name(&self) -> &String { - if let CpEntry::Utf8(utf8) = &self.constant_pool.get(&self.name_index).unwrap() { - return utf8; - } - unreachable!() - } - - pub fn type_of(&self) -> &String { - if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.descriptor_index).unwrap() { - return s; - } - panic!() - } -} - -const _MODIFIERS: [(Modifier, &str); 12] = [ - (Modifier::Public, "public "), - (Modifier::Private, "private "), - (Modifier::Protected, "protected "), - (Modifier::Static, "static "), - (Modifier::Final, "final "), - (Modifier::Synchronized, "synchronized "), - (Modifier::Volatile, "volatile "), - (Modifier::Transient, "transient "), - (Modifier::Native, "native "), - (Modifier::Abstract, "abstract"), - (Modifier::Strict, "strict"), - (Modifier::Synthetic, "synthetic"), -]; - -pub enum Modifier { - Public = 0x0001, - Private = 0x0002, - Protected = 0x0004, - Static = 0x0008, - Final = 0x0010, - Synchronized = 0x0020, - Volatile = 0x0040, - Transient = 0x0080, - Native = 0x0100, - Abstract = 0x0400, - Strict = 0x0800, - Synthetic = 0x1000, -} - -//TODO implement more types -#[derive(Debug)] -pub enum AttributeType { - ConstantValue(u16), - Code(Box), - StackMapTable, - BootstrapMethods, - NestHost, - NestMembers, - PermittedSubclasses, - Exceptions, - InnerClasses, - EnclosingMethod, - Synthetic, - Signature, - Record, - SourceFile, - LineNumberTable, - LocalVariableTable, - LocalVariableTypeTable, - SourceDebugExtension, - Deprecated, - RuntimeVisibleAnnotations, - RuntimeInvisibleAnnotations, - RuntimeVisibleParameterAnnotations, - RuntimeInvisibleParameterAnnotations, - RuntimeVisibleTypeAnnotations, - RuntimeInvisibleTypeAnnotations, - AnnotationDefault, - MethodParameters, - Module, - ModulePackages, - ModuleMainClass, -} - -#[derive(Debug)] -pub struct Exception { - pub start_pc: u16, - pub end_pc: u16, - pub handler_pc: u16, - pub catch_type: u16, -} - -impl Exception { - pub fn read(code: &[u8], index: &mut usize) -> Self { - Self { - start_pc: read_u16(code, index), - end_pc: read_u16(code, index), - handler_pc: read_u16(code, index), - catch_type: read_u16(code, index), - } - } -} - -#[derive(Debug)] -pub struct MethodCode { - _max_stack: u16, - _max_locals: u16, - pub(crate) opcodes: Vec, - _exception_table: Vec, - _code_attributes: HashMap, -} - -impl MethodCode { - pub(crate) fn new( - _max_stack: u16, - _max_locals: u16, - code: Vec, - _exception_table: Vec, - _code_attributes: HashMap, - ) -> Self { - Self { - _max_stack, - _max_locals, - opcodes: code, - _exception_table, - _code_attributes, - } - } -} #[derive(Debug, Clone)] pub enum Value { @@ -636,7 +60,7 @@ pub enum Value { BOOL(bool), CHAR(char), // objects and arrays - Ref(UnsafeRef), + Ref(ObjectRef), // special object Utf8(String), } @@ -651,7 +75,7 @@ impl Value { } } - pub fn into_object(self) -> UnsafeRef { + pub fn into_object(self) -> ObjectRef { if let Value::Ref(v) = self { v } else { @@ -660,22 +84,145 @@ impl Value { } } -pub type UnsafeRef = Arc>; - -pub fn unsafe_ref(object: ObjectRef) -> UnsafeRef { - return Arc::new(UnsafeCell::new(object)); +#[derive(Debug, Clone)] +pub enum ObjectRef { + ByteArray(Vec), + ShortArray(Vec), + IntArray(Vec), + LongArray(Vec), + FloatArray(Vec), + DoubleArray(Vec), + BooleanArray(Vec), + CharArray(Vec), + StringArray(Vec), + ObjectArray(ClassId, Vec), + Object(Object), + //Box necessary?? + Class(Class), } -// pub fn unsafe_val(val: Value) -> UnsafeValue { -// return Arc::new(UnsafeCell::new(val)); +impl ObjectRef { + pub fn get_array_length(&self) -> usize { + match self { + ByteArray(d) => d.len(), + ShortArray(d) => d.len(), + IntArray(d) => d.len(), + LongArray(d) => d.len(), + FloatArray(d) => d.len(), + DoubleArray(d) => d.len(), + BooleanArray(d) => d.len(), + CharArray(d) => d.len(), + StringArray(d) => d.len(), + ObjectArray(_, d) => d.len(), + _ => unreachable!("not an array") + } + } +} + +impl ObjectRef { + pub fn new_object_array(class: &Class, size: usize) -> Self { + ObjectArray(class.id, Vec::with_capacity(size)) + } + + pub fn new_int_array(size: usize) -> Self { + IntArray(Vec::with_capacity(size)) + } + + pub fn new_byte_array(d: Vec) -> Self { + ByteArray(into_vec_i8(d)) + } +} + +fn into_vec_i8(v: Vec) -> Vec { + let mut v = std::mem::ManuallyDrop::new(v); + + // then, pick apart the existing Vec + let p = v.as_mut_ptr(); + let len = v.len(); + let cap = v.capacity(); + + // finally, adopt the data into a new Vec + unsafe { Vec::from_raw_parts(p as *mut i8, len, cap) } +} + +#[derive(Debug, Clone)] +pub struct Object { + // locked: bool, + // hashcode: i32, + pub class_id: ClassId, + pub data: Vec, +} //arrays + +// object, not array +impl Object { + pub fn new(class: &Class) -> Self { + let instance_data = Object::init_fields(class); + Self { + class_id: class.id, + data: instance_data, + } + } + + // initializes all non-static fields to their default values + pub(crate) fn init_fields(class: &Class) -> Vec { + let mut field_data = Vec::with_capacity(class.n_object_fields()); + + for (_, fields) in &class.object_field_mapping { + for (_, type_index) in fields { + let value = match type_index.type_name.as_str() { + "Z" => Value::BOOL(false), + "B" => Value::I32(0), + "S" => Value::I32(0), + "I" => Value::I32(0), + "J" => Value::I64(0), + "F" => Value::F32(0.0), + "D" => Value::F64(0.0), + _ => Value::Null, + }; + field_data.push(value.into()); + } + } + + field_data + } + + pub fn set(&mut self, class: &Class, declared_type: &str, field_name: &str, value: Value) { + let type_index = class + .object_field_mapping + .get(declared_type) + .unwrap() + .get(field_name) + .unwrap(); + self.data[type_index.index] = value; + } + + pub fn get(&mut self, instancedef: &Class, declared_type: &String, field_name: &String) -> &Value { + let type_index = instancedef + .object_field_mapping + .get(declared_type) + .unwrap() + .get(field_name) + .unwrap(); + &self.data[type_index.index] + } + + // fn get_field_name(&self, cp_index: &u16) -> &str { + // if let CpEntry::Utf8(name) = self.class.constant_pool.get(cp_index).unwrap() { + // return name; + // } + // panic!() + // } +} + +// impl Debug for Object { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// // let fields: Vec = self.data.unwrap().iter().map(|(k)| { +// // // let mut r: String = self.get_field_name(k).into(); +// // // r.push(':'); +// // // r.push_str(format!("{:?}").as_str()); +// // // r +// // } +// // ).collect(); +// write!(f, "{}", self.class.name) +// } // } - -pub fn type_ref(class: Class) -> Type { - return Arc::new(RefCell::new(class)); -} - -pub type Type = Arc>; - -unsafe impl Send for Value {} - -unsafe impl Sync for Value {} diff --git a/src/classloader/classdef.rs b/src/classloader/classdef.rs new file mode 100644 index 0000000..f2bd4c9 --- /dev/null +++ b/src/classloader/classdef.rs @@ -0,0 +1,367 @@ +use std::collections::HashMap; +use std::fmt; +use std::fmt::{Debug, Formatter}; +use std::rc::Rc; + +use crate::classloader::io::read_u16; + +/// This is the class representation when the bytecode had just been loaded. + +pub struct ClassDef { + pub minor_version: u16, + pub major_version: u16, + pub constant_pool: Rc>, + pub access_flags: u16, + this_class: u16, + pub super_class: Option, + pub interfaces: Vec, + pub fields: HashMap, + pub methods: HashMap, + pub attributes: HashMap, +} + +impl Debug for ClassDef{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.cp_class_name(&self.this_class)) + } +} + +impl ClassDef { + pub fn new( + minor_version: u16, + major_version: u16, + constant_pool: Rc>, + access_flags: u16, + this_class: u16, + super_class: Option, + interfaces: Vec, + fields: HashMap, + methods: HashMap, + attributes: HashMap, + ) -> Self { + Self { + major_version, + minor_version, + constant_pool, + access_flags, + this_class, + super_class, + interfaces, + fields, + methods, + attributes, + } + } + /// the bytecode version + pub fn version(&self) -> (u16, u16) { + (self.major_version, self.minor_version) + } + + /// get the class name + pub fn name(&self) -> &str { + self.cp_class_name(&self.this_class) + } + + pub fn get_method(&self, name: &str) -> Option<&Method> { + self.methods.get(name) + } + + pub fn cp_field_ref(&self, index: &u16) -> (&u16, &u16) { + if let CpEntry::Fieldref(class_index, name_and_type_index) = + self.constant_pool.get(index).unwrap() + { + (class_index, name_and_type_index) + } else { + unreachable!("should be field") + } + } + + /// both methodRef and InterfaceMethodRef + /// returns (class_index, name_and_type_index) + pub fn cp_method_ref(&self, index: &u16) -> (&u16, &u16) { + if let CpEntry::MethodRef(class_index, name_and_type_index) + | CpEntry::InterfaceMethodref(class_index, name_and_type_index) = + self.constant_pool.get(index).unwrap() + { + (class_index, name_and_type_index) + } else { + unreachable!("should be method") + } + } + + pub fn cp_class_name(&self, index: &u16) -> &String { + let cr = self.cp_class_ref(index); + self.cp_utf8(cr) + } + + pub fn cp_class_ref(&self, index: &u16) -> &u16 { + if let CpEntry::ClassRef(name_index) = self.constant_pool.get(index).unwrap() { + name_index + } else { + unreachable!("should be class entry") + } + } + + pub fn cp_utf8(&self, index: &u16) -> &String { + if let CpEntry::Utf8(utf8) = self.constant_pool.get(index).unwrap() { + utf8 + } else { + unreachable!("should be utf8 entry") + } + } + + pub fn cp_name_and_type(&self, index: &u16) -> (&u16, &u16) { + if let CpEntry::NameAndType(name_index, type_index) = self.constant_pool.get(index).unwrap() + { + (name_index, type_index) + } else { + unreachable!("should be name_and_type entry") + } + } +} + +#[derive(Debug)] +pub enum CpEntry { + Utf8(String), + Integer(i32), + Float(f32), + Long(i64), + Double(f64), + ClassRef(u16), + // (utf8) + StringRef(u16), + // (utf8) + Fieldref(u16, u16), + // (class, name_and_type) + MethodRef(u16, u16), + // (class, name_and_type) + InterfaceMethodref(u16, u16), + // (class, name_and_type) + NameAndType(u16, u16), + // (name, descriptor) + MethodHandle(u8, u16), + MethodType(u16), + InvokeDynamic(u16, u16), +} + +pub enum Modifier { + Public = 0x0001, + Private = 0x0002, + Protected = 0x0004, + Static = 0x0008, + Final = 0x0010, + Synchronized = 0x0020, + Volatile = 0x0040, + Transient = 0x0080, + Native = 0x0100, + Abstract = 0x0400, + Strict = 0x0800, + Synthetic = 0x1000, +} + +//TODO implement more types +#[derive(Debug)] +pub enum AttributeType { + ConstantValue(u16), + Code(Box), + StackMapTable, + BootstrapMethods, + NestHost, + NestMembers, + PermittedSubclasses, + Exceptions, + InnerClasses, + EnclosingMethod, + Synthetic, + Signature, + Record, + SourceFile, + LineNumberTable, + LocalVariableTable, + LocalVariableTypeTable, + SourceDebugExtension, + Deprecated, + RuntimeVisibleAnnotations, + RuntimeInvisibleAnnotations, + RuntimeVisibleParameterAnnotations, + RuntimeInvisibleParameterAnnotations, + RuntimeVisibleTypeAnnotations, + RuntimeInvisibleTypeAnnotations, + AnnotationDefault, + MethodParameters, + Module, + ModulePackages, + ModuleMainClass, +} + +#[derive(Debug)] +pub struct Exception { + pub start_pc: u16, + pub end_pc: u16, + pub handler_pc: u16, + pub catch_type: u16, +} + +impl Exception { + pub fn read(code: &[u8], index: &mut usize) -> Self { + Self { + start_pc: read_u16(code, index), + end_pc: read_u16(code, index), + handler_pc: read_u16(code, index), + catch_type: read_u16(code, index), + } + } +} + +#[derive(Debug)] +pub struct MethodCode { + _max_stack: u16, + _max_locals: u16, + pub(crate) opcodes: Vec, + _exception_table: Vec, + _code_attributes: HashMap, +} + +impl MethodCode { + pub(crate) fn new( + _max_stack: u16, + _max_locals: u16, + code: Vec, + _exception_table: Vec, + _code_attributes: HashMap, + ) -> Self { + Self { + _max_stack, + _max_locals, + opcodes: code, + _exception_table, + _code_attributes, + } + } +} + +pub(crate) const _MODIFIERS: [(Modifier, &str); 12] = [ + (Modifier::Public, "public "), + (Modifier::Private, "private "), + (Modifier::Protected, "protected "), + (Modifier::Static, "static "), + (Modifier::Final, "final "), + (Modifier::Synchronized, "synchronized "), + (Modifier::Volatile, "volatile "), + (Modifier::Transient, "transient "), + (Modifier::Native, "native "), + (Modifier::Abstract, "abstract"), + (Modifier::Strict, "strict"), + (Modifier::Synthetic, "synthetic"), +]; + +pub struct Field { + constant_pool: Rc>, + access_flags: u16, + pub(crate) name_index: u16, + descriptor_index: u16, + attributes: HashMap, + _index: u16, +} + +impl fmt::Debug for Field { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Field {{access_flags: {}, name_index: {}, descriptor_index: {}, attributes: {:?} }}", + self.access_flags, self.name_index, self.descriptor_index, self.attributes + ) + } +} + +impl Field { + pub fn new( + constant_pool: Rc>, + access_flags: u16, + name_index: u16, + descriptor_index: u16, + attributes: HashMap, + field_index: u16, + ) -> Self { + Field { + constant_pool, + access_flags, + name_index, + descriptor_index, + attributes, + _index: field_index, + } + } + + pub fn is(&self, modifier: Modifier) -> bool { + let modifier = modifier as u16; + self.access_flags & modifier == modifier + } + + pub fn name(&self) -> &String { + if let CpEntry::Utf8(utf8) = &self.constant_pool.get(&self.name_index).unwrap() { + return utf8; + } + unreachable!() + } + + pub fn type_of(&self) -> &String { + if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.descriptor_index).unwrap() { + return s; + } + panic!() + } +} + +pub struct Method { + pub(crate) constant_pool: Rc>, + access_flags: u16, + name_index: u16, + descriptor_index: u16, + pub(crate) attributes: HashMap, +} + +impl fmt::Debug for Method { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Method {{access_flags: {}, name_index: {}, descriptor_index: {}, attributes: {:?} }}", + self.access_flags, self.name_index, self.descriptor_index, self.attributes + ) + } +} + +impl Method { + pub fn new( + constant_pool: Rc>, + access_flags: u16, + name_index: u16, + descriptor_index: u16, + attributes: HashMap, + ) -> Self { + Method { + constant_pool, + access_flags, + name_index, + descriptor_index, + attributes, + } + } + + pub fn name(&self) -> String { + let mut full_name = String::new(); + if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.name_index).unwrap() { + full_name.push_str(s); + } + if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.descriptor_index).unwrap() { + full_name.push_str(s); + } + + full_name + } + + pub fn is(&self, modifier: Modifier) -> bool { + let m = modifier as u16; + (self.access_flags & m) == m + } +} diff --git a/src/io.rs b/src/classloader/io.rs similarity index 79% rename from src/io.rs rename to src/classloader/io.rs index 0208b6c..1eee757 100644 --- a/src/io.rs +++ b/src/classloader/io.rs @@ -1,6 +1,12 @@ +use std::fs::{self}; + use anyhow::{anyhow, Error}; -use std::fs::{self, File}; -use std::io::Read; + +#[cfg(target_family = "unix")] +pub const PATH_SEPARATOR: char = ':'; + +#[cfg(target_family = "windows")] +pub const PATH_SEPARATOR: char = ';'; /// resolves the actual path where the class file is found /// for std lib there is a special case that resolves to the jmod @@ -38,25 +44,7 @@ pub fn find_class(classpath: &Vec, class_name: &str) -> Result Result, Error> { - let mut buffer; - if name.contains('#') { - let parts: Vec<&str> = name.split('#').collect(); - let archive_file = File::open(parts[0])?; - let mut archive_zip = zip::ZipArchive::new(archive_file)?; - let mut entry = archive_zip.by_name(parts[1])?; - buffer = vec![0; entry.size() as usize]; - entry.read_exact(&mut buffer)?; - } else { - let mut f = File::open(&name)?; - let metadata = fs::metadata(&name)?; - buffer = vec![0; metadata.len() as usize]; - f.read_exact(&mut buffer)?; - } - Ok(buffer) -} + // methods to read values from big-endian binary data diff --git a/src/classloader.rs b/src/classloader/mod.rs similarity index 85% rename from src/classloader.rs rename to src/classloader/mod.rs index 19de269..17083de 100644 --- a/src/classloader.rs +++ b/src/classloader/mod.rs @@ -1,11 +1,46 @@ -use crate::class::{AttributeType, Class, Exception, Field, Method, MethodCode}; -use crate::io::{read_bytes, read_f32, read_f64, read_i32, read_i64, read_u16, read_u32, read_u8}; -use anyhow::Error; use std::collections::HashMap; +use std::fs; +use std::fs::File; +use std::io::Read; use std::rc::Rc; +use anyhow::Error; + +use crate::classloader::io::{find_class, read_bytes, read_f32, read_f64, read_i32, read_i64, read_u16, read_u32, read_u8}; +use crate::classloader::classdef::{AttributeType, ClassDef, CpEntry, Exception, Field, Method, MethodCode}; + +pub(crate) mod classdef; +pub(crate) mod io; + +pub(crate) fn get_classdef(classpath: &Vec, class_name: &str) -> Result { + println!("read class {} ", class_name); + let resolved_path = find_class(classpath, class_name)?; + let bytecode = read_bytecode(resolved_path)?; + load_class(bytecode) +} + +/// reads the binary class file from file path or archive +/// and returns the byte array as Vec +fn read_bytecode(name: String) -> Result, Error> { + let mut buffer; + if name.contains('#') { + let parts: Vec<&str> = name.split('#').collect(); + let archive_file = File::open(parts[0])?; + let mut archive_zip = zip::ZipArchive::new(archive_file)?; + let mut entry = archive_zip.by_name(parts[1])?; + buffer = vec![0; entry.size() as usize]; + entry.read_exact(&mut buffer)?; + } else { + let mut f = File::open(&name)?; + let metadata = fs::metadata(&name)?; + buffer = vec![0; metadata.len() as usize]; + f.read_exact(&mut buffer)?; + } + Ok(buffer) +} + // The native classoader -pub fn load_class(bytecode: Vec) -> Result { +fn load_class(bytecode: Vec) -> Result { let pos = &mut 0; check_magic(&bytecode, pos); let minor_version = read_u16(&bytecode, pos); @@ -22,13 +57,11 @@ pub fn load_class(bytecode: Vec) -> Result { ); cp_index += 1; } - let constant_pool = Rc::new(constant_pool); - let access_flags = read_u16(&bytecode, pos); let this_class = read_u16(&bytecode, pos); let super_class = read_u16(&bytecode, pos); - + let super_class = if super_class != 0 { Some(super_class) } else { None }; let interfaces_count = read_u16(&bytecode, pos); let mut interfaces = vec![]; for _ in 0..interfaces_count { @@ -46,7 +79,7 @@ pub fn load_class(bytecode: Vec) -> Result { let mut methods = HashMap::new(); for _ in 0..methods_count { let m = read_method(constant_pool.clone(), pos, &bytecode); - methods.insert(m.name(), Rc::new(m)); + methods.insert(m.name(), m); } let attributes_count = read_u16(&bytecode, pos); @@ -60,7 +93,7 @@ pub fn load_class(bytecode: Vec) -> Result { } } - Ok(Class::new( + Ok(ClassDef::new( minor_version, major_version, constant_pool, @@ -224,7 +257,6 @@ fn read_attribute( *index += attribute_length; if let CpEntry::Utf8(s) = &constant_pool.get(&attribute_name_index).unwrap() { - // println!("Att [{}]", s); return match s.as_str() { "ConstantValue" => { assert_eq!(info.len(), 2); @@ -274,6 +306,7 @@ fn read_attribute( "Signature" => Some(("".into(), AttributeType::Signature)), //stub "NestHost" => Some(("".into(), AttributeType::NestHost)), //stub "EnclosingMethod" => Some(("".into(), AttributeType::EnclosingMethod)), //stub + "PermittedSubclasses" => Some(("".into(), AttributeType::PermittedSubclasses)), //stub //TODO more actual attribute implementations _ => None, }; @@ -281,20 +314,3 @@ fn read_attribute( None } -#[derive(Debug)] -pub enum CpEntry { - Utf8(String), - Integer(i32), - Float(f32), - Long(i64), - Double(f64), - ClassRef(u16), // (utf8) - StringRef(u16), // (utf8) - Fieldref(u16, u16), // (class, name_and_type) - MethodRef(u16, u16), // (class, name_and_type) - InterfaceMethodref(u16, u16), // (class, name_and_type) - NameAndType(u16, u16), // (name, descriptor) - MethodHandle(u8, u16), - MethodType(u16), - InvokeDynamic(u16, u16), -} diff --git a/src/classmanager.rs b/src/classmanager.rs new file mode 100644 index 0000000..378bc1d --- /dev/null +++ b/src/classmanager.rs @@ -0,0 +1,319 @@ +use std::collections::{HashMap, LinkedList}; +use once_cell::sync::Lazy; + +use crate::class::{Class, ClassId, ObjectRef, TypeIndex, Value::*, Value}; +use crate::class::Object; +use crate::classloader; +use crate::classloader::classdef::{ClassDef, Modifier}; +use crate::classloader::io::PATH_SEPARATOR; +use crate::vm::Vm; + +static mut CLASSMANAGER: Lazy = Lazy::new(|| ClassManager::new()); + +pub fn init() { + unsafe { + CLASSMANAGER.classes.clear(); + CLASSMANAGER.names.clear(); + CLASSMANAGER.classdefs.clear(); + CLASSMANAGER.class_objects.clear(); + CLASSMANAGER.static_class_data.clear(); + } +} + +pub fn set_classpath(classpath: &str) { + unsafe { + CLASSMANAGER.set_classpath(classpath); + } +} + +pub fn get_class_by_id(id: ClassId) -> Option<&'static Class> { + unsafe { + CLASSMANAGER.get_class_by_id(id) + } +} + +pub fn classdef_name(id: &ClassId) -> Option { + unsafe { + CLASSMANAGER.classdef_name(id) + } +} + +pub fn get_classid(name: &str) -> &ClassId { + unsafe { + CLASSMANAGER.get_classid(name) + } +} + +pub fn get_classdef(id: &ClassId) -> &ClassDef { + unsafe { + CLASSMANAGER.get_classdef(id) + } +} + +pub fn load_class_by_name(name: &str) { + unsafe { + CLASSMANAGER.load_class_by_name(name) + } +} + +pub fn get_class_by_name(name: &str) -> Option<&Class> { + unsafe { + CLASSMANAGER.get_class_by_name(name) + } +} + +pub fn add_class(name: &str) -> ClassId { + unsafe { + CLASSMANAGER.add_class(name) + } +} + +pub fn get_static(id: &ClassId, index: usize) -> Value { + unsafe { + CLASSMANAGER.static_class_data.get(id).unwrap()[index].clone() + } +} + +pub fn set_static(id: &ClassId, index: usize, value: Value) { + unsafe { + CLASSMANAGER.static_class_data.get_mut(id).unwrap()[index] = value; + } +} + +pub fn get_classobject(id: &ClassId) -> Option<&Value> { + unsafe { + CLASSMANAGER.class_objects.get(id) + } +} + +//TODO less pubs +pub struct ClassManager { + static_class_data: HashMap>, + // sequence for passing new classIds + current_id: ClassId, + // the classpath + classpath: Vec, + + //references to classdefs, ie the static class info + pub classdefs: HashMap, + + // references to the runtime class + pub classes: HashMap, + + pub names: HashMap, + pub class_objects: HashMap, + vm: Vm, +} + +impl ClassManager { + pub fn new() -> Self { + Self { + static_class_data: HashMap::new(), + current_id: 0, + classdefs: HashMap::new(), + classes: HashMap::new(), + class_objects: HashMap::new(), + names: HashMap::new(), + classpath: vec![], + vm:Vm::new_internal(), + } + } + + fn set_classpath(&mut self, classpath: &str) { + self.classpath = classpath + .split(PATH_SEPARATOR) + .map(|s| s.into()) + .collect(); + } + + fn get_class_by_id(&mut self, id: ClassId) -> Option<&Class> { + if !self.classes.contains_key(&id) { + let name = self.classdef_name(&id); + if name.is_some() { + self.add_class(&name.unwrap()); + } + } + self.classes.get(&id) + } + + fn classdef_name(&self, id: &ClassId) -> Option { + self.classdefs.get(id).map(|c| c.name().to_owned()) //drops borrow to self here + } + + fn get_classid(&self, name: &str) -> &ClassId { + self.names.get(name).unwrap() + } + + fn get_classdef(&self, id: &ClassId) -> &ClassDef { + self.classdefs.get(&id).unwrap() + } + + fn load_class_by_name(&mut self, name: &str) { + let id = self.names.get(name); + match id { + Some(id) => if self.classes.get(id).is_none() { + self.add_class(name); + } + None => { self.add_class(name); } + } + } + + fn get_class_by_name(&self, name: &str) -> Option<&Class> { + let id = self.names.get(name); + self.classes.get(id.unwrap()) + } + + fn add_class(&mut self, name: &str) -> ClassId { + let this_classid = self.load(name); + let this_classdef = self.classdefs.get(&this_classid).unwrap(); + + //compute indices to fields + let mut object_field_mapping = HashMap::new(); + let mut static_field_mapping = HashMap::new(); + let object_field_map_index: &mut usize = &mut 0; + let static_field_map_index: &mut usize = &mut 0; + + let mut current_id = Some(this_classid); + let mut current_classdef; + let mut parents = LinkedList::new(); + while let Some(c) = current_id { + parents.push_front(current_id.unwrap()); + current_classdef = self.classdefs.get(&c).unwrap(); + Self::add_fields_for_this_or_parents(&mut object_field_mapping, &mut static_field_mapping, object_field_map_index, static_field_map_index, current_classdef); + + current_id = current_classdef.super_class.as_ref() + .map(|i| current_classdef.cp_class_name(i).to_owned()) + .map(|n| *self.names.get(&n).unwrap()); + } + + //handrolled references to superclass and interfaces + let superclass_id = this_classdef.super_class.as_ref() + .map(|i| this_classdef.cp_class_name(i).to_owned()) + .map(|n| *self.names.get(&n).unwrap()); + + let interface_ids: Vec = this_classdef.interfaces.iter() + .map(|i| this_classdef.cp_class_name(i).to_owned()) + .map(|n| *self.names.get(n.as_str()).unwrap()) + .collect(); + + self.static_class_data.insert(this_classid, Self::set_field_data(&static_field_mapping)); + + self.names.get(name) + .and_then(|id| + self.classes.insert(*id, Class { + id: *id, + initialized: false, + name: name.into(), + superclass: superclass_id, + parents, + interfaces: interface_ids, + object_field_mapping, + static_field_mapping, + // static_field_data: static_values, + })); + if name != "java/lang/Class" { + let cls = self.get_class_by_name("java/lang/Class").unwrap(); + let mut instance = Object::new(cls); + instance.set(cls, "java/lang/Class", "name", Value::Utf8(name.into())); + let instance = Ref(ObjectRef::Object(instance)); + + self.class_objects.insert(this_classid, instance); + } + let clinit = this_classdef.methods.contains_key("()V"); + + if clinit { + self.vm.execute_special(&mut vec![],name, "()V", vec![]).unwrap(); + } + + this_classid + } + + fn add_fields_for_this_or_parents(object_field_mapping: &mut HashMap>, + static_field_mapping: &mut HashMap>, + object_field_map_index: &mut usize, static_field_map_index: + &mut usize, + current_classdef: &ClassDef) { + let mut instance_field_mappings: HashMap = HashMap::new(); + let mut static_field_mappings: HashMap = HashMap::new(); + for (field_name, field) in ¤t_classdef.fields { + if !field.is(Modifier::Static) { + instance_field_mappings.insert(field_name.to_owned(), + TypeIndex::new(field.type_of().to_owned(), *object_field_map_index)); + *object_field_map_index += 1; + } else { + static_field_mappings.insert(field_name.to_owned(), + TypeIndex::new(field.type_of().to_owned(), *static_field_map_index)); + *static_field_map_index += 1; + } + } + object_field_mapping.insert(current_classdef.name().to_owned(), instance_field_mappings); + static_field_mapping.insert(current_classdef.name().to_owned(), static_field_mappings); + } + + /// loads the class and recursively its dependencies + fn load(&mut self, name: &str) -> ClassId { + let (id, mut classes_to_load) = self.load_class_and_deps(name); + while !classes_to_load.is_empty() { + if let Some(classname) = classes_to_load.pop() { + classes_to_load.append(&mut self.load_class_and_deps(classname.as_str()).1); + } + } + id + } + + /// loads the class and returns it's dependencies + fn load_class_and_deps(&mut self, name: &str) -> (ClassId, Vec) { + let id = *self.names.entry(name.to_string()).or_insert_with(|| { + self.current_id += 1; + self.current_id + }); + + let classdef = self.classdefs + .entry(id) + .or_insert_with(|| classloader::get_classdef(&self.classpath, name).expect("ClassNotFound")); + (self.current_id, inspect_dependencies(classdef)) + } + + pub(crate) fn set_field_data(field_mapping: &HashMap>) -> Vec { + let mut field_data = vec![Null; n_fields(field_mapping)]; + + for (_, this_class) in field_mapping { + for (_name, type_index) in this_class { + let value = match type_index.type_name.as_str() { + "Z" => BOOL(false), + "B" => I32(0), + "S" => I32(0), + "I" => I32(0), + "J" => I64(0), + "F" => F32(0.0), + "D" => F64(0.0), + _ => Null, + }; + // println!("{} = {:?}", name, value); + field_data[type_index.index] = value.into(); + } + } + + field_data + } +} + +pub(crate) fn n_fields(field_mapping: &HashMap>) -> usize { + field_mapping + .iter() + .map(|(_, v)| v.len()) + .reduce(|acc, e| acc + e) + .unwrap() +} + +pub(crate) fn inspect_dependencies(classdef: &ClassDef) -> Vec { + let mut classes_to_load: Vec = vec![]; + + if let Some(superclass) = &classdef.super_class { + classes_to_load.push(classdef.cp_class_name(superclass).into()); + } + for interface in &classdef.interfaces { + classes_to_load.push(classdef.cp_class_name(interface).into()); + } + classes_to_load +} \ No newline at end of file diff --git a/src/heap.rs b/src/heap.rs index 797d1f0..e69de29 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -1,190 +0,0 @@ -use std::cell::{RefCell, UnsafeCell}; -use std::fmt; -use std::fmt::{Debug, Formatter}; -use std::sync::Arc; -use ObjectRef::{BooleanArray, CharArray, DoubleArray, FloatArray, LongArray, ShortArray}; - -use crate::class::{Class, Type, Value}; -use crate::heap::ObjectRef::{ByteArray, IntArray, ObjectArray, StringArray}; - -// can contain object or array -pub enum ObjectRef { - ByteArray(Vec), - ShortArray(Vec), - IntArray(Vec), - LongArray(Vec), - FloatArray(Vec), - DoubleArray(Vec), - BooleanArray(Vec), - CharArray(Vec), - StringArray(Vec), - ObjectArray(Type, Vec>>), - Object(Box),//Box necessary?? - Class(Arc>), -} - -impl ObjectRef { - pub fn get_array_length(&self) -> usize { - match self { - ByteArray(d) => d.len(), - ShortArray(d) => d.len(), - IntArray(d) => d.len(), - LongArray(d) => d.len(), - FloatArray(d) => d.len(), - DoubleArray(d) => d.len(), - BooleanArray(d) => d.len(), - CharArray(d) => d.len(), - StringArray(d) => d.len(), - ObjectArray(_, d) => d.len(), - _ => unreachable!("not an array") - } - } -} - -fn into_vec_i8(v: Vec) -> Vec { - let mut v = std::mem::ManuallyDrop::new(v); - - // then, pick apart the existing Vec - let p = v.as_mut_ptr(); - let len = v.len(); - let cap = v.capacity(); - - // finally, adopt the data into a new Vec - unsafe { Vec::from_raw_parts(p as *mut i8, len, cap) } -} - -impl ObjectRef { - pub fn new_object_array(class: Type, size: usize) -> Self { - ObjectArray(class, Vec::with_capacity(size)) - } - - pub fn new_int_array(size: usize) -> Self { - IntArray(Vec::with_capacity(size)) - } - - pub fn new_byte_array(d: Vec) -> Arc> { - Arc::new(UnsafeCell::new(ByteArray(into_vec_i8(d)))) - } -} - -impl Debug for ObjectRef { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - BooleanArray(d) => write!(f, "[Z;{}]", d.len()), - ByteArray(d) => write!(f, "[B;{}]", d.len()), - CharArray(d) => write!(f, "[C;{}]", d.len()), - DoubleArray(d) => write!(f, "[D;{}]", d.len()), - FloatArray(d) => write!(f, "[F;{}]", d.len()), - IntArray(d) => write!(f, "[I;{}]", d.len()), - LongArray(d) => write!(f, "[J;{}]", d.len()), - ObjectArray(t, d) => write!(f, "[L{};{}]", t.borrow().name, d.len()), - ShortArray(d) => write!(f, "[S;{}]", d.len()), - StringArray(d) => write!(f, "[S;{}]", d.len()), - ObjectRef::Object(r) => write!(f, "{}{{ {:?} }}", r.class.borrow().name, r.data), - ObjectRef::Class(s) => write!(f, "Class {:?}", s.borrow().name), - } - } -} - -// trying to implement efficient object instance storage -pub struct Object { - // locked: bool, - // hashcode: i32, - pub class: Arc>, - pub data: Vec, -} //arrays - -unsafe impl Send for Object {} - -unsafe impl Sync for Object {} - -// object, not array -impl Object { - pub fn new(class: Arc>) -> Self { - let instance_data = Object::init_fields(class.clone()); - Self { - class, - data: instance_data, - } - } - - // initializes all non-static fields to their default values - pub(crate) fn init_fields(class: Arc>) -> Vec { - let mut field_data = Vec::with_capacity(class.borrow().n_object_fields()); - - for (_, fields) in &class.borrow().object_field_mapping { - for (_, type_index) in fields { - let value = match type_index.type_name.as_str() { - "Z" => Value::BOOL(false), - "B" => Value::I32(0), - "S" => Value::I32(0), - "I" => Value::I32(0), - "J" => Value::I64(0), - "F" => Value::F32(0.0), - "D" => Value::F64(0.0), - _ => Value::Null, - }; - field_data.push(value.into()); - } - } - - field_data - } - - pub fn set(&mut self, class_name: &String, field_name: &String, value: Value) { - let borrow = self.class.borrow(); - let type_index = borrow - .object_field_mapping - .get(class_name) - .unwrap() - .get(field_name) - .unwrap(); - self.data[type_index.index] = value; - } - - pub fn get(&mut self, class_name: &String, field_name: &String) -> &Value { - let borrow = self.class.borrow(); - let type_index = borrow - .object_field_mapping - .get(class_name) - .unwrap() - .get(field_name) - .unwrap(); - &self.data[type_index.index] - } - - // fn get_field_name(&self, cp_index: &u16) -> &str { - // if let CpEntry::Utf8(name) = self.class.constant_pool.get(cp_index).unwrap() { - // return name; - // } - // panic!() - // } -} - -impl fmt::Debug for Object { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // let fields: Vec = self.data.unwrap().iter().map(|(k)| { - // // let mut r: String = self.get_field_name(k).into(); - // // r.push(':'); - // // r.push_str(format!("{:?}").as_str()); - // // r - // } - // ).collect(); - write!(f, "{}", self.class.borrow().name) - } -} - -// will using Arc's enable a GC-less heap???? -pub(crate) struct Heap { - objects: Vec>>, -} - -impl Heap { - pub fn new() -> Self { - Self { objects: vec![] } - } - - pub(crate) fn new_object(&mut self, object: Arc>) { - self.objects.push(object); - } -} diff --git a/src/lib.rs b/src/lib.rs index 56b7999..42a3200 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,5 @@ +mod classloader; +pub mod classmanager; pub mod class; -pub mod classloader; -pub mod heap; -pub mod io; -pub mod opcodes; pub mod vm; - -pub mod native; +pub mod heap; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 166bd34..6b310ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,11 @@ -use std::io::Error; +use java_rs::classmanager::set_classpath; use java_rs::vm::Vm; - - -fn main() -> Result<(), Error> { - // TODO cmdline args - // TODO build index for package -> jarfile? - - let mut vm = Vm::new("tests"); - // let main_class = "Inheritance"; +fn main() { + let mut stackframes = Vec::new(); + let mut vm = Vm::new(&mut stackframes); + set_classpath("/Users/Shautvast/dev/java/tests"); let main_class = "testclasses.Main"; - - vm.execute_static( main_class, "main([Ljava/lang/String;)V", vec![]) + vm.execute_static( &mut stackframes, main_class, "main([Ljava/lang/String;)V", vec![]) .unwrap(); - Ok(()) } diff --git a/src/vm/array.rs b/src/vm/array.rs index b156748..8ce814d 100644 --- a/src/vm/array.rs +++ b/src/vm/array.rs @@ -1,16 +1,17 @@ use anyhow::{anyhow, Error}; -use crate::class::Value::{self,*}; -use crate::heap::ObjectRef; -pub(crate) unsafe fn array_load(index: Value, arrayref: Value) -> Result { - if let I32(index) = &index { - let index = *index as usize; +use crate::class::ObjectRef; +use crate::class::Value::{self, *}; + +pub(crate) fn array_load(index: Value, arrayref: Value) -> Result { + if let I32(index) = index { + let index = index as usize; if let Null = arrayref { return Err(anyhow!("NullpointerException")); } if let Ref(objectref) = arrayref { - match &*objectref.get() { + match objectref { ObjectRef::ByteArray(array) => { return Ok(I32(array[index] as i32)); } @@ -53,14 +54,14 @@ pub(crate) unsafe fn array_load(index: Value, arrayref: Value) -> Result Result<(), Error> { - if let Null = &*arrayref { +pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result<(), Error> { + if let Null = arrayref { return Err(anyhow!("NullpointerException")); } if let I32(index) = index { - if let Ref(ref mut objectref) = arrayref { - match &mut *objectref.get() { + if let Ref(mut objectref) = arrayref { + match objectref { ObjectRef::ByteArray(ref mut array) => { if let I32(value) = value { // is i32 correct? @@ -91,7 +92,7 @@ pub(crate) unsafe fn array_store(value: Value, index: Value, arrayref: &mut Valu unreachable!() } } - ObjectRef::CharArray(ref mut array) => { + ObjectRef::CharArray(ref mut array) => unsafe{ if let I32(value) = value { array[index as usize] = char::from_u32_unchecked(value as u32); } else { diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 1de1426..af09934 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -2,4 +2,6 @@ mod vm; pub use vm::Vm; mod operations; mod stack; -mod array; \ No newline at end of file +mod array; +mod opcodes; +mod native; \ No newline at end of file diff --git a/src/native.rs b/src/vm/native.rs similarity index 75% rename from src/native.rs rename to src/vm/native.rs index 2153d80..68eb474 100644 --- a/src/native.rs +++ b/src/vm/native.rs @@ -1,52 +1,52 @@ #![allow(non_snake_case)] -use std::ptr::hash; use anyhow::Error; -use log::{debug, info}; +use log::{info}; use once_cell::sync::Lazy; -use crate::class::{get_class, unsafe_ref, Value}; +use crate::class::{ObjectRef, Value}; +use crate::class::ObjectRef::Object; use crate::class::Value::Void; -use crate::heap::ObjectRef; -use crate::heap::ObjectRef::Object; +use crate::classmanager; +use crate::vm::stack::StackFrame; use crate::vm::Vm; -pub fn invoke_native(vm: &mut Vm, class_name: &String, method_name: &String, _args: Vec) -> Result { +pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec, class_name: &String, method_name: &str, _args: Vec) -> Result { info!("native {}.{}", class_name, method_name); match class_name.as_str() { "java/lang/Class" => java_lang_class(vm, method_name), - "jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(vm, method_name), + "jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(vm, stackframes, method_name), _ => Ok(Void) } } -fn java_lang_class(_vm: &mut Vm, method_name: &String) -> Result { - Ok(match method_name.as_str() { +fn java_lang_class(_vm: &Vm, method_name: &str) -> Result { + Ok(match method_name { "desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false), _ => Void }) } -fn jdk_internal_util_SystemProps_Raw(vm: &mut Vm,method_name: &String) -> Result { - match method_name.as_str() { +fn jdk_internal_util_SystemProps_Raw(vm: &mut Vm, stackframes: &mut Vec, method_name: &str) -> Result { + match method_name { "platformProperties()[Ljava/lang/String;" => systemProps(), - "cmdProperties()Ljava/util/HashMap;" => cmdProps(vm), //TODO ability to instantiate classes here - "vmProperties()[Ljava/lang/String;" => cmdProps(vm), + "cmdProperties()Ljava/util/HashMap;" => cmdProps(vm, stackframes), //TODO ability to instantiate classes here + "vmProperties()[Ljava/lang/String;" => cmdProps(vm, stackframes), _ => Ok(Void) } } -fn cmdProps(vm: &mut Vm,) -> Result { - let hashmap_class = get_class(vm, "java/util/HashMap")?; +fn cmdProps(vm: &mut Vm, stackframes: &mut Vec) -> Result { + classmanager::load_class_by_name("java/util/HashMap"); + let hashmap_class = classmanager::get_class_by_name("java/util/HashMap").unwrap(); let hashmap = Vm::new_instance(hashmap_class); - let hashmap = Value::Ref(unsafe_ref(Object(Box::new(hashmap)))); - vm.execute_special("java/util/HashMap", "()V", vec![hashmap.clone()]); - unsafe {debug!("hashmap {:?}", *hashmap.into_object().get());} + let hashmap = Value::Ref(Object(hashmap)); + vm.execute_special(stackframes, "java/util/HashMap", "()V", vec![hashmap.clone()]); panic!() } -fn systemProps() -> Result { +fn systemProps() -> Result { unsafe { let props: Lazy> = Lazy::new(|| { let mut vec: Vec = Vec::new(); @@ -87,7 +87,7 @@ fn systemProps() -> Result { if let Ok(https_proxy) = std::env::var("https_proxy") { vec.push(https_proxy.to_owned()); vec.push(https_proxy); - }else { + } else { vec.push("".to_owned()); vec.push("".to_owned()); } @@ -131,6 +131,6 @@ fn systemProps() -> Result { vec }); - Ok(Value::Ref(unsafe_ref(ObjectRef::StringArray(props.to_vec())))) + Ok(Value::Ref(ObjectRef::StringArray(props.to_vec()))) } } \ No newline at end of file diff --git a/src/opcodes.rs b/src/vm/opcodes.rs similarity index 100% rename from src/opcodes.rs rename to src/vm/opcodes.rs diff --git a/src/vm/operations.rs b/src/vm/operations.rs index 0ba7a89..f949760 100644 --- a/src/vm/operations.rs +++ b/src/vm/operations.rs @@ -1,29 +1,27 @@ -use std::cell::RefCell; use std::collections::HashMap; -use std::rc::Rc; -use std::sync::Arc; + use anyhow::Error; -use crate::class::{Class, get_class, Value}; -use crate::classloader::CpEntry; -use crate::vm::Vm; +use crate::class::{Class, Value}; +use crate::classloader::classdef::CpEntry; +use crate::classmanager; use crate::vm::vm::{Invocation, MethodSignature}; /// the place for opcode implementations that are a bit long // GET_STATIC opcode -pub(crate) fn get_static(vm: &mut Vm, this_class: Arc>, field_index: u16) -> Result { - let this_class = this_class.borrow(); +pub(crate) fn get_static(this_class: &Class, field_index: u16) -> Result { + let classdef = classmanager::get_classdef(&this_class.id); let (class_index, field_name_and_type_index) = - this_class.cp_field_ref(&field_index); // all these unwraps are safe as long as the class is valid + classdef.cp_field_ref(&field_index); // all these unwraps are safe as long as the class is valid let (name_index, _) = - this_class.cp_name_and_type(field_name_and_type_index); - let field_name = this_class.cp_utf8(name_index); + classdef.cp_name_and_type(field_name_and_type_index); + let field_name = classdef.cp_utf8(name_index); - let that_class_name_index = this_class.cp_class_ref(class_index); - let that_class_name = this_class.cp_utf8(that_class_name_index); - let that_class = get_class(vm, that_class_name.as_str())?; - let that_class = that_class.borrow(); + let that_class_name_index = classdef.cp_class_ref(class_index); + let that_class_name = classdef.cp_utf8(that_class_name_index); + classmanager::load_class_by_name(that_class_name); + let that_class = classmanager::get_class_by_name(that_class_name).unwrap(); let type_index = that_class .static_field_mapping @@ -32,10 +30,10 @@ pub(crate) fn get_static(vm: &mut Vm, this_class: Arc>, field_ind .get(field_name) .unwrap(); // safe because field must be there - Ok(that_class.static_data[type_index.index].clone()) + Ok(classmanager::get_static(&this_class.id, type_index.index)) } -pub(crate) fn get_name_and_type(cp: Rc>, index: u16) -> Option { +pub(crate) fn get_name_and_type(cp: &HashMap, index: u16) -> Option { if let CpEntry::NameAndType(method_name_index, signature_index) = cp.get(&index).unwrap() { if let CpEntry::Utf8(method_name) = cp.get(method_name_index).unwrap() { if let CpEntry::Utf8(signature) = cp.get(signature_index).unwrap() { @@ -48,16 +46,17 @@ pub(crate) fn get_name_and_type(cp: Rc>, index: u16) -> Op } None } -pub(crate) fn get_signature_for_invoke(cp: &Rc>, index: u16) -> Option { + +pub(crate) fn get_signature_for_invoke(cp: &HashMap, index: u16) -> Option { if let CpEntry::MethodRef(class_index, name_and_type_index) | CpEntry::InterfaceMethodref(class_index, name_and_type_index) = cp.get(&index).unwrap() { - if let Some(method_signature) = get_name_and_type(Rc::clone(&cp), *name_and_type_index) { + if let Some(method_signature) = get_name_and_type(cp, *name_and_type_index) { if let CpEntry::ClassRef(class_name_index) = cp.get(class_index).unwrap() { if let CpEntry::Utf8(class_name) = cp.get(class_name_index).unwrap() { return Some(Invocation::new( class_name.into(), - method_signature) + method_signature) ); } } diff --git a/src/vm/stack.rs b/src/vm/stack.rs index e359340..f741e42 100644 --- a/src/vm/stack.rs +++ b/src/vm/stack.rs @@ -1,8 +1,10 @@ use anyhow::Error; +use log::debug; + use crate::class::Value; #[derive(Debug)] -pub(crate) struct StackFrame { +pub struct StackFrame { pub(crate) at: String, pub(crate) data: Vec, } @@ -17,12 +19,14 @@ impl StackFrame { } pub(crate) fn push(&mut self, val: Value) { + debug!("push {:?}", val); self.data.push(val); } pub(crate) fn len(&self) -> usize { self.data.len() } + pub(crate) fn pop(&mut self) -> Result { Ok(self.data.pop().unwrap()) } diff --git a/src/vm/vm.rs b/src/vm/vm.rs index cfde0cf..69e5991 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -1,42 +1,22 @@ -use std::cell::RefCell; -use std::collections::HashMap; use std::io::Write; -use std::rc::Rc; -use std::sync::Arc; -use anyhow::{anyhow, Error}; +use anyhow::Error; use log::{debug, info}; -use once_cell::sync::Lazy; -use Value::*; - -use crate::class::{AttributeType, Class, CLASSES, get_class, Method, Modifier, unsafe_ref, Value}; -use crate::class::Value::{Null, Void}; -use crate::classloader::CpEntry; -use crate::heap::{Heap, Object, ObjectRef}; -use crate::io::*; -use crate::native::invoke_native; -use crate::opcodes; -use crate::opcodes::*; +use crate::class::{Class, ClassId, Object, ObjectRef, Value}; +use crate::class::Value::{F32, F64, I32, I64, Null, Ref, Utf8, Void}; +use crate::classloader::classdef::{AttributeType, CpEntry, Method, Modifier}; +use crate::classloader::io::{read_u16, read_u8}; +use crate::classmanager; use crate::vm::array::{array_load, array_store}; +use crate::vm::native::invoke_native; +use crate::vm::opcodes; +use crate::vm::opcodes::*; use crate::vm::operations::{get_signature_for_invoke, get_static}; use crate::vm::stack::StackFrame; -pub struct Vm { - pub classpath: Vec, - heap: Heap, - pub(crate) stackframes: Vec, -} +pub struct Vm {} -impl Vm { - fn init(vm: &mut Vm) { - Self::initialize_class(vm, "java/lang/System"); - } - - fn initialize_class(vm: &mut Vm, class: &str) { - vm.execute_static(class, "initPhase1()V", vec![]).expect("cannot create VM"); - } -} #[cfg(target_family = "unix")] const PATH_SEPARATOR: char = ':'; @@ -48,81 +28,89 @@ const PATH_SEPARATOR: char = ';'; //TODO goto //TODO error handling impl Vm { - fn current_frame(&mut self) -> &mut StackFrame { - let i = self.stackframes.len() - 1; - self.stackframes.get_mut(i).unwrap() + + /// for running static initializers + pub fn new_internal() -> Self { + Self {} } - pub fn new(classpath: &'static str) -> Self { + pub fn new(stack: &mut Vec) -> Self { env_logger::builder() .format(|buf, record| { writeln!(buf, "{}: {}", record.level(), record.args()) }) - .init(); - let mut vm_instance = Self { - classpath: classpath - .split(PATH_SEPARATOR) - .map(|s| s.to_owned()) - .collect(), - heap: Heap::new(), - stackframes: vec![], - }; - - Vm::init(&mut vm_instance); - + .try_init(); + let mut vm_instance = Self {}; + classmanager::init(); + Vm::init(&mut vm_instance, stack); vm_instance } - pub fn new_instance(class: Arc>) -> Object { - Object::new(class.clone()) + fn init(vm: &mut Vm, stack: &mut Vec) { + classmanager::load_class_by_name("java/lang/Class"); + Self::initialize_class(vm, stack, "java/lang/System"); + } + + fn initialize_class(vm: &mut Vm, stack: &mut Vec, class: &str) { + vm.execute_static(stack, class, "initPhase1()V", vec![]).expect("cannot create VM"); + } + + fn current_frame(stackframes: &mut Vec) -> &mut StackFrame { + let i = stackframes.len() - 1; + stackframes.get_mut(i).unwrap() + } + + pub fn new_instance(class: &Class) -> Object { + Object::new(class) } /// execute the bytecode - /// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM pub fn execute_virtual( &mut self, + stack: &mut Vec, class_name: &str, method_name: &str, args: Vec, ) -> Result { - unsafe { - for arg in &args { - if let Ref(r) = arg { - info!("arg {:?}",&*r.get()); + for arg in &args { + if let Ref(r) = arg { + info!("arg {:?}",r); + } else { + info!("arg {:?}",arg); + } + } + + if let Null = args[0] { + panic!("NPE"); + } + if let Ref(this) = &args[0] { + if let ObjectRef::Object(this) = this { + let cd = classmanager::get_classdef(&this.class_id); + let method = cd.get_method(method_name); + if let Some(method) = method { + return self.execute_class_id(stack, this.class_id, &method, args.clone()); } else { - info!("arg {:?}",arg); - } - } - - - if let Null = args[0] { - panic!("NPE"); - } - if let Ref(this) = &args[0] { - if let ObjectRef::Object(this) = &*this.get() { - let class = &this.class; - let borrow = class.borrow(); - let method = borrow.get_method(method_name); - if let Some(method) = method { - return self.execute_class(class.clone(), method.clone(), args); - } else { - for s in &borrow.super_classes { - let borrow2 = s.borrow(); - let method = borrow2.get_method(method_name); + let name = classmanager::classdef_name(&this.class_id); + if let Some(name) = name { + classmanager::load_class_by_name(&name); + let class = classmanager::get_class_by_name(&name).unwrap(); + for parent_id in &class.parents { if let Some(method) = method { - return self.execute_class(class.clone(), method.clone(), args); + return self.execute_class(stack, class, method_name, args); } else { - debug!("not {:?}", s); + debug!("not {:?}", parent_id); } } - debug!("not found {}", method_name); + } else { + panic!("ClassNotFound"); } - } else if let ObjectRef::Class(class) = &*this.get() { - let klazz = get_class(self, "java/lang/Class")?; - let borrow = klazz.borrow(); - let method = borrow.get_method(method_name).unwrap(); - return self.execute_class(class.clone(), method.clone(), args); } + } else if let ObjectRef::Class(_class) = this { + //TODO is this right?? + classmanager::load_class_by_name("java/lang/Class");//TODO preload, so this is not needed + let klazz = classmanager::get_class_by_name("java/lang/Class").unwrap(); + // let klazzdef = self.classmanager.get_classdef(&klazz.id); + return self.execute_class(stack, klazz, method_name, args); } } println!("this is not an object reference {}", class_name); @@ -131,157 +119,160 @@ impl Vm { pub fn execute_special( &mut self, + stack: &mut Vec, class_name: &str, method_name: &str, args: Vec, ) -> Result { - let class = get_class(self, class_name)?; - let method = class.clone().borrow().get_method(method_name).expect("execute special needs invoked method on the class").clone(); - self.execute_class(class.clone(), method.clone(), args) + classmanager::load_class_by_name(class_name); + let class = classmanager::get_class_by_name(class_name).unwrap(); + self.execute_class(stack, class, method_name, args) } pub fn execute_static( &mut self, + stack: &mut Vec, class_name: &str, method_name: &str, args: Vec, ) -> Result { - let class = get_class(self, class_name)?; - let method = class.clone().borrow().get_method(method_name).expect("execute static needs this method").clone(); - self.execute_class(class, method, args) + classmanager::load_class_by_name(class_name); + let class = classmanager::get_class_by_name(class_name).unwrap(); + let _classdef = classmanager::get_classdef(&class.id); + self.execute_class(stack, class, method_name, args) + } + + pub fn execute_class_id(&self, _stack: &mut Vec, _this_class: ClassId, _method: &Method, _args: Vec) -> Result { + Ok(Null) } pub fn execute_class( &mut self, - class: Arc>, - method: Rc, + stackframes: &mut Vec, + this_class: &Class, + method_name: &str, args: Vec, ) -> Result { - let this_class = class; - info!("execute {}.{}", this_class.borrow().name, method.name()); + info!("execute {}.{}", this_class.name, method_name); //TODO implement dynamic dispatch -> get method from instance - + let method = classmanager::get_classdef(&this_class.id).get_method(method_name).unwrap(); let mut local_params: Vec> = args.clone().iter().map(|e| Some(e.clone())).collect(); if method.is(Modifier::Native) { - return invoke_native(self, &this_class.borrow().name, &method.name(), args); + return invoke_native(self, stackframes, &this_class.name, method_name, args); } if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() { - let stackframe = StackFrame::new(&this_class.borrow().name, &method.name()); - self.stackframes.push(stackframe); + let stackframe = StackFrame::new(&this_class.name, method_name); + stackframes.push(stackframe); let pc = &mut 0; while *pc < code.opcodes.len() { let opcode = read_u8(&code.opcodes, pc); - let cur_frame = self.current_frame(); + let cur_frame = Self::current_frame(stackframes); info!("\t{} #{} {} - {}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.len()); match opcode { ACONST_NULL => { - self.current_frame().push(Value::Null); + Self::current_frame(stackframes).push(Value::Null); } ICONST_M1 => { - self.current_frame().push(I32(-1)); + Self::current_frame(stackframes).push(I32(-1)); } ICONST_0 => { - self.current_frame().push(I32(0)); + Self::current_frame(stackframes).push(I32(0)); } ICONST_1 => { - self.current_frame().push(I32(1)); + Self::current_frame(stackframes).push(I32(1)); } ICONST_2 => { - self.current_frame().push(I32(2)); + Self::current_frame(stackframes).push(I32(2)); } ICONST_3 => { - self.current_frame().push(I32(3)); + Self::current_frame(stackframes).push(I32(3)); } ICONST_4 => { - self.current_frame().push(I32(4)); + Self::current_frame(stackframes).push(I32(4)); } ICONST_5 => { - self.current_frame().push(I32(5)); + Self::current_frame(stackframes).push(I32(5)); } LCONST_0 => { - self.current_frame().push(I64(0)); + Self::current_frame(stackframes).push(I64(0)); } LCONST_1 => { - self.current_frame().push(I64(1)); + Self::current_frame(stackframes).push(I64(1)); } FCONST_0 => { - self.current_frame().push(F32(0.0)); + Self::current_frame(stackframes).push(F32(0.0)); } FCONST_1 => { - self.current_frame().push(F32(1.0)); + Self::current_frame(stackframes).push(F32(1.0)); } FCONST_2 => { - self.current_frame().push(F32(2.0)); + Self::current_frame(stackframes).push(F32(2.0)); } DCONST_0 => { - self.current_frame().push(F64(0.0)); + Self::current_frame(stackframes).push(F64(0.0)); } DCONST_1 => { - self.current_frame().push(F64(1.0)); + Self::current_frame(stackframes).push(F64(1.0)); } SIPUSH => { let s = read_u16(&code.opcodes, pc) as i32; - self.current_frame().push(I32(s)); + Self::current_frame(stackframes).push(I32(s)); } BIPUSH => { let c = read_u8(&code.opcodes, pc) as i32; - self.current_frame().push(I32(c)); + Self::current_frame(stackframes).push(I32(c)); } LDC => { let cp_index = read_u8(&code.opcodes, pc) as u16; let c = method.constant_pool.get(&cp_index).unwrap(); match c { CpEntry::Integer(i) => { - self.current_frame().push(I32(*i)); + Self::current_frame(stackframes).push(I32(*i)); } CpEntry::Float(f) => { - self.current_frame().push(Value::F32(*f)); + Self::current_frame(stackframes).push(Value::F32(*f)); } CpEntry::Double(d) => { - self.current_frame().push(Value::F64(*d)); + Self::current_frame(stackframes).push(Value::F64(*d)); } CpEntry::StringRef(utf8) => { //TODO - let stringclass = get_class( - self, - "java/lang/String", - ) - .unwrap(); + classmanager::load_class_by_name("java/lang/String"); + let stringclass = classmanager::get_class_by_name("java/lang/String").unwrap(); let stringinstance = - Ref(unsafe_ref(ObjectRef::Object( - Box::new(Vm::new_instance(stringclass.clone())), - ))); - let string: Vec = this_class - .borrow() - .cp_utf8(utf8) - .to_owned() - .as_bytes() - .into(); + Ref(ObjectRef::Object(Vm::new_instance(stringclass))); - self.execute_special( - "java/lang/String", - "([B)V", - vec![ - stringinstance.clone(), - Ref(ObjectRef::new_byte_array(string)), - ], + let string: Vec = + classmanager::get_classdef(&this_class.id).cp_utf8(utf8) + .to_owned() + .as_bytes() + .into(); + + self.execute_special(stackframes, + "java/lang/String", + "([B)V", + vec![ + stringinstance.clone(), + Ref(ObjectRef::new_byte_array(string)), + ], )?; - self.current_frame().push(stringinstance); + Self::current_frame(stackframes).push(stringinstance); } CpEntry::Long(l) => { - self.current_frame().push(Value::I64(*l)); + Self::current_frame(stackframes).push(Value::I64(*l)); } CpEntry::ClassRef(utf8) => { - let class_name = this_class.borrow().cp_utf8(utf8).to_owned(); - unsafe { - if let Some(class) = CLASSES.get(&class_name) { - self.current_frame().push(class.clone()); - } else { - unreachable!("should not be here"); - } + let classdef = classmanager::get_classdef(&this_class.id); + let class_name = classdef.cp_utf8(utf8); + classmanager::load_class_by_name(class_name); + let klass_id = classmanager::get_classid(class_name); + if let Some(class) = classmanager::get_classobject(klass_id) { + Self::current_frame(stackframes).push(class.clone()); + } else { + unreachable!("should not be here"); } } _ => { @@ -294,14 +285,14 @@ impl Vm { let cp_entry = method.constant_pool.get(&cp_index).unwrap(); match cp_entry { CpEntry::Integer(i) => { - self.current_frame().push(I32(*i)); + Self::current_frame(stackframes).push(I32(*i)); } CpEntry::Float(f) => { - self.current_frame().push(F32(*f)); + Self::current_frame(stackframes).push(F32(*f)); } CpEntry::StringRef(utf8_index) => { if let CpEntry::Utf8(s) = method.constant_pool.get(utf8_index).unwrap() { - self.current_frame().push(Utf8(s.to_owned())); + Self::current_frame(stackframes).push(Utf8(s.to_owned())); } else {} } _ => { @@ -314,10 +305,10 @@ impl Vm { let cp_index = read_u16(&code.opcodes, pc); match method.constant_pool.get(&cp_index).unwrap() { CpEntry::Double(d) => { - self.current_frame().push(Value::F64(*d)); + Self::current_frame(stackframes).push(Value::F64(*d)); } CpEntry::Long(l) => { - self.current_frame().push(Value::I64(*l)); + Self::current_frame(stackframes).push(Value::I64(*l)); } _ => { unreachable!() @@ -327,115 +318,112 @@ impl Vm { ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => { // omitting the type checks so far let n = read_u8(&code.opcodes, pc) as usize; - self.current_frame() + Self::current_frame(stackframes) .push(local_params[n].as_ref().unwrap().clone()); } ILOAD_0 | LLOAD_0 | FLOAD_0 | DLOAD_0 | ALOAD_0 => { - self.current_frame() + Self::current_frame(stackframes) .push(local_params[0].as_ref().unwrap().clone()); } ILOAD_1 | LLOAD_1 | FLOAD_1 | DLOAD_1 | ALOAD_1 => { - self.current_frame() + Self::current_frame(stackframes) .push(local_params[1].as_ref().unwrap().clone()); } ILOAD_2 | LLOAD_2 | FLOAD_2 | DLOAD_2 | ALOAD_2 => { - self.current_frame() + Self::current_frame(stackframes) .push(local_params[2].as_ref().unwrap().clone()); } ILOAD_3 | LLOAD_3 | FLOAD_3 | DLOAD_3 | ALOAD_3 => { - self.current_frame() + Self::current_frame(stackframes) .push(local_params[3].as_ref().unwrap().clone()); } - IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => unsafe { - let index = self.current_frame().pop()?; - let arrayref = self.current_frame().pop()?; - self.current_frame().push(array_load(index, arrayref)?); - }, + IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => { + let index = Self::current_frame(stackframes).pop()?; + let arrayref = Self::current_frame(stackframes).pop()?; + Self::current_frame(stackframes).push(array_load(index, arrayref)?); + } ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => { let index = read_u8(&code.opcodes, pc) as usize; - self.store(&mut local_params, index)?; + self.store(stackframes, &mut local_params, index)?; } ISTORE_0 | LSTORE_0 | DSTORE_0 | ASTORE_0 | FSTORE_0 => { - self.store(&mut local_params, 0)?; + self.store(stackframes, &mut local_params, 0)?; } ISTORE_1 | LSTORE_1 | DSTORE_1 | ASTORE_1 | FSTORE_1 => { - self.store(&mut local_params, 1)?; + self.store(stackframes, &mut local_params, 1)?; } ISTORE_2 | LSTORE_2 | DSTORE_2 | ASTORE_2 | FSTORE_2 => { - self.store(&mut local_params, 2)?; + self.store(stackframes, &mut local_params, 2)?; } ISTORE_3 | LSTORE_3 | DSTORE_3 | ASTORE_3 | FSTORE_3 => { - self.store(&mut local_params, 3)?; + self.store(stackframes, &mut local_params, 3)?; } BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE - | AASTORE => unsafe { - let value = self.current_frame().pop()?; - let index = self.current_frame().pop()?; - let arrayref = &mut self.current_frame().pop()?; + | AASTORE => { + let value = Self::current_frame(stackframes).pop()?; + let index = Self::current_frame(stackframes).pop()?; + let arrayref = Self::current_frame(stackframes).pop()?; array_store(value, index, arrayref)? - }, + } POP => { - self.current_frame().pop()?; + Self::current_frame(stackframes).pop()?; } DUP => { - let value = self.current_frame().pop()?; - self.current_frame().push(value.clone()); - self.current_frame().push(value); + let value = Self::current_frame(stackframes).pop()?; + Self::current_frame(stackframes).push(value.clone()); + Self::current_frame(stackframes).push(value); } IDIV => { - let value1 = self.current_frame().pop()?; - let value2 = self.current_frame().pop()?; - self.current_frame().push(I32(value1.into_i32() / value2.into_i32())); + let value1 = Self::current_frame(stackframes).pop()?; + let value2 = Self::current_frame(stackframes).pop()?; + Self::current_frame(stackframes).push(I32(value1.into_i32() / value2.into_i32())); } IFEQ | IFNE | IFLT | IFGE | IFGT | IFLE => { let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode - let value = self.current_frame().pop()?; - unsafe { - Self::if_cmp(pc, opcode, jmp_to, &value, &I32(0)); - } + let value = Self::current_frame(stackframes).pop()?; + Self::if_cmp(pc, opcode, jmp_to, &value, &I32(0)); } IF_ICMPEQ | IF_ICMPNE | IF_ICMPGT | IF_ICMPGE | IF_ICMPLT | IF_ICMPLE => { let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode - let value1 = self.current_frame().pop()?; - let value2 = self.current_frame().pop()?; - unsafe { - Self::if_cmp(pc, opcode, jmp_to, &value1, &value2); - } + let value1 = Self::current_frame(stackframes).pop()?; + let value2 = Self::current_frame(stackframes).pop()?; + Self::if_cmp(pc, opcode, jmp_to, &value1, &value2); } GOTO => { let jmp_to = read_u16(&code.opcodes, pc) - 3; *pc += jmp_to as usize; } IRETURN | FRETURN | DRETURN | ARETURN => { - let result = self.current_frame().pop(); - self.stackframes.pop(); + let result = Self::current_frame(stackframes).pop(); + stackframes.pop(); return result; } RETURN_VOID => { - self.stackframes.pop(); + stackframes.pop(); return Ok(Void); } GETSTATIC => { let field_index = read_u16(&code.opcodes, pc); - let field_value = get_static(self, this_class.clone(), field_index)?; - self.current_frame().push(field_value); + let field_value = get_static(this_class, field_index)?; + + Self::current_frame(stackframes).push(field_value); } PUTSTATIC => { - let mut borrow = this_class.borrow_mut(); + let classdef = classmanager::get_classdef(&this_class.id); let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) = - borrow.cp_field_ref(&cp_index); // all these unwraps are safe as long as the class is valid + classdef.cp_field_ref(&cp_index); // 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); - let name = borrow.cp_utf8(name_index); - let class_name_index = borrow.cp_class_ref(class_index); - let that_class_name = borrow.cp_utf8(class_name_index); + classdef.cp_name_and_type(field_name_and_type_index); + let name = classdef.cp_utf8(name_index); + let class_name_index = classdef.cp_class_ref(class_index); + let that_class_name = classdef.cp_utf8(class_name_index); - let val_index = if &borrow.name == that_class_name { + let val_index = if &this_class.name == that_class_name { // may have to apply this in GETSTATIC too - borrow + this_class .static_field_mapping .get(that_class_name) .unwrap() @@ -443,209 +431,203 @@ impl Vm { .unwrap() .index } else { - let that = - get_class(self, that_class_name.as_str())?; - let that_borrow = that.borrow(); - that_borrow - .static_field_mapping + classmanager::load_class_by_name(that_class_name); + let that = classmanager::get_class_by_name(that_class_name).unwrap(); + that.static_field_mapping .get(that_class_name) .unwrap() .get(name) .unwrap() .index }; - let value = self.current_frame().pop()?; - borrow.static_data[val_index] = value; + let value = Self::current_frame(stackframes).pop()?; + classmanager::set_static(&this_class.id, val_index, value); } - GETFIELD => unsafe { - let borrow = this_class.borrow(); + GETFIELD => { + let classdef = classmanager::get_classdef(&this_class.id); let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) = - borrow.cp_field_ref(&cp_index); + classdef.cp_field_ref(&cp_index); let (field_name_index, _) = - borrow.cp_name_and_type(field_name_and_type_index); - let class_name_index = borrow.cp_class_ref(class_index); - let class_name = borrow.cp_utf8(class_name_index); - let field_name = borrow.cp_utf8(field_name_index); + classdef.cp_name_and_type(field_name_and_type_index); + let class_name_index = classdef.cp_class_ref(class_index); + let declared_type = classdef.cp_utf8(class_name_index); + let field_name = classdef.cp_utf8(field_name_index); - let objectref = self.current_frame().pop()?; + let objectref = Self::current_frame(stackframes).pop()?; if let Ref(instance) = objectref { - if let ObjectRef::Object(ref mut object) = &mut *instance.get() { - let value = object.get(class_name, field_name); - self.current_frame().push(value.clone()); + if let ObjectRef::Object(mut object) = instance { + let value = object.get(this_class, declared_type, field_name); + Self::current_frame(stackframes).push(value.clone()); } else { unreachable!() } } else { unreachable!("objectref {:?}", objectref) } - }, - PUTFIELD => unsafe { - let borrow = this_class.borrow(); + } + PUTFIELD => { + let classdef = classmanager::get_classdef(&this_class.id); let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) = - borrow.cp_field_ref(&cp_index); + classdef.cp_field_ref(&cp_index); let (field_name_index, _) = - borrow.cp_name_and_type(field_name_and_type_index); - let class_name_index = borrow.cp_class_ref(class_index); - let class_name = borrow.cp_utf8(class_name_index); - let field_name = borrow.cp_utf8(field_name_index); + classdef.cp_name_and_type(field_name_and_type_index); + let class_name_index = classdef.cp_class_ref(class_index); + let declared_type = classdef.cp_utf8(class_name_index); + let field_name = classdef.cp_utf8(field_name_index); - let value = self.current_frame().pop()?; - let objectref = self.current_frame().pop()?; + let value = Self::current_frame(stackframes).pop()?; + let objectref = Self::current_frame(stackframes).pop()?; if let Ref(instance) = objectref { - if let ObjectRef::Object(ref mut object) = &mut *instance.get() { - object.set(class_name, field_name, value); + if let ObjectRef::Object(mut object) = instance { + object.set(this_class, declared_type, field_name, value); } } else { unreachable!() } - }, - INVOKESPECIAL => unsafe { - // TODO differentiate these opcodes - let cp_index = read_u16(&code.opcodes, pc); - if let Some(invocation) = - get_signature_for_invoke(&method.constant_pool, cp_index) - { - let mut args = Vec::with_capacity(invocation.method.num_args); - for _ in 0..invocation.method.num_args { - args.insert(0, self.current_frame().pop()?.clone()); - } - args.insert(0, self.current_frame().pop()?); - let return_value = self.execute_special( - &invocation.class_name, - &invocation.method.name, - args, - )?; - if let Ref(r) = &return_value { - if let ObjectRef::Object(p) = &*r.get() { - info!("return {:?}", p); - } - } else { - info!("return {:?}", return_value); - } - match return_value { - Void => {} - _ => { - self.current_frame().push(return_value.clone()); - } - } - // println!("stack {} at {}", self.current_frame().len(), self.current_frame().at) - } else { - unreachable!() - } - }, - INVOKEVIRTUAL => unsafe { - // TODO differentiate these opcodes - let cp_index = read_u16(&code.opcodes, pc); - if let Some(invocation) = - get_signature_for_invoke(&method.constant_pool, cp_index) - { - let mut args = Vec::with_capacity(invocation.method.num_args); - for _ in 0..invocation.method.num_args { - args.insert(0, self.current_frame().pop()?.clone()); - } - args.insert(0, self.current_frame().pop()?); - let return_value = self.execute_virtual( - &invocation.class_name, - &invocation.method.name, - args, - )?; - if let Ref(r) = &return_value { - if let ObjectRef::Object(p) = &*r.get() { - info!("return {:?}", p); - } - } else { - info!("return {:?}", return_value); - } - match return_value { - Void => {} - _ => { - self.current_frame().push(return_value.clone()); - } - } - // println!("stack {} at {}", self.current_frame().len(), self.current_frame().at) - } else { - unreachable!() - } - }, - INVOKESTATIC => unsafe { - let cp_index = read_u16(&code.opcodes, pc); - if let Some(invocation) = - get_signature_for_invoke(&method.constant_pool, cp_index) - { - let mut args = Vec::with_capacity(invocation.method.num_args); - for _ in 0..invocation.method.num_args { - args.insert(0, self.current_frame().pop()?.clone()); - } - let return_value = self.execute_static( - &invocation.class_name, - &invocation.method.name, - args, - )?; - if let Ref(r) = &return_value { - if let ObjectRef::Object(p) = &*r.get() { - info!("return {:?}", p); - } - } else { - info!("return {:?}", return_value); - } - match return_value { - Void => {} - _ => { - self.current_frame().push(return_value.clone()); - } - } - } else { - unreachable!() - } - }, - NEW => { - let class_index = &read_u16(&code.opcodes, pc); - let borrow = this_class.borrow(); - let class_name_index = borrow.cp_class_ref(class_index); - let class_name = borrow.cp_utf8(class_name_index); - let class_to_instantiate = get_class(self, class_name)?; - - let object = unsafe_ref(ObjectRef::Object(Box::new(Vm::new_instance( - class_to_instantiate, - )))); - self.current_frame().push(Value::Ref(Arc::clone(&object))); - self.heap.new_object(object); } - ANEWARRAY => unsafe { + INVOKESPECIAL => { + // TODO differentiate these opcodes + let cp_index = read_u16(&code.opcodes, pc); + if let Some(invocation) = + get_signature_for_invoke(&method.constant_pool, cp_index) + { + let mut args = Vec::with_capacity(invocation.method.num_args); + for _ in 0..invocation.method.num_args { + args.insert(0, Self::current_frame(stackframes).pop()?.clone()); + } + args.insert(0, Self::current_frame(stackframes).pop()?); + let return_value = self.execute_special(stackframes, + &invocation.class_name, + &invocation.method.name, + args, + )?; + if let Ref(objectref) = &return_value { + if let ObjectRef::Object(object) = objectref { + info!("return {:?}", object); + } + } else { + info!("return {:?}", return_value); + } + match return_value { + Void => {} + _ => { + Self::current_frame(stackframes).push(return_value.clone()); + } + } + // println!("stack {} at {}", Self::current_frame(stack).len(), Self::current_frame(stack).at) + } else { + unreachable!() + } + } + INVOKEVIRTUAL => { + // TODO differentiate these opcodes + let cp_index = read_u16(&code.opcodes, pc); + if let Some(invocation) = + get_signature_for_invoke(&method.constant_pool, cp_index) + { + let mut args = Vec::with_capacity(invocation.method.num_args); + for _ in 0..invocation.method.num_args { + args.insert(0, Self::current_frame(stackframes).pop()?.clone()); + } + args.insert(0, Self::current_frame(stackframes).pop()?); + let return_value = self.execute_virtual( + stackframes, + &invocation.class_name, + &invocation.method.name, + args, + )?; + if let Ref(objectref) = &return_value { + if let ObjectRef::Object(object) = objectref { + info!("return {:?}", object); + } + } else { + info!("return {:?}", return_value); + } + match return_value { + Void => {} + _ => { + Self::current_frame(stackframes).push(return_value.clone()); + } + } + } else { + unreachable!() + } + } + INVOKESTATIC => { + let cp_index = read_u16(&code.opcodes, pc); + if let Some(invocation) = + get_signature_for_invoke(&method.constant_pool, cp_index) + { + let mut args = Vec::with_capacity(invocation.method.num_args); + for _ in 0..invocation.method.num_args { + args.insert(0, Self::current_frame(stackframes).pop()?.clone()); + } + let return_value = self.execute_static(stackframes, + &invocation.class_name, + &invocation.method.name, + args, + )?; + if let Ref(objectref) = &return_value { + if let ObjectRef::Object(object) = objectref { + info!("return {:?}", object); + } + } else { + info!("return {:?}", return_value); + } + match return_value { + Void => {} + _ => { + Self::current_frame(stackframes).push(return_value.clone()); + } + } + } else { + unreachable!() + } + } + NEW => { + let classdef = classmanager::get_classdef(&this_class.id); let class_index = &read_u16(&code.opcodes, pc); - let borrow = this_class.borrow(); - let class_name_index = borrow.cp_class_ref(class_index); - let class_name = borrow.cp_utf8(class_name_index); - let arraytype = get_class(self, class_name)?; - let count = self.current_frame().pop()?; - if let I32(count) = count { - // why does pop()?.get() give weird results? - let array = ObjectRef::new_object_array(arraytype, count as usize); - let array = unsafe_ref(array); + let class_name_index = classdef.cp_class_ref(class_index); + let class_name = classdef.cp_utf8(class_name_index); + classmanager::load_class_by_name(class_name); + let class_to_instantiate = classmanager::get_class_by_name(class_name).unwrap(); - self.current_frame().push(Value::Ref(Arc::clone(&array))); - self.heap.new_object(array); + let object = ObjectRef::Object(Vm::new_instance( + class_to_instantiate, + )); + Self::current_frame(stackframes).push(Ref(object)); + // self.heap.new_object(object); + } + ANEWARRAY => { + let classdef = classmanager::get_classdef(&this_class.id); + let class_index = &read_u16(&code.opcodes, pc); + let class_name_index = classdef.cp_class_ref(class_index); + let class_name = classdef.cp_utf8(class_name_index); + classmanager::load_class_by_name(class_name); + let arraytype = classmanager::get_class_by_name(class_name).unwrap(); + let count = Self::current_frame(stackframes).pop()?; + if let I32(count) = count { + let array = ObjectRef::new_object_array(arraytype, count as usize); + + Self::current_frame(stackframes).push(Value::Ref(array)); } else { panic!(); } - }, + } ARRAYLENGTH => { - let val = self.current_frame().pop()?; - unsafe { - if let Ref(val) = val { - let o = &*val.get(); - self.current_frame().push(I32(o.get_array_length() as i32)); - } + let val = Self::current_frame(stackframes).pop()?; + if let Ref(val) = val { + Self::current_frame(stackframes).push(I32(val.get_array_length() as i32)); } } MONITORENTER => { - self.current_frame().pop()?; + Self::current_frame(stackframes).pop()?; } //TODO implement - IFNULL | IFNONNULL => unsafe { + IFNULL | IFNONNULL => { let jmp_to = read_u16(&code.opcodes, pc) - 3; - let value = self.current_frame().pop()?; + let value = Self::current_frame(stackframes).pop()?; let its_null = if let Null = value { true } else { false }; if its_null && opcode == IFNULL { @@ -666,7 +648,7 @@ impl Vm { }, //TODO implement all opcodes _ => { - panic!("opcode {} not implemented {:?}", opcode, self.stackframes) + panic!("opcode {} not implemented {:?}", opcode, stackframes) //TODO implement proper --stacktraces-- error handling } } @@ -697,16 +679,19 @@ impl Vm { } } + + /// store in local param fn store( &mut self, + stack: &mut Vec, local_params: &mut Vec>, index: usize, ) -> Result<(), Error> { - let value = self.current_frame().pop()?; + let value = Self::current_frame(stack).pop()?; while local_params.len() < index + 1 { local_params.push(None); } - local_params[index] = Some(value.clone()); + local_params[index] = Some(value); Ok(()) } } diff --git a/tests/class_tests.rs b/tests/class_tests.rs index dd442a3..e63b942 100644 --- a/tests/class_tests.rs +++ b/tests/class_tests.rs @@ -1,18 +1,20 @@ mod test { - use java_rs::class::Value; - use java_rs::heap::ObjectRef; - use java_rs::vm1::Vm; + use java_rs::class::{ObjectRef, Value}; + use java_rs::classmanager::set_classpath; + use java_rs::vm::Vm; #[test] fn if_cmp() { - let mut vm = Vm::new("tests"); - let ret = vm.execute_virtual("testclasses.IfCmp", "i_is_1()Z", vec![]).unwrap(); + let mut stackframes = Vec::new(); + let mut vm = Vm::new(&mut stackframes); + set_classpath("/Users/Shautvast/dev/java/tests"); + let ret = vm.execute_virtual(&mut stackframes,"testclasses.IfCmp", "i_is_1()Z", vec![]).unwrap(); unsafe { - if let Value::I32(b) = *ret.get() { + if let Value::I32(b) = ret { // internally a boolean is an int assert_eq!(0, b); } else { - println!("{:?}", *ret.get()); + println!("{:?}", ret); assert!(false) } } @@ -20,18 +22,20 @@ mod test { #[test] fn consts() { - let mut vm = Vm::new("tests"); + let mut stackframes = Vec::new(); + let mut vm = Vm::new(&mut stackframes); + set_classpath("/Users/Shautvast/dev/java/tests"); let ret = vm - .execute_static("testclasses.Const", "hello()Ljava/lang/String;", vec![]) + .execute_static(&mut stackframes, "testclasses.Const", "hello()Ljava/lang/String;", vec![]) .unwrap(); unsafe { - if let Value::Ref(s) = &*ret.get() { + if let Value::Ref(s) = ret { // internally a boolean is an int - if let ObjectRef::Object(a) = &*s.get() { + if let ObjectRef::Object(a) = s { println!("{:?}", a); } } else { - println!("{:?}", *ret.get()); + println!("{:?}", ret); assert!(false) } }