From 92a4fa96a39b1adf04e70818a8ab3794964d7fd5 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Fri, 10 Nov 2023 23:32:00 +0100 Subject: [PATCH] lot of bugfixes --- Cargo.lock | 52 +++++++- Cargo.toml | 3 +- src/class.rs | 32 +++-- src/classloader/io.rs | 1 - src/classloader/mod.rs | 2 +- src/classmanager.rs | 91 ++++++++++++-- src/vm/native.rs | 12 +- src/vm/stack.rs | 4 - src/vm/vm.rs | 279 ++++++++++++++++++++--------------------- tests/class_tests.rs | 32 +++-- 10 files changed, 309 insertions(+), 199 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07a064c..bed9745 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -217,6 +217,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "hermit-abi" version = "0.3.3" @@ -266,6 +277,7 @@ dependencies = [ "env_logger", "log", "once_cell", + "rand", "whoami", "zip", ] @@ -290,9 +302,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.148" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linux-raw-sys" @@ -356,6 +368,12 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.67" @@ -374,11 +392,35 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] [[package]] name = "regex" @@ -525,6 +567,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" version = "0.2.87" diff --git a/Cargo.toml b/Cargo.toml index ce2189f..2e36e53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,5 @@ once_cell = { version = "1.18.0", features = [] } zip = { version = "0.6", features = ["zstd"] } log = "0.4" env_logger = "0.10" -whoami = "1.4.1" \ No newline at end of file +whoami = "1.4.1" +rand="0.8" \ No newline at end of file diff --git a/src/class.rs b/src/class.rs index 63d0109..bdb2d7b 100644 --- a/src/class.rs +++ b/src/class.rs @@ -1,4 +1,9 @@ +use std::cell::RefCell; use std::collections::{HashMap, LinkedList}; +use std::rc::Rc; + +use log::debug; +use rand::random; use crate::class::ObjectRef::*; @@ -41,7 +46,7 @@ impl Class { .iter() .map(|(_, v)| v.len()) .reduce(|acc, e| acc + e) - .unwrap() + .unwrap_or(0) } } @@ -71,7 +76,7 @@ impl Value { if let Value::I32(v) = self { v } else { - panic!(); + panic!("{:?} is not I32", self); } } @@ -96,7 +101,7 @@ pub enum ObjectRef { CharArray(Vec), StringArray(Vec), ObjectArray(ClassId, Vec), - Object(Object), + Object(Rc>), //Box necessary?? Class(Class), } @@ -170,10 +175,11 @@ fn into_vec_i8(v: Vec) -> Vec { unsafe { Vec::from_raw_parts(p as *mut i8, len, cap) } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Object { // locked: bool, // hashcode: i32, + pub id: u32, pub class_id: ClassId, pub data: Vec, } //arrays @@ -183,6 +189,7 @@ impl Object { pub fn new(class: &Class) -> Self { let instance_data = Object::init_fields(class); Self { + id: random(), class_id: class.id, data: instance_data, } @@ -190,7 +197,7 @@ impl Object { // 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()); + let mut field_data = vec![Value::Null;class.n_object_fields()]; for (_, fields) in &class.object_field_mapping { for (_, type_index) in fields { @@ -204,15 +211,16 @@ impl Object { "D" => Value::F64(0.0), _ => Value::Null, }; - field_data.push(value.into()); + field_data[type_index.index] = value.into(); } } field_data } - pub fn set(&mut self, class: &Class, declared_type: &str, field_name: &str, value: Value) { - let type_index = class + pub fn set(&mut self, runtime_type: &Class, declared_type: &str, field_name: &str, value: Value) { + debug!("set {:?}.{}", runtime_type.name, field_name); + let type_index = runtime_type .object_field_mapping .get(declared_type) .unwrap() @@ -221,14 +229,16 @@ impl Object { self.data[type_index.index] = value; } - pub fn get(&mut self, instancedef: &Class, declared_type: &String, field_name: &String) -> &Value { - let type_index = instancedef + pub fn get(&self, runtime_type: &Class, declared_type: &String, field_name: &String) -> &Value { + let type_index = runtime_type .object_field_mapping .get(declared_type) .unwrap() .get(field_name) .unwrap(); - &self.data[type_index.index] + debug!("get {:?}:{}.{}:{} @{}", runtime_type, declared_type, field_name, type_index.type_name, type_index.index); + debug!("from data {:?}", self.data); + self.data.get(type_index.index).unwrap() } // fn get_field_name(&self, cp_index: &u16) -> &str { diff --git a/src/classloader/io.rs b/src/classloader/io.rs index 1eee757..ef195a5 100644 --- a/src/classloader/io.rs +++ b/src/classloader/io.rs @@ -33,7 +33,6 @@ pub fn find_class(classpath: &Vec, class_name: &str) -> Result CpEntry { let tag = read_u8(bytecode, index); - // println!("tag {}", tag); + // debug!("tag {}", tag); match tag { 1 => { let len = read_u16(bytecode, index) as usize; diff --git a/src/classmanager.rs b/src/classmanager.rs index 718d60e..3ed686e 100644 --- a/src/classmanager.rs +++ b/src/classmanager.rs @@ -1,4 +1,6 @@ +use std::cell::RefCell; use std::collections::{HashMap, LinkedList}; +use std::rc::Rc; use log::debug; use once_cell::sync::Lazy; @@ -27,7 +29,7 @@ pub fn set_classpath(classpath: &str) { } } -pub fn get_class_by_id(id: ClassId) -> Option<&'static Class> { +pub fn get_class_by_id(id: &ClassId) -> Option<&'static Class> { unsafe { CLASSMANAGER.get_class_by_id(id) } @@ -127,14 +129,14 @@ impl ClassManager { .collect(); } - fn get_class_by_id(&mut self, id: ClassId) -> Option<&Class> { - if !self.classes.contains_key(&id) { - let name = self.classdef_name(&id); + 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) + self.classes.get(id) } fn classdef_name(&self, id: &ClassId) -> Option { @@ -156,7 +158,6 @@ impl ClassManager { self.add_class(name); } None => { - self.add_class(name); } } @@ -212,14 +213,13 @@ impl ClassManager { 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)); + let instance = Ref(ObjectRef::Object(Rc::new(RefCell::new(instance)))); self.class_objects.insert(this_classid, instance); } @@ -234,8 +234,8 @@ impl ClassManager { 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, + 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(); @@ -295,7 +295,6 @@ impl ClassManager { "D" => F64(0.0), _ => Null, }; - // println!("{} = {:?}", name, value); field_data[type_index.index] = value.into(); } } @@ -322,4 +321,74 @@ pub(crate) fn inspect_dependencies(classdef: &ClassDef) -> Vec { classes_to_load.push(classdef.cp_class_name(interface).into()); } classes_to_load +} + +#[cfg(test)] +mod test { + use std::rc::Rc; + use crate::classloader::classdef::{CpEntry, Field}; + use super::*; + + #[test] + fn add_class() { + let mut names = HashMap::new(); + names.insert("C".to_owned(), 1); + names.insert("java/lang/String".to_owned(), 2); + names.insert("java/lang/Class".to_owned(), 3); + + let mut constant_pool = HashMap::new(); + constant_pool.insert(0, CpEntry::ClassRef(1)); + constant_pool.insert(1, CpEntry::Utf8("C".into())); + constant_pool.insert(2, CpEntry::NameAndType(3, 4)); + constant_pool.insert(3, CpEntry::Utf8("name".into())); + constant_pool.insert(4, CpEntry::Utf8("java/lang/String".into())); + constant_pool.insert(5, CpEntry::Utf8("Ljava/lang/String;".into())); + constant_pool.insert(6, CpEntry::ClassRef(4)); + constant_pool.insert(7, CpEntry::Utf8("java/lang/Class".into())); + constant_pool.insert(8, CpEntry::ClassRef(7)); + constant_pool.insert(9, CpEntry::Utf8("value1".into())); + constant_pool.insert(10, CpEntry::Utf8("value2".into())); + let constant_pool = Rc::new(constant_pool); + + // give class C a fields called value + let mut c_fields = HashMap::new(); + c_fields.insert("value1".to_owned(), Field::new(constant_pool.clone(), 0, 9, 5, HashMap::new(), 0)); + c_fields.insert("value2".to_owned(), Field::new(constant_pool.clone(), 0, 10, 5, HashMap::new(), 0)); + + // Class needs a public (non-static) field called name + let mut class_fields = HashMap::new(); + class_fields.insert("name".to_owned(), Field::new(constant_pool.clone(), 1, 2, 5, HashMap::new(), 0)); + + let mut classdefs = HashMap::new(); + classdefs.insert(1, ClassDef::new(0, 0, constant_pool.clone(), 0, 0, None, vec![], c_fields, HashMap::new(), HashMap::new())); + + // preload java.lang.String + classdefs.insert(2, ClassDef::new(0, 0, constant_pool.clone(), 0, 6, None, vec![], HashMap::new(), HashMap::new(), HashMap::new())); + + // preload java.lang.Class + classdefs.insert(3, ClassDef::new(0, 0, constant_pool, 0, 8, None, vec![], class_fields, HashMap::new(), HashMap::new())); + let mut classes = HashMap::new(); + let mut class_field_mapping = HashMap::new(); + 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() }); + + let mut cm = ClassManager { + static_class_data: HashMap::new(), + classes, + class_objects: HashMap::new(), + classdefs, + current_id: 1, + names, + classpath: Vec::new(), + vm: Vm::new(&mut vec![]), + }; + + let c_id = cm.add_class("C"); + let loaded_class = cm.classes.get(&c_id).unwrap(); + + assert_eq!(0, loaded_class.object_field_mapping.get("C").unwrap().get("value1").unwrap().index); + assert_eq!(1, loaded_class.object_field_mapping.get("C").unwrap().get("value2").unwrap().index); + } } \ No newline at end of file diff --git a/src/vm/native.rs b/src/vm/native.rs index e1e1441..a674551 100644 --- a/src/vm/native.rs +++ b/src/vm/native.rs @@ -1,7 +1,9 @@ #![allow(non_snake_case)] +use std::cell::RefCell; +use std::rc::Rc; use anyhow::Error; -use log::{debug, info}; +use log::debug; use once_cell::sync::Lazy; use crate::class::{ObjectRef, Value}; @@ -41,14 +43,14 @@ fn cmdProps(vm: &mut Vm, stackframes: &mut Vec) -> Result()V", vec![hashmap.clone()]); + let hashmap = Value::Ref(Object(Rc::new(RefCell::new(hashmap)))); + vm.execute_special(stackframes, "java/util/HashMap", "()V", vec![hashmap.clone()])?; Ok(hashmap) } -fn vmProperties(vm: &mut Vm, stackframes: &mut Vec) -> Result { +fn vmProperties(_vm: &mut Vm, _stackframes: &mut Vec) -> Result { let props: Lazy> = Lazy::new(|| { - let mut vec: Vec = Vec::new(); + let vec: Vec = Vec::new(); //TODO insert some values vec }); diff --git a/src/vm/stack.rs b/src/vm/stack.rs index f741e42..9a2dfbe 100644 --- a/src/vm/stack.rs +++ b/src/vm/stack.rs @@ -23,10 +23,6 @@ impl StackFrame { 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 f4b8da1..25e9eb7 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -1,13 +1,16 @@ +use std::cell::RefCell; use std::io::Write; +use std::rc::Rc; use anyhow::Error; -use log::debug; +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::io::{read_u16, read_u8}; use crate::classmanager; +use crate::classmanager::get_class_by_id; use crate::vm::array::{array_load, array_store}; use crate::vm::native::invoke_native; use crate::vm::opcodes; @@ -38,7 +41,7 @@ impl Vm { .format(|buf, record| { writeln!(buf, "{}: {}", record.level(), record.args()) }) - .try_init(); + .try_init().unwrap(); let mut vm_instance = Self {}; classmanager::init(); Vm::init(&mut vm_instance, stack); @@ -48,13 +51,6 @@ impl Vm { fn init(vm: &mut Vm, stack: &mut Vec) { classmanager::load_class_by_name("java/lang/Class"); vm.execute_static(stack, "java/lang/System", "initPhase1()V", vec![]).expect("cannot create VM"); - // classmanager::load_class_by_name("java/lang/String"); - } - - - 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 { @@ -82,22 +78,25 @@ impl Vm { } if let Ref(this) = &args[0] { if let ObjectRef::Object(this) = this { - let cd = classmanager::get_classdef(&this.class_id); + let thisb= this.borrow(); + let cd = classmanager::get_classdef(&thisb.class_id); let method = cd.get_method(method_name); if let Some(method) = method { classmanager::load_class_by_name(class_name); let class = classmanager::get_class_by_name(class_name).unwrap(); return self.execute_class(stack, class, method.name().as_str(), args.clone()); } else { - let name = classmanager::classdef_name(&this.class_id); + let name = classmanager::classdef_name(&this.borrow().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(stack, class, method_name, args); - } else { - debug!("not {:?}", parent_id); + let classdef = classmanager::get_classdef(parent_id); + let method = classdef.get_method(method_name); + if let Some(_) = method { + let class= get_class_by_id(parent_id).unwrap(); + return self.execute_class(stack, class, method_name, args.clone()); } } } else { @@ -163,98 +162,90 @@ impl Vm { let pc = &mut 0; while *pc < code.opcodes.len() { let opcode = read_u8(&code.opcodes, pc); - let cur_frame = Self::current_frame(stackframes); - debug!("\t{} #{} {} - {}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.len()); + let cur_frame = current_frame(stackframes); + debug!("\t{} #{} {} - {:?}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.data); match opcode { ACONST_NULL => { - Self::current_frame(stackframes).push(Value::Null); + current_frame(stackframes).push(Value::Null); } ICONST_M1 => { - Self::current_frame(stackframes).push(I32(-1)); + current_frame(stackframes).push(I32(-1)); } ICONST_0 => { - Self::current_frame(stackframes).push(I32(0)); + current_frame(stackframes).push(I32(0)); } ICONST_1 => { - Self::current_frame(stackframes).push(I32(1)); + current_frame(stackframes).push(I32(1)); } ICONST_2 => { - Self::current_frame(stackframes).push(I32(2)); + current_frame(stackframes).push(I32(2)); } ICONST_3 => { - Self::current_frame(stackframes).push(I32(3)); + current_frame(stackframes).push(I32(3)); } ICONST_4 => { - Self::current_frame(stackframes).push(I32(4)); + current_frame(stackframes).push(I32(4)); } ICONST_5 => { - Self::current_frame(stackframes).push(I32(5)); + current_frame(stackframes).push(I32(5)); } LCONST_0 => { - Self::current_frame(stackframes).push(I64(0)); + current_frame(stackframes).push(I64(0)); } LCONST_1 => { - Self::current_frame(stackframes).push(I64(1)); + current_frame(stackframes).push(I64(1)); } FCONST_0 => { - Self::current_frame(stackframes).push(F32(0.0)); + current_frame(stackframes).push(F32(0.0)); } FCONST_1 => { - Self::current_frame(stackframes).push(F32(1.0)); + current_frame(stackframes).push(F32(1.0)); } FCONST_2 => { - Self::current_frame(stackframes).push(F32(2.0)); + current_frame(stackframes).push(F32(2.0)); } DCONST_0 => { - Self::current_frame(stackframes).push(F64(0.0)); + current_frame(stackframes).push(F64(0.0)); } DCONST_1 => { - Self::current_frame(stackframes).push(F64(1.0)); + current_frame(stackframes).push(F64(1.0)); } SIPUSH => { let s = read_u16(&code.opcodes, pc) as i32; - Self::current_frame(stackframes).push(I32(s)); + current_frame(stackframes).push(I32(s)); } BIPUSH => { let c = read_u8(&code.opcodes, pc) as i32; - Self::current_frame(stackframes).push(I32(c)); + 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(stackframes).push(I32(*i)); + current_frame(stackframes).push(I32(*i)); } CpEntry::Float(f) => { - Self::current_frame(stackframes).push(Value::F32(*f)); + current_frame(stackframes).push(Value::F32(*f)); } CpEntry::Double(d) => { - Self::current_frame(stackframes).push(Value::F64(*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 stringinstance = - Ref(ObjectRef::Object(Vm::new_instance(stringclass))); + let mut stringinstance = Vm::new_instance(stringclass); + stringinstance.set(stringclass, "java/lang/String", "value", Value::Ref(ObjectRef::new_byte_array(string))); - // let string = classmanager::get_classdef(&this_class.id).cp_utf8(utf8); debug!("new string \"{}\"", utf8); - // let string: Vec = string.as_bytes().into(); - // self.execute_special(stackframes, - // "java/lang/String", - // "([B)V", - // vec![ - // stringinstance.clone(), - // Ref(ObjectRef::new_byte_array(string)), - // ], - // )?; - Self::current_frame(stackframes).push(stringinstance); + current_frame(stackframes).push(Ref(ObjectRef::Object(Rc::new(RefCell::new(stringinstance))))); } CpEntry::Long(l) => { - Self::current_frame(stackframes).push(Value::I64(*l)); + current_frame(stackframes).push(Value::I64(*l)); } CpEntry::ClassRef(utf8) => { let classdef = classmanager::get_classdef(&this_class.id); @@ -262,7 +253,7 @@ impl Vm { 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()); + current_frame(stackframes).push(class.clone()); } else { unreachable!("should not be here"); } @@ -277,18 +268,18 @@ impl Vm { let cp_entry = method.constant_pool.get(&cp_index).unwrap(); match cp_entry { CpEntry::Integer(i) => { - Self::current_frame(stackframes).push(I32(*i)); + current_frame(stackframes).push(I32(*i)); } CpEntry::Float(f) => { - Self::current_frame(stackframes).push(F32(*f)); + 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(stackframes).push(Utf8(s.to_owned())); + current_frame(stackframes).push(Utf8(s.to_owned())); } else {} } _ => { - println!("{:?}", cp_entry); + error!("{:?}", cp_entry); unreachable!() } } @@ -297,10 +288,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(stackframes).push(Value::F64(*d)); + current_frame(stackframes).push(Value::F64(*d)); } CpEntry::Long(l) => { - Self::current_frame(stackframes).push(Value::I64(*l)); + current_frame(stackframes).push(Value::I64(*l)); } _ => { unreachable!() @@ -310,29 +301,29 @@ 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(stackframes) + current_frame(stackframes) .push(local_params[n].as_ref().unwrap().clone()); } ILOAD_0 | LLOAD_0 | FLOAD_0 | DLOAD_0 | ALOAD_0 => { - Self::current_frame(stackframes) + current_frame(stackframes) .push(local_params[0].as_ref().unwrap().clone()); } ILOAD_1 | LLOAD_1 | FLOAD_1 | DLOAD_1 | ALOAD_1 => { - Self::current_frame(stackframes) + current_frame(stackframes) .push(local_params[1].as_ref().unwrap().clone()); } ILOAD_2 | LLOAD_2 | FLOAD_2 | DLOAD_2 | ALOAD_2 => { - Self::current_frame(stackframes) + current_frame(stackframes) .push(local_params[2].as_ref().unwrap().clone()); } ILOAD_3 | LLOAD_3 | FLOAD_3 | DLOAD_3 | ALOAD_3 => { - Self::current_frame(stackframes) + current_frame(stackframes) .push(local_params[3].as_ref().unwrap().clone()); } 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)?); + let index = current_frame(stackframes).pop()?; + let arrayref = current_frame(stackframes).pop()?; + current_frame(stackframes).push(array_load(index, arrayref)?); } ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => { let index = read_u8(&code.opcodes, pc) as usize; @@ -352,49 +343,55 @@ impl Vm { } BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE | AASTORE => { - let value = Self::current_frame(stackframes).pop()?; - let index = Self::current_frame(stackframes).pop()?; - let arrayref = Self::current_frame(stackframes).pop()?; + let value = current_frame(stackframes).pop()?; + let index = current_frame(stackframes).pop()?; + let arrayref = current_frame(stackframes).pop()?; array_store(value, index, arrayref)? } POP => { - Self::current_frame(stackframes).pop()?; + current_frame(stackframes).pop()?; } DUP => { - let value = Self::current_frame(stackframes).pop()?; - Self::current_frame(stackframes).push(value.clone()); - Self::current_frame(stackframes).push(value); + let value = current_frame(stackframes).pop()?; + current_frame(stackframes).push(value.clone()); + current_frame(stackframes).push(value); } IADD => { - let stack = Self::current_frame(stackframes); - let value2 = stack.pop()?; - let value1 = stack.pop()?; - stack.push(I32(value1.into_i32() + value2.into_i32())); + 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 = Self::current_frame(stackframes).pop()?; - let value1 = Self::current_frame(stackframes).pop()?; - Self::current_frame(stackframes).push(I32(value1.into_i32() / value2.into_i32())); + let value2 = current_frame(stackframes).pop()?; + let value1 = current_frame(stackframes).pop()?; + current_frame(stackframes).push(I32(value1.into_i32() / value2.into_i32())); + } + 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))); } - 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(stackframes).pop()?; + let value = 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(stackframes).pop()?; - let value2 = Self::current_frame(stackframes).pop()?; + let value1 = current_frame(stackframes).pop()?; + let value2 = 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; + debug!("GOTO {}", *pc) } IRETURN | FRETURN | DRETURN | ARETURN => { - let result = Self::current_frame(stackframes).pop(); + let result = current_frame(stackframes).pop(); stackframes.pop(); return result; } @@ -406,7 +403,7 @@ impl Vm { let field_index = read_u16(&code.opcodes, pc); let field_value = get_static(this_class, field_index)?; - Self::current_frame(stackframes).push(field_value); + current_frame(stackframes).push(field_value); } PUTSTATIC => { let classdef = classmanager::get_classdef(&this_class.id); @@ -416,29 +413,16 @@ impl Vm { let (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 &this_class.name == that_class_name { - // may have to apply this in GETSTATIC too - this_class - .static_field_mapping - .get(that_class_name) - .unwrap() - .get(name) - .unwrap() - .index - } else { - 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(stackframes).pop()?; + let that_class_name_index = classdef.cp_class_ref(class_index); + let that_class_name = classdef.cp_utf8(that_class_name_index); + let that_class = classmanager::get_class_by_name(that_class_name).unwrap(); + let val_index = that_class.static_field_mapping + .get(that_class_name) + .unwrap() + .get(name) + .unwrap() + .index; + let value = current_frame(stackframes).pop()?; classmanager::set_static(&this_class.id, val_index, value); } GETFIELD => { @@ -450,13 +434,16 @@ impl Vm { 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(stackframes).pop()?; + let field_name = classdef.cp_utf8(field_name_index); + debug!("get field {}.{}",declared_type, field_name); + let objectref = current_frame(stackframes).pop()?; if let Ref(instance) = objectref { - if let ObjectRef::Object(mut object) = instance { - let value = object.get(this_class, declared_type, field_name); - Self::current_frame(stackframes).push(value.clone()); + if let ObjectRef::Object(object) = instance { + let runtime_type = classmanager::get_class_by_id(&object.borrow().class_id).unwrap(); + let object = object.borrow(); + let value = object.get(runtime_type, declared_type, field_name); + current_frame(stackframes).push(value.clone()); } else { unreachable!() } @@ -475,11 +462,12 @@ impl Vm { let declared_type = classdef.cp_utf8(class_name_index); let field_name = classdef.cp_utf8(field_name_index); - let value = Self::current_frame(stackframes).pop()?; - let objectref = Self::current_frame(stackframes).pop()?; + let value = current_frame(stackframes).pop()?; + let objectref = current_frame(stackframes).pop()?; if let Ref(instance) = objectref { - if let ObjectRef::Object(mut object) = instance { - object.set(this_class, declared_type, field_name, value); + if let ObjectRef::Object(object) = instance { + let runtime_type = classmanager::get_class_by_id(&object.borrow().class_id).unwrap(); + object.borrow_mut().set(runtime_type, declared_type, field_name, value); } } else { unreachable!() @@ -494,9 +482,9 @@ impl Vm { debug!("invoke {:?}", invocation); 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, current_frame(stackframes).pop()?.clone()); } - args.insert(0, Self::current_frame(stackframes).pop()?); + args.insert(0, current_frame(stackframes).pop()?); let return_value = self.execute_special(stackframes, &invocation.class_name, &invocation.method.name, @@ -512,10 +500,9 @@ impl Vm { match return_value { Void => {} _ => { - Self::current_frame(stackframes).push(return_value.clone()); + current_frame(stackframes).push(return_value.clone()); } } - // println!("stack {} at {}", Self::current_frame(stack).len(), Self::current_frame(stack).at) } else { unreachable!() } @@ -529,9 +516,9 @@ impl Vm { debug!("invoke {:?}", invocation); 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, current_frame(stackframes).pop()?.clone()); } - args.insert(0, Self::current_frame(stackframes).pop()?); + args.insert(0, current_frame(stackframes).pop()?); let return_value = self.execute_virtual( stackframes, &invocation.class_name, @@ -548,7 +535,7 @@ impl Vm { match return_value { Void => {} _ => { - Self::current_frame(stackframes).push(return_value.clone()); + current_frame(stackframes).push(return_value.clone()); } } } else { @@ -562,7 +549,7 @@ impl Vm { { 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, current_frame(stackframes).pop()?.clone()); } let return_value = self.execute_static(stackframes, &invocation.class_name, @@ -579,7 +566,7 @@ impl Vm { match return_value { Void => {} _ => { - Self::current_frame(stackframes).push(return_value.clone()); + current_frame(stackframes).push(return_value.clone()); } } } else { @@ -594,16 +581,16 @@ impl Vm { classmanager::load_class_by_name(class_name); let class_to_instantiate = classmanager::get_class_by_name(class_name).unwrap(); - let object = ObjectRef::Object(Vm::new_instance( + let object = ObjectRef::Object(Rc::new(RefCell::new(Vm::new_instance( class_to_instantiate, - )); - Self::current_frame(stackframes).push(Ref(object)); + )))); + current_frame(stackframes).push(Ref(object)); } - NEWARRAY =>{ + NEWARRAY => { let arraytype = read_u8(&code.opcodes, pc); - let count = Self::current_frame(stackframes).pop()?; + let count = current_frame(stackframes).pop()?; let array = ObjectRef::new_array(arraytype, count.into_i32() as usize); - Self::current_frame(stackframes).push(Ref(array)); + current_frame(stackframes).push(Ref(array)); } ANEWARRAY => { let classdef = classmanager::get_classdef(&this_class.id); @@ -612,26 +599,24 @@ impl Vm { 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(Ref(array)); - } else { - panic!(); - } + let count = current_frame(stackframes).pop()?.into_i32(); + let array = ObjectRef::new_object_array(arraytype, count as usize); + current_frame(stackframes).push(Ref(array)); } ARRAYLENGTH => { - let val = Self::current_frame(stackframes).pop()?; + let val = current_frame(stackframes).pop()?; if let Ref(val) = val { - Self::current_frame(stackframes).push(I32(val.get_array_length() as i32)); + current_frame(stackframes).push(I32(val.get_array_length() as i32)); + } else { + unreachable!("array length {:?}", val); } } MONITORENTER | MONITOREXIT => { - Self::current_frame(stackframes).pop()?; + current_frame(stackframes).pop()?; } //TODO implement IFNULL | IFNONNULL => { let jmp_to = read_u16(&code.opcodes, pc) - 3; - let value = Self::current_frame(stackframes).pop()?; + let value = current_frame(stackframes).pop()?; let its_null = if let Null = value { true } else { false }; if its_null && opcode == IFNULL { @@ -691,7 +676,7 @@ impl Vm { local_params: &mut Vec>, index: usize, ) -> Result<(), Error> { - let value = Self::current_frame(stack).pop()?; + let value = current_frame(stack).pop()?; while local_params.len() < index + 1 { local_params.push(None); } @@ -730,3 +715,7 @@ impl MethodSignature { } } +fn current_frame(stackframes: &mut Vec) -> &mut StackFrame { + let i = stackframes.len() - 1; + stackframes.get_mut(i).unwrap() +} \ No newline at end of file diff --git a/tests/class_tests.rs b/tests/class_tests.rs index e63b942..68d881b 100644 --- a/tests/class_tests.rs +++ b/tests/class_tests.rs @@ -8,15 +8,13 @@ mod test { 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 { - // internally a boolean is an int - assert_eq!(0, b); - } else { - println!("{:?}", ret); - assert!(false) - } + let ret = vm.execute_virtual(&mut stackframes, "testclasses.IfCmp", "i_is_1()Z", vec![]).unwrap(); + if let Value::I32(b) = ret { + // internally a boolean is an int + assert_eq!(0, b); + } else { + println!("{:?}", ret); + assert!(false) } } @@ -28,16 +26,14 @@ mod test { let ret = vm .execute_static(&mut stackframes, "testclasses.Const", "hello()Ljava/lang/String;", vec![]) .unwrap(); - unsafe { - if let Value::Ref(s) = ret { - // internally a boolean is an int - if let ObjectRef::Object(a) = s { - println!("{:?}", a); - } - } else { - println!("{:?}", ret); - assert!(false) + if let Value::Ref(s) = ret { + // internally a boolean is an int + if let ObjectRef::Object(a) = s { + println!("{:?}", a); } + } else { + println!("{:?}", ret); + assert!(false) } } }