diff --git a/README.md b/README.md index 677f7b9..71b7b20 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,4 @@ actually: **Ultimate goal** * Hello world domination +`` \ No newline at end of file diff --git a/src/class.rs b/src/class.rs index bdb2d7b..02a9e69 100644 --- a/src/class.rs +++ b/src/class.rs @@ -7,6 +7,7 @@ use rand::random; use crate::class::ObjectRef::*; +/// ClassId facilitates loose coupling between classes, classdefs and objects pub type ClassId = usize; #[derive(Debug, Clone)] @@ -24,20 +25,17 @@ 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 + // lookup index and type from the name of the declared class and then field pub(crate) object_field_mapping: HashMap>, pub(crate) static_field_mapping: HashMap>, - // pub(crate) static_field_data: Vec, + // pub(crate) static_field_data: Vec // moved to classmanager } impl Class { diff --git a/src/classmanager.rs b/src/classmanager.rs index 3ed686e..d9ca87b 100644 --- a/src/classmanager.rs +++ b/src/classmanager.rs @@ -1,6 +1,7 @@ use std::cell::RefCell; use std::collections::{HashMap, LinkedList}; use std::rc::Rc; + use log::debug; use once_cell::sync::Lazy; @@ -12,6 +13,7 @@ use crate::classloader::io::PATH_SEPARATOR; use crate::vm::Vm; static mut CLASSMANAGER: Lazy = Lazy::new(|| ClassManager::new()); +static PRIMITIVES: Lazy> = Lazy::new(|| vec!["B", "S", "I", "J", "F", "D", "Z", "J", "C"]); pub fn init() { unsafe { @@ -151,23 +153,64 @@ impl ClassManager { self.classdefs.get(&id).unwrap() } + /// loads the class if not already there 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); + debug!("load class {}", name); + // determine no of dimensions and get type of array if any + let mut chars = name.chars(); + let mut num_dims = 0; + while let Some(c) = chars.nth(num_dims) { + if c == '[' { + num_dims += 1; + } else { + break; } - None => { - self.add_class(name); + } + let mut type_name = name[num_dims..name.len()].to_owned(); + + if num_dims > 0 { + if !PRIMITIVES.contains(&type_name.as_str()){ + type_name = type_name[1..type_name.len()].to_owned(); + } + let id = self.get_or_new_id(name); + if !self.class_objects.contains_key(&id) { + 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(Rc::new(RefCell::new(instance)))); + + self.class_objects.insert(id, instance); + } + } else { + // in cache? + let id = self.names.get(&type_name); + match id { + Some(id) => if self.classes.get(id).is_none() { + self.add_class(&type_name); + } + None => { + self.add_class(&type_name); + } } } } + /// get optional classid from cache fn get_class_by_name(&self, name: &str) -> Option<&Class> { let id = self.names.get(name); self.classes.get(id.unwrap()) } + /// adds the class and calculates the 'offset' of it's fields (static and non-static) + /// this is a map (declared-class -> map (field-name -> type_index)) + /// -> fields are not polymorphic, meaning a field can exist in the class and in the superclass and can be addressed individually (no hiding) + /// -> the bytecode will know what declared type field is needed + /// + /// type_index is tuple (field-type, index) + /// field-type is a string + /// index is an index into the list of values that object instances will use to store the values + /// + /// the function also instantiates a (java.lang.) Class object for each loaded class fn add_class(&mut self, name: &str) -> ClassId { debug!("add class {}", name); let this_classid = self.load(name); @@ -202,11 +245,11 @@ impl ClassManager { .map(|n| *self.names.get(n.as_str()).unwrap()) .collect(); + // initial values for static fields (before static init) self.static_class_data.insert(this_classid, Self::set_field_data(&static_field_mapping)); self.classes.insert(this_classid, Class { id: this_classid, - initialized: false, name: name.into(), superclass: superclass_id, parents, @@ -215,6 +258,7 @@ impl ClassManager { static_field_mapping, }); + // add a new Class instance if name != "java/lang/Class" { let cls = self.get_class_by_name("java/lang/Class").unwrap(); let mut instance = Object::new(cls); @@ -223,15 +267,16 @@ impl ClassManager { self.class_objects.insert(this_classid, instance); } - let clinit = this_classdef.methods.contains_key("()V"); - if clinit { + // run static init + if this_classdef.methods.contains_key("()V") { self.vm.execute_special(&mut vec![], name, "()V", vec![]).unwrap(); } this_classid } + /// like described above fn add_fields_for_this_or_parents(object_field_mapping: &mut HashMap>, static_field_mapping: &mut HashMap>, object_field_map_index: &mut usize, @@ -269,10 +314,7 @@ impl ClassManager { /// 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 id = self.get_or_new_id(name); let classdef = self.classdefs .entry(id) @@ -280,6 +322,14 @@ impl ClassManager { (id, inspect_dependencies(classdef)) } + fn get_or_new_id(&mut self, name: &str) -> ClassId { + let id = *self.names.entry(name.to_string()).or_insert_with(|| { + self.current_id += 1; + self.current_id + }); + id + } + pub(crate) fn set_field_data(field_mapping: &HashMap>) -> Vec { let mut field_data = vec![Null; n_fields(field_mapping)]; @@ -326,7 +376,9 @@ pub(crate) fn inspect_dependencies(classdef: &ClassDef) -> Vec { #[cfg(test)] mod test { use std::rc::Rc; + use crate::classloader::classdef::{CpEntry, Field}; + use super::*; #[test] @@ -372,7 +424,7 @@ mod test { let mut fields_declared_by_java_lang_class = HashMap::new(); fields_declared_by_java_lang_class.insert("name".to_owned(), TypeIndex { type_name: "java/lang/String".into(), index: 0 }); class_field_mapping.insert("java/lang/Class".to_owned(), fields_declared_by_java_lang_class); - classes.insert(3, Class { id: 3, initialized: true, name: "".into(), superclass: None, parents: LinkedList::new(), interfaces: vec![], object_field_mapping: class_field_mapping, static_field_mapping: HashMap::new() }); + classes.insert(3, Class { id: 3, name: "".into(), superclass: None, parents: LinkedList::new(), interfaces: vec![], object_field_mapping: class_field_mapping, static_field_mapping: HashMap::new() }); let mut cm = ClassManager { static_class_data: HashMap::new(), diff --git a/src/vm/array.rs b/src/vm/array.rs index bf8ff8e..ce59db7 100644 --- a/src/vm/array.rs +++ b/src/vm/array.rs @@ -1,6 +1,6 @@ use anyhow::{anyhow, Error}; -use crate::class::ObjectRef; +use crate::class::ObjectRef::*; use crate::class::Value::{self, *}; @@ -13,40 +13,40 @@ pub(crate) fn array_load(index: Value, arrayref: Value) -> Result } if let Ref(objectref) = arrayref { match objectref { - ObjectRef::ByteArray(array) => { + ByteArray(array) => { return Ok(I32(array[index] as i32)); } - ObjectRef::ShortArray(array) => { + ShortArray(array) => { return Ok(I32(array[index] as i32)); } - ObjectRef::IntArray(array) => { + IntArray(array) => { return Ok(I32(array[index])); } - ObjectRef::BooleanArray(array) => { + BooleanArray(array) => { return Ok(I32(array[index] as i32)); } - ObjectRef::CharArray(array) => { + CharArray(array) => { return Ok(CHAR(array[index])); } - ObjectRef::LongArray(array) => { + LongArray(array) => { return Ok(I64(array[index])); } - ObjectRef::FloatArray(array) => { + FloatArray(array) => { return Ok(F32(array[index])); } - ObjectRef::DoubleArray(array) => { + DoubleArray(array) => { return Ok(F64(array[index])); } - ObjectRef::ObjectArray(_arraytype, data) => { + ObjectArray(_arraytype, data) => { return Ok(Ref(data[index].clone())); } - ObjectRef::StringArray(array) => { + StringArray(array) => { return Ok(Utf8(array[index].to_owned())); } - ObjectRef::Class(_) => { + Class(_) => { panic!("should be array") } - ObjectRef::Object(_) => { + Object(_) => { panic!("should be array") } //throw error? } @@ -63,7 +63,7 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result if let I32(index) = index { if let Ref(mut objectref) = arrayref { match objectref { - ObjectRef::ByteArray(ref mut array) => { + ByteArray(ref mut array) => { if let I32(value) = value { // is i32 correct? array[index as usize] = value as i8; @@ -71,7 +71,7 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result unreachable!() } } - ObjectRef::ShortArray(ref mut array) => { + ShortArray(ref mut array) => { if let I32(value) = value { // is i32 correct? array[index as usize] = value as i16; @@ -79,63 +79,63 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result unreachable!() } } - ObjectRef::IntArray(ref mut array) => { + IntArray(ref mut array) => { if let I32(value) = value { array[index as usize] = value; } else { unreachable!() } } - ObjectRef::BooleanArray(ref mut array) => { + BooleanArray(ref mut array) => { if let I32(value) = value { array[index as usize] = value > 0; } else { unreachable!() } } - ObjectRef::CharArray(ref mut array) => unsafe { + CharArray(ref mut array) => unsafe { if let I32(value) = value { array[index as usize] = char::from_u32_unchecked(value as u32); } else { unreachable!() } } - ObjectRef::LongArray(ref mut array) => { + LongArray(ref mut array) => { if let I64(value) = value { array[index as usize] = value; } else { unreachable!() } } - ObjectRef::FloatArray(ref mut array) => { + FloatArray(ref mut array) => { if let F32(value) = value { array[index as usize] = value } else { unreachable!() } } - ObjectRef::DoubleArray(ref mut array) => { + DoubleArray(ref mut array) => { if let F64(value) = value { array[index as usize] = value } else { unreachable!() } } - ObjectRef::ObjectArray(_arraytype, ref mut array) => { + ObjectArray(_arraytype, ref mut array) => { if let Ref(ref value) = value { array[index as usize] = value.clone(); } else { unreachable!() } } - ObjectRef::StringArray(ref mut array) => { + StringArray(ref mut array) => { if let Utf8(ref value) = value { array[index as usize] = value.clone(); } else { unreachable!() } } - ObjectRef::Object(_) | ObjectRef::Class(_) => {} //throw error? + Object(_) | Class(_) => {} //throw error? } } } else { diff --git a/src/vm/native.rs b/src/vm/native.rs index a674551..4d7deaa 100644 --- a/src/vm/native.rs +++ b/src/vm/native.rs @@ -2,13 +2,13 @@ use std::cell::RefCell; use std::rc::Rc; -use anyhow::Error; +use anyhow::{anyhow, Error}; use log::debug; use once_cell::sync::Lazy; use crate::class::{ObjectRef, Value}; use crate::class::ObjectRef::Object; -use crate::class::Value::Void; +use crate::class::Value::{I32, Void}; use crate::classmanager; use crate::vm::stack::StackFrame; use crate::vm::Vm; @@ -17,19 +17,35 @@ pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec, class_name: debug!("native {}.{}", class_name, method_name); match class_name.as_str() { - "java/lang/Class" => java_lang_class(vm, method_name), + "java/lang/Class" => java_lang_Class(vm, method_name), + "java/lang/System" => java_lang_System(vm, method_name), + "jdk/internal/misc/Unsafe" => jdk_internal_misc_Unsafe(vm, method_name), "jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(vm, stackframes, method_name), - _ => Ok(Void) + _ => unimplemented!("") } } -fn java_lang_class(_vm: &Vm, method_name: &str) -> Result { +fn java_lang_Class(_vm: &Vm, method_name: &str) -> Result { Ok(match method_name { "desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false), _ => Void }) } +fn java_lang_System(_vm: &Vm, method_name: &str) -> Result { + Ok(match method_name { + _ => Void + }) +} + +fn jdk_internal_misc_Unsafe(_vm: &Vm, method_name: &str) -> Result { + Ok(match method_name { + "arrayBaseOffset0(Ljava/lang/Class;)I" => I32(0), //TODO surely this is not right + "arrayIndexScale0(Ljava/lang/Class;)I" => I32(0), //TODO surely this is not right + _ => Void + }) +} + fn jdk_internal_util_SystemProps_Raw(vm: &mut Vm, stackframes: &mut Vec, method_name: &str) -> Result { match method_name { "platformProperties()[Ljava/lang/String;" => platformProperties(), diff --git a/src/vm/opcodes.rs b/src/vm/opcodes.rs index 6e087f1..0ed1c6f 100644 --- a/src/vm/opcodes.rs +++ b/src/vm/opcodes.rs @@ -190,17 +190,19 @@ pub const _DUP2_X1: u8 = 93; //(0x5d) Duplicate the top one or two operand stack values and insert two or three values down pub const _DUP2_X2: u8 = 94; // (0x5e) Duplicate the top one or two operand stack values and insert two, three, or four values down -pub const IADD:u8 = 96; +pub const IADD: u8 = 96; pub const _FADD: u8 = 98; // (0x62) Add float pub const _DADD: u8 = 99; // (0x63) add double +pub const ISUB: u8 = 100; pub const _DSUB: u8 = 103; // (0x67) subtract double pub const _FMUL: u8 = 106; // (0x6a) Multiply float -pub const _DMUL: u8 = 107; // (0x6b) Multiply double -pub const IDIV:u8 = 108; +pub const _DMUL: u8 = 107; +// (0x6b) Multiply double +pub const IDIV: u8 = 108; pub const _FDIV: u8 = 110; // (0x6e) Divide float pub const _DDIV: u8 = 111; @@ -212,8 +214,8 @@ pub const _DREM: u8 = 115; pub const _FNEG: u8 = 118; // (0x76) Negate float pub const _DNEG: u8 = 119; // (0x77) Negate double - -pub const ISHR:u8 = 122; +pub const ISHL:u8 = 120; +pub const ISHR: u8 = 122; pub const _F2I: u8 = 139; // (0x8b) Convert float to int pub const _F2L: u8 = 140; @@ -286,7 +288,7 @@ pub const INVOKESTATIC: u8 = 184; // (0xb8) Invoke a class (static) method pub const NEW: u8 = 187; // (0xbb) Create new object -pub const NEWARRAY:u8 = 188; +pub const NEWARRAY: u8 = 188; pub const ANEWARRAY: u8 = 189; // (0xbd) pub const ARRAYLENGTH: u8 = 190; @@ -300,160 +302,162 @@ pub const MONITOREXIT: u8 = 195; pub const IFNULL: u8 = 198; pub const IFNONNULL: u8 = 199; -pub const OPCODES:Lazy> = Lazy::new(|| { - let mut opcodes = vec!["";256]; - opcodes[NOP as usize] = "NOP" ; - opcodes[ACONST_NULL as usize] = "ACONST_NULL" ; - opcodes[ICONST_M1 as usize] = "ICONST_M1" ; - opcodes[ICONST_0 as usize] = "ICONST_0" ; - opcodes[ICONST_1 as usize] = "ICONST_1" ; - opcodes[ICONST_2 as usize] = "ICONST_2" ; - opcodes[ICONST_3 as usize] = "ICONST_3" ; - opcodes[ICONST_4 as usize] = "ICONST_4" ; - opcodes[ICONST_5 as usize] = "ICONST_5" ; - opcodes[LCONST_0 as usize] = "LCONST_0" ; - opcodes[LCONST_1 as usize] = "LCONST_1" ; - opcodes[FCONST_0 as usize] = "FCONST_0" ; - opcodes[FCONST_1 as usize] = "FCONST_1" ; - opcodes[FCONST_2 as usize] = "FCONST_2" ; - opcodes[DCONST_0 as usize] = "DCONST_0" ; - opcodes[DCONST_1 as usize] = "DCONST_1" ; - opcodes[BIPUSH as usize] = "BIPUSH" ; - opcodes[SIPUSH as usize] = "SIPUSH" ; - opcodes[LDC as usize] = "LDC" ; - opcodes[LDC_W as usize] = "LDC_W" ; - opcodes[LDC2_W as usize] = "LDC2_W" ; - opcodes[ILOAD as usize] = "ILOAD" ; - opcodes[LLOAD as usize] = "LLOAD" ; - opcodes[FLOAD as usize] = "FLOAD" ; - opcodes[DLOAD as usize] = "DLOAD" ; - opcodes[ALOAD as usize] = "ALOAD" ; - opcodes[ILOAD_0 as usize] = "ILOAD_0" ; - opcodes[ILOAD_1 as usize] = "ILOAD_1" ; - opcodes[ILOAD_2 as usize] = "ILOAD_2" ; - opcodes[ILOAD_3 as usize] = "ILOAD_3" ; - opcodes[LLOAD_0 as usize] = "LLOAD_0" ; - opcodes[LLOAD_1 as usize] = "LLOAD_1" ; - opcodes[LLOAD_2 as usize] = "LLOAD_2" ; - opcodes[LLOAD_3 as usize] = "LLOAD_3" ; - opcodes[FLOAD_0 as usize] = "FLOAD_0" ; - opcodes[FLOAD_1 as usize] = "FLOAD_1" ; - opcodes[FLOAD_2 as usize] = "FLOAD_2" ; - opcodes[FLOAD_3 as usize] = "FLOAD_3" ; - opcodes[DLOAD_0 as usize] = "DLOAD_0" ; - opcodes[DLOAD_1 as usize] = "DLOAD_1" ; - opcodes[DLOAD_2 as usize] = "DLOAD_2" ; - opcodes[DLOAD_3 as usize] = "DLOAD_3" ; - opcodes[ALOAD_0 as usize] = "ALOAD_0" ; - opcodes[ALOAD_1 as usize] = "ALOAD_1" ; - opcodes[ALOAD_2 as usize] = "ALOAD_2" ; - opcodes[ALOAD_3 as usize] = "ALOAD_3" ; - opcodes[IALOAD as usize] = "IALOAD" ; - opcodes[LALOAD as usize] = "LALOAD" ; - opcodes[FALOAD as usize] = "FALOAD" ; - opcodes[DALOAD as usize] = "DALOAD" ; - opcodes[AALOAD as usize] = "AALOAD" ; - opcodes[BALOAD as usize] = "BALOAD" ; - opcodes[CALOAD as usize] = "CALOAD" ; - opcodes[SALOAD as usize] = "SALOAD" ; - opcodes[ISTORE as usize] = "ISTORE" ; - opcodes[LSTORE as usize] = "LSTORE" ; - opcodes[FSTORE as usize] = "FSTORE" ; - opcodes[DSTORE as usize] = "DSTORE" ; - opcodes[ASTORE as usize] = "ASTORE" ; - opcodes[ISTORE_0 as usize] = "ISTORE_0" ; - opcodes[ISTORE_1 as usize] = "ISTORE_1" ; - opcodes[ISTORE_2 as usize] = "ISTORE_2" ; - opcodes[ISTORE_3 as usize] = "ISTORE_3" ; - opcodes[LSTORE_0 as usize] = "LSTORE_0" ; - opcodes[LSTORE_1 as usize] = "LSTORE_1" ; - opcodes[LSTORE_2 as usize] = "LSTORE_2" ; - opcodes[LSTORE_3 as usize] = "LSTORE_3" ; - opcodes[FSTORE_0 as usize] = "FSTORE_0" ; - opcodes[FSTORE_1 as usize] = "FSTORE_1" ; - opcodes[FSTORE_2 as usize] = "FSTORE_2" ; - opcodes[FSTORE_3 as usize] = "FSTORE_3" ; - opcodes[DSTORE_0 as usize] = "DSTORE_0" ; - opcodes[DSTORE_1 as usize] = "DSTORE_1" ; - opcodes[DSTORE_2 as usize] = "DSTORE_2" ; - opcodes[DSTORE_3 as usize] = "DSTORE_3" ; - opcodes[ASTORE_0 as usize] = "ASTORE_0" ; - opcodes[ASTORE_1 as usize] = "ASTORE_1" ; - opcodes[ASTORE_2 as usize] = "ASTORE_2" ; - opcodes[ASTORE_3 as usize] = "ASTORE_3" ; - opcodes[IASTORE as usize] = "IASTORE" ; - opcodes[LASTORE as usize] = "LASTORE" ; - opcodes[FASTORE as usize] = "FASTORE" ; - opcodes[DASTORE as usize] = "DASTORE" ; - opcodes[AASTORE as usize] = "AASTORE" ; - opcodes[BASTORE as usize] = "BASTORE" ; - opcodes[CASTORE as usize] = "CASTORE" ; - opcodes[SASTORE as usize] = "SASTORE" ; - opcodes[POP as usize] = "POP" ; - opcodes[DUP as usize] = "DUP" ; - opcodes[_DUP_X1 as usize] = "_DUP_X1" ; - opcodes[_DUP_X2 as usize] = "_DUP_X2" ; - opcodes[_DUP2 as usize] = "_DUP2" ; - opcodes[_DUP2_X1 as usize] = "_DUP2_X1" ; - opcodes[_DUP2_X2 as usize] = "_DUP2_X2" ; +pub const OPCODES: Lazy> = Lazy::new(|| { + let mut opcodes = vec![""; 256]; + opcodes[NOP as usize] = "NOP"; + opcodes[ACONST_NULL as usize] = "ACONST_NULL"; + opcodes[ICONST_M1 as usize] = "ICONST_M1"; + opcodes[ICONST_0 as usize] = "ICONST_0"; + opcodes[ICONST_1 as usize] = "ICONST_1"; + opcodes[ICONST_2 as usize] = "ICONST_2"; + opcodes[ICONST_3 as usize] = "ICONST_3"; + opcodes[ICONST_4 as usize] = "ICONST_4"; + opcodes[ICONST_5 as usize] = "ICONST_5"; + opcodes[LCONST_0 as usize] = "LCONST_0"; + opcodes[LCONST_1 as usize] = "LCONST_1"; + opcodes[FCONST_0 as usize] = "FCONST_0"; + opcodes[FCONST_1 as usize] = "FCONST_1"; + opcodes[FCONST_2 as usize] = "FCONST_2"; + opcodes[DCONST_0 as usize] = "DCONST_0"; + opcodes[DCONST_1 as usize] = "DCONST_1"; + opcodes[BIPUSH as usize] = "BIPUSH"; + opcodes[SIPUSH as usize] = "SIPUSH"; + opcodes[LDC as usize] = "LDC"; + opcodes[LDC_W as usize] = "LDC_W"; + opcodes[LDC2_W as usize] = "LDC2_W"; + opcodes[ILOAD as usize] = "ILOAD"; + opcodes[LLOAD as usize] = "LLOAD"; + opcodes[FLOAD as usize] = "FLOAD"; + opcodes[DLOAD as usize] = "DLOAD"; + opcodes[ALOAD as usize] = "ALOAD"; + opcodes[ILOAD_0 as usize] = "ILOAD_0"; + opcodes[ILOAD_1 as usize] = "ILOAD_1"; + opcodes[ILOAD_2 as usize] = "ILOAD_2"; + opcodes[ILOAD_3 as usize] = "ILOAD_3"; + opcodes[LLOAD_0 as usize] = "LLOAD_0"; + opcodes[LLOAD_1 as usize] = "LLOAD_1"; + opcodes[LLOAD_2 as usize] = "LLOAD_2"; + opcodes[LLOAD_3 as usize] = "LLOAD_3"; + opcodes[FLOAD_0 as usize] = "FLOAD_0"; + opcodes[FLOAD_1 as usize] = "FLOAD_1"; + opcodes[FLOAD_2 as usize] = "FLOAD_2"; + opcodes[FLOAD_3 as usize] = "FLOAD_3"; + opcodes[DLOAD_0 as usize] = "DLOAD_0"; + opcodes[DLOAD_1 as usize] = "DLOAD_1"; + opcodes[DLOAD_2 as usize] = "DLOAD_2"; + opcodes[DLOAD_3 as usize] = "DLOAD_3"; + opcodes[ALOAD_0 as usize] = "ALOAD_0"; + opcodes[ALOAD_1 as usize] = "ALOAD_1"; + opcodes[ALOAD_2 as usize] = "ALOAD_2"; + opcodes[ALOAD_3 as usize] = "ALOAD_3"; + opcodes[IALOAD as usize] = "IALOAD"; + opcodes[LALOAD as usize] = "LALOAD"; + opcodes[FALOAD as usize] = "FALOAD"; + opcodes[DALOAD as usize] = "DALOAD"; + opcodes[AALOAD as usize] = "AALOAD"; + opcodes[BALOAD as usize] = "BALOAD"; + opcodes[CALOAD as usize] = "CALOAD"; + opcodes[SALOAD as usize] = "SALOAD"; + opcodes[ISTORE as usize] = "ISTORE"; + opcodes[LSTORE as usize] = "LSTORE"; + opcodes[FSTORE as usize] = "FSTORE"; + opcodes[DSTORE as usize] = "DSTORE"; + opcodes[ASTORE as usize] = "ASTORE"; + opcodes[ISTORE_0 as usize] = "ISTORE_0"; + opcodes[ISTORE_1 as usize] = "ISTORE_1"; + opcodes[ISTORE_2 as usize] = "ISTORE_2"; + opcodes[ISTORE_3 as usize] = "ISTORE_3"; + opcodes[LSTORE_0 as usize] = "LSTORE_0"; + opcodes[LSTORE_1 as usize] = "LSTORE_1"; + opcodes[LSTORE_2 as usize] = "LSTORE_2"; + opcodes[LSTORE_3 as usize] = "LSTORE_3"; + opcodes[FSTORE_0 as usize] = "FSTORE_0"; + opcodes[FSTORE_1 as usize] = "FSTORE_1"; + opcodes[FSTORE_2 as usize] = "FSTORE_2"; + opcodes[FSTORE_3 as usize] = "FSTORE_3"; + opcodes[DSTORE_0 as usize] = "DSTORE_0"; + opcodes[DSTORE_1 as usize] = "DSTORE_1"; + opcodes[DSTORE_2 as usize] = "DSTORE_2"; + opcodes[DSTORE_3 as usize] = "DSTORE_3"; + opcodes[ASTORE_0 as usize] = "ASTORE_0"; + opcodes[ASTORE_1 as usize] = "ASTORE_1"; + opcodes[ASTORE_2 as usize] = "ASTORE_2"; + opcodes[ASTORE_3 as usize] = "ASTORE_3"; + opcodes[IASTORE as usize] = "IASTORE"; + opcodes[LASTORE as usize] = "LASTORE"; + opcodes[FASTORE as usize] = "FASTORE"; + opcodes[DASTORE as usize] = "DASTORE"; + opcodes[AASTORE as usize] = "AASTORE"; + opcodes[BASTORE as usize] = "BASTORE"; + opcodes[CASTORE as usize] = "CASTORE"; + opcodes[SASTORE as usize] = "SASTORE"; + opcodes[POP as usize] = "POP"; + opcodes[DUP as usize] = "DUP"; + opcodes[_DUP_X1 as usize] = "_DUP_X1"; + opcodes[_DUP_X2 as usize] = "_DUP_X2"; + opcodes[_DUP2 as usize] = "_DUP2"; + opcodes[_DUP2_X1 as usize] = "_DUP2_X1"; + opcodes[_DUP2_X2 as usize] = "_DUP2_X2"; opcodes[IADD as usize] = "IADD"; - opcodes[_FADD as usize] = "_FADD" ; - opcodes[_DADD as usize] = "_DADD" ; - opcodes[_DSUB as usize] = "_DSUB" ; - opcodes[_FMUL as usize] = "_FMUL" ; - opcodes[_DMUL as usize] = "_DMUL" ; - opcodes[IDIV as usize] = "IDIV" ; - opcodes[_FDIV as usize] = "_FDIV" ; - opcodes[_DDIV as usize] = "_DDIV" ; - opcodes[_FREM as usize] = "_FREM" ; - opcodes[_DREM as usize] = "_DREM" ; - opcodes[_FNEG as usize] = "_FNEG" ; - opcodes[_DNEG as usize] = "_DNEG" ; - opcodes[ISHR as usize] = "ISHR" ; - opcodes[_F2I as usize] = "_F2I" ; - opcodes[_F2L as usize] = "_F2L" ; - opcodes[_F2D as usize] = "_F2D" ; - opcodes[_D2I as usize] = "_D2I" ; - opcodes[_D2L as usize] = "_D2L" ; - opcodes[_D2F as usize] = "_D2F" ; - opcodes[_FCMPL as usize] = "_FCMPL" ; - opcodes[_FCMPG as usize] = "_FCMPG" ; - opcodes[_DCMPL as usize] = "_DCMPL" ; - opcodes[_DCMPG as usize] = "_DCMPG" ; - opcodes[IFEQ as usize] = "IFEQ" ; - opcodes[IFNE as usize] = "IFNE" ; - opcodes[IFLT as usize] = "IFLT" ; - opcodes[IFGE as usize] = "IFGE" ; - opcodes[IFGT as usize] = "IFGT" ; - opcodes[IFLE as usize] = "IFLE" ; - opcodes[IF_ICMPEQ as usize] = "IF_ICMPEQ" ; - opcodes[IF_ICMPNE as usize] = "IF_ICMPNE" ; - opcodes[IF_ICMPLT as usize] = "IF_ICMPLT" ; - opcodes[IF_ICMPGE as usize] = "IF_ICMPGE" ; - opcodes[IF_ICMPGT as usize] = "IF_ICMPGT" ; - opcodes[IF_ICMPLE as usize] = "IF_ICMPLE" ; - opcodes[GOTO as usize] = "GOTO" ; - opcodes[IRETURN as usize] = "IRETURN" ; - opcodes[FRETURN as usize] = "FRETURN" ; - opcodes[DRETURN as usize] = "DRETURN" ; - opcodes[ARETURN as usize] = "ARETURN" ; - opcodes[RETURN_VOID as usize] = "RETURN_VOID" ; - opcodes[GETSTATIC as usize] = "GETSTATIC" ; - opcodes[PUTSTATIC as usize] = "PUTSTATIC" ; - opcodes[GETFIELD as usize] = "GETFIELD" ; - opcodes[PUTFIELD as usize] = "PUTFIELD" ; - opcodes[INVOKEVIRTUAL as usize] = "INVOKEVIRTUAL" ; - opcodes[INVOKESPECIAL as usize] = "INVOKESPECIAL" ; - opcodes[INVOKESTATIC as usize] = "INVOKESTATIC" ; - opcodes[NEW as usize] = "NEW" ; - opcodes[NEWARRAY as usize] = "NEWARRAY" ; - opcodes[ANEWARRAY as usize] = "ANEWARRAY" ; - opcodes[ARRAYLENGTH as usize] = "ARRAYLENGTH" ; - opcodes[_ATHROW as usize] = "_ATHROW" ; - opcodes[_CHECKCAST as usize] = "_CHECKCAST" ; - opcodes[MONITORENTER as usize] = "MONITORENTER" ; - opcodes[MONITOREXIT as usize] = "MONITOREXIT" ; - opcodes[IFNULL as usize] = "IFNULL" ; - opcodes[IFNONNULL as usize] = "IFNONNULL" ; + opcodes[_FADD as usize] = "_FADD"; + opcodes[_DADD as usize] = "_DADD"; + opcodes[ISUB as usize] = "ISUB"; + opcodes[_DSUB as usize] = "_DSUB"; + opcodes[_FMUL as usize] = "_FMUL"; + opcodes[_DMUL as usize] = "_DMUL"; + opcodes[IDIV as usize] = "IDIV"; + opcodes[_FDIV as usize] = "_FDIV"; + opcodes[_DDIV as usize] = "_DDIV"; + opcodes[_FREM as usize] = "_FREM"; + opcodes[_DREM as usize] = "_DREM"; + opcodes[_FNEG as usize] = "_FNEG"; + opcodes[_DNEG as usize] = "_DNEG"; + opcodes[ISHL as usize] = "ISHL"; + opcodes[ISHR as usize] = "ISHR"; + opcodes[_F2I as usize] = "_F2I"; + opcodes[_F2L as usize] = "_F2L"; + opcodes[_F2D as usize] = "_F2D"; + opcodes[_D2I as usize] = "_D2I"; + opcodes[_D2L as usize] = "_D2L"; + opcodes[_D2F as usize] = "_D2F"; + opcodes[_FCMPL as usize] = "_FCMPL"; + opcodes[_FCMPG as usize] = "_FCMPG"; + opcodes[_DCMPL as usize] = "_DCMPL"; + opcodes[_DCMPG as usize] = "_DCMPG"; + opcodes[IFEQ as usize] = "IFEQ"; + opcodes[IFNE as usize] = "IFNE"; + opcodes[IFLT as usize] = "IFLT"; + opcodes[IFGE as usize] = "IFGE"; + opcodes[IFGT as usize] = "IFGT"; + opcodes[IFLE as usize] = "IFLE"; + opcodes[IF_ICMPEQ as usize] = "IF_ICMPEQ"; + opcodes[IF_ICMPNE as usize] = "IF_ICMPNE"; + opcodes[IF_ICMPLT as usize] = "IF_ICMPLT"; + opcodes[IF_ICMPGE as usize] = "IF_ICMPGE"; + opcodes[IF_ICMPGT as usize] = "IF_ICMPGT"; + opcodes[IF_ICMPLE as usize] = "IF_ICMPLE"; + opcodes[GOTO as usize] = "GOTO"; + opcodes[IRETURN as usize] = "IRETURN"; + opcodes[FRETURN as usize] = "FRETURN"; + opcodes[DRETURN as usize] = "DRETURN"; + opcodes[ARETURN as usize] = "ARETURN"; + opcodes[RETURN_VOID as usize] = "RETURN_VOID"; + opcodes[GETSTATIC as usize] = "GETSTATIC"; + opcodes[PUTSTATIC as usize] = "PUTSTATIC"; + opcodes[GETFIELD as usize] = "GETFIELD"; + opcodes[PUTFIELD as usize] = "PUTFIELD"; + opcodes[INVOKEVIRTUAL as usize] = "INVOKEVIRTUAL"; + opcodes[INVOKESPECIAL as usize] = "INVOKESPECIAL"; + opcodes[INVOKESTATIC as usize] = "INVOKESTATIC"; + opcodes[NEW as usize] = "NEW"; + opcodes[NEWARRAY as usize] = "NEWARRAY"; + opcodes[ANEWARRAY as usize] = "ANEWARRAY"; + opcodes[ARRAYLENGTH as usize] = "ARRAYLENGTH"; + opcodes[_ATHROW as usize] = "_ATHROW"; + opcodes[_CHECKCAST as usize] = "_CHECKCAST"; + opcodes[MONITORENTER as usize] = "MONITORENTER"; + opcodes[MONITOREXIT as usize] = "MONITOREXIT"; + opcodes[IFNULL as usize] = "IFNULL"; + opcodes[IFNONNULL as usize] = "IFNONNULL"; opcodes }); \ No newline at end of file diff --git a/src/vm/operations.rs b/src/vm/operations.rs index 2ba18e2..39d5ed5 100644 --- a/src/vm/operations.rs +++ b/src/vm/operations.rs @@ -1,12 +1,17 @@ +use std::cell::RefCell; use std::collections::HashMap; +use std::rc::Rc; use anyhow::Error; use log::debug; -use crate::class::{Class, Value}; -use crate::classloader::classdef::CpEntry; +use crate::class::{Class, ObjectRef, Value}; +use crate::class::Value::{I32, Ref}; +use crate::classloader::classdef::{CpEntry, Method}; use crate::classmanager; -use crate::vm::vm::{Invocation, MethodSignature}; +use crate::vm::stack::StackFrame; +use crate::vm::Vm; +use crate::vm::vm::{current_frame, Invocation, MethodSignature}; /// the place for opcode implementations that are a bit long @@ -66,6 +71,52 @@ pub(crate) fn get_signature_for_invoke(cp: &HashMap, index: u16) - None } +/// LDC in all varieties (LDC, LDC_W, LDC2_W) +pub(crate) fn load_constant(cp_index: &u16, method: &Method, stackframes: &mut Vec, this_class: &Class){ + let c = method.constant_pool.get(cp_index).unwrap(); + match c { + CpEntry::Integer(i) => { + current_frame(stackframes).push(I32(*i)); + } + CpEntry::Float(f) => { + current_frame(stackframes).push(Value::F32(*f)); + } + CpEntry::Double(d) => { + current_frame(stackframes).push(Value::F64(*d)); + } + CpEntry::StringRef(utf8) => { + //TODO + let string = classmanager::get_classdef(&this_class.id).cp_utf8(utf8); + let string: Vec = string.as_bytes().into(); + classmanager::load_class_by_name("java/lang/String"); + let stringclass = classmanager::get_class_by_name("java/lang/String").unwrap(); + let mut stringinstance = Vm::new_instance(stringclass); + stringinstance.set(stringclass, "java/lang/String", "value", Value::Ref(ObjectRef::new_byte_array(string))); + + debug!("new string \"{}\"", utf8); + + current_frame(stackframes).push(Ref(ObjectRef::Object(Rc::new(RefCell::new(stringinstance))))); + } + CpEntry::Long(l) => { + current_frame(stackframes).push(Value::I64(*l)); + } + CpEntry::ClassRef(utf8_index) => { + let classdef = classmanager::get_classdef(&this_class.id); + let class_name = classdef.cp_utf8(utf8_index); + classmanager::load_class_by_name(class_name); + let klass_id = classmanager::get_classid(class_name); + if let Some(class) = classmanager::get_classobject(klass_id) { + current_frame(stackframes).push(class.clone()); + } else { + unreachable!("should not be here"); + } + } + _ => { + panic!("add variant {:?}", c) + } + } +} + fn get_num_args(signature: &str) -> usize { let mut num = 0; diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 25e9eb7..7b61398 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -7,7 +7,7 @@ use log::{debug, error}; use crate::class::{Class, Object, ObjectRef, Value}; use crate::class::Value::{F32, F64, I32, I64, Null, Ref, Utf8, Void}; -use crate::classloader::classdef::{AttributeType, CpEntry, Modifier}; +use crate::classloader::classdef::{AttributeType, CpEntry, Method, Modifier}; use crate::classloader::io::{read_u16, read_u8}; use crate::classmanager; use crate::classmanager::get_class_by_id; @@ -15,7 +15,7 @@ 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::operations::{get_signature_for_invoke, get_static, load_constant}; use crate::vm::stack::StackFrame; pub struct Vm {} @@ -27,6 +27,8 @@ const PATH_SEPARATOR: char = ':'; #[cfg(target_family = "windows")] const PATH_SEPARATOR: char = ';'; +const MASK_LOWER_5BITS: i32 = 0b00011111; + /// The singlethreaded VM (maybe a future Thread) //TODO goto //TODO error handling @@ -220,83 +222,15 @@ impl Vm { } 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) => { - current_frame(stackframes).push(I32(*i)); - } - CpEntry::Float(f) => { - current_frame(stackframes).push(Value::F32(*f)); - } - CpEntry::Double(d) => { - current_frame(stackframes).push(Value::F64(*d)); - } - CpEntry::StringRef(utf8) => { - //TODO - let string = classmanager::get_classdef(&this_class.id).cp_utf8(utf8); - let string: Vec = string.as_bytes().into(); - classmanager::load_class_by_name("java/lang/String"); - let stringclass = classmanager::get_class_by_name("java/lang/String").unwrap(); - let mut stringinstance = Vm::new_instance(stringclass); - stringinstance.set(stringclass, "java/lang/String", "value", Value::Ref(ObjectRef::new_byte_array(string))); - - debug!("new string \"{}\"", utf8); - - current_frame(stackframes).push(Ref(ObjectRef::Object(Rc::new(RefCell::new(stringinstance))))); - } - CpEntry::Long(l) => { - current_frame(stackframes).push(Value::I64(*l)); - } - CpEntry::ClassRef(utf8) => { - 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) { - current_frame(stackframes).push(class.clone()); - } else { - unreachable!("should not be here"); - } - } - _ => { - panic!("add variant {:?}", c) - } - } + load_constant(&cp_index, method, stackframes, this_class); } LDC_W => { let cp_index = read_u16(&code.opcodes, pc); - let cp_entry = method.constant_pool.get(&cp_index).unwrap(); - match cp_entry { - CpEntry::Integer(i) => { - current_frame(stackframes).push(I32(*i)); - } - CpEntry::Float(f) => { - current_frame(stackframes).push(F32(*f)); - } - CpEntry::StringRef(utf8_index) => { - if let CpEntry::Utf8(s) = method.constant_pool.get(utf8_index).unwrap() { - current_frame(stackframes).push(Utf8(s.to_owned())); - } else {} - } - _ => { - error!("{:?}", cp_entry); - unreachable!() - } - } + load_constant(&cp_index, method, stackframes, this_class); } LDC2_W => { let cp_index = read_u16(&code.opcodes, pc); - match method.constant_pool.get(&cp_index).unwrap() { - CpEntry::Double(d) => { - current_frame(stackframes).push(Value::F64(*d)); - } - CpEntry::Long(l) => { - current_frame(stackframes).push(Value::I64(*l)); - } - _ => { - unreachable!() - } - } + load_constant(&cp_index, method, stackframes, this_class); } ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => { // omitting the type checks so far @@ -362,16 +296,28 @@ impl Vm { debug!("{:?}+{:?}", value1, value2); current_frame(stackframes).push(I32(value1.into_i32() + value2.into_i32())); } + ISUB => { + let value2 = current_frame(stackframes).pop()?; + let value1 = current_frame(stackframes).pop()?; + debug!("{:?}-{:?}", value1, value2); + current_frame(stackframes).push(I32(value1.into_i32() - value2.into_i32())); + } IDIV => { let value2 = current_frame(stackframes).pop()?; let value1 = current_frame(stackframes).pop()?; current_frame(stackframes).push(I32(value1.into_i32() / value2.into_i32())); } + ISHL => { + let value2 = current_frame(stackframes).pop()?; + let value1 = current_frame(stackframes).pop()?; + debug!("{:?} shl {:?}", value1, value2); + current_frame(stackframes).push(I32(value1.into_i32() << (value2.into_i32() & MASK_LOWER_5BITS))); + } ISHR => { let value2 = current_frame(stackframes).pop()?; let value1 = current_frame(stackframes).pop()?; debug!("{:?} shr {:?}", value1, value2); - current_frame(stackframes).push(I32(value1.into_i32() >> (value2.into_i32() & 0b00011111))); + current_frame(stackframes).push(I32(value1.into_i32() >> (value2.into_i32() & MASK_LOWER_5BITS))); } IFEQ | IFNE | IFLT | IFGE | IFGT | IFLE => { let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode @@ -715,7 +661,7 @@ impl MethodSignature { } } -fn current_frame(stackframes: &mut Vec) -> &mut StackFrame { +pub(crate) fn current_frame(stackframes: &mut Vec) -> &mut StackFrame { let i = stackframes.len() - 1; stackframes.get_mut(i).unwrap() } \ No newline at end of file