diff --git a/src/class.rs b/src/class.rs index cd5b30b..2049791 100644 --- a/src/class.rs +++ b/src/class.rs @@ -1,7 +1,9 @@ use std::collections::HashMap; use std::fmt; use std::rc::Rc; +use std::sync::Arc; use crate::classloader::CpEntry; +use crate::heap::Object; use crate::io::read_u16; @@ -222,4 +224,5 @@ pub enum Value { F64(f64), BOOL(bool), CHAR(char), + Ref(Arc) } \ No newline at end of file diff --git a/src/classloader.rs b/src/classloader.rs index 5f3c7fa..ff44671 100644 --- a/src/classloader.rs +++ b/src/classloader.rs @@ -143,8 +143,8 @@ fn read_constant_pool_entry(cp_index: &mut u16, index: &mut usize, bytecode: &[u CpEntry::InterfaceMethodref(class_index, name_and_type_index) } 12 => { - let name_index = read_u16(bytecode, *index + 1) as usize; - let descriptor_index = read_u16(bytecode, *index + 3) as usize; + let name_index = read_u16(bytecode, *index + 1); + let descriptor_index = read_u16(bytecode, *index + 3); *index += 5; CpEntry::NameAndType(name_index, descriptor_index) } @@ -264,6 +264,6 @@ pub enum CpEntry { Fieldref(u16, u16), MethodRef(u16, u16), InterfaceMethodref(u16, u16), - NameAndType(usize, usize), + NameAndType(u16, u16), } diff --git a/src/heap.rs b/src/heap.rs index 0a35833..0a02971 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -1,16 +1,18 @@ use std::collections::HashMap; use std::rc::Rc; +use std::sync::Arc; use crate::class::{Class, Value}; -pub(crate) struct Object { +#[derive(Debug)] +pub struct Object { // locked: bool, // hashcode: i32, - class: Rc, - data: HashMap, //TODO optimize + class: Arc, + pub data: HashMap>, //TODO optimize } impl Object { - pub fn new(class: Rc, data: HashMap) -> Self { + pub fn new(class: Arc, data: HashMap>) -> Self { Self { class, data, @@ -19,7 +21,7 @@ impl Object { } pub(crate) struct Heap { - objects: Vec, + objects: Vec>, } impl Heap { @@ -29,7 +31,7 @@ impl Heap { } } - pub(crate) fn new_object(&mut self, object: Object) { + pub(crate) fn new_object(&mut self, object: Arc) { self.objects.push(object); } } \ No newline at end of file diff --git a/src/vm.rs b/src/vm.rs index ee27e8b..aa7b01e 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,15 +1,16 @@ use std::collections::HashMap; -use std::rc::Rc; -use anyhow::Error; +use std::sync::Arc; -use crate::opcodes; -use crate::class::{AttributeType, Class, Method, Value}; +use anyhow::{anyhow, Error}; + +use crate::class::{AttributeType, Class, Value}; use crate::classloader::{CpEntry, load_class}; use crate::heap::{Heap, Object}; use crate::io::*; +use crate::opcodes; struct StackFrame { - data: Vec, + data: Vec>, } impl StackFrame { @@ -19,18 +20,18 @@ impl StackFrame { } } - fn push(&mut self, val: Value) { + fn push(&mut self, val: Arc) { self.data.push(val); } - fn pop(&mut self) -> Option { - self.data.pop() + fn pop(&mut self) -> Result, Error> { + Ok(self.data.pop().unwrap()) } } pub struct Vm { classpath: Vec, - classes: HashMap, + classes: HashMap>, //TODO implement classloader heap: Heap, } @@ -44,22 +45,18 @@ impl Vm { } } - pub fn get_class(&mut self, class_name: &str) -> Result<&Class, Error> { - if !self.classes.contains_key(class_name) { - self.load_class(class_name)?; - } - let class = self.classes.get(class_name); - Ok(class.expect("ClassNotFoundException")) + pub fn get_class(&mut self, class_name: &str) -> Result, Error> { + let entry = self.classes.entry(class_name.into()); + let entry = entry.or_insert_with(|| { + let resolved_path = find_class(&self.classpath, class_name).unwrap(); + let bytecode = read_class_file(resolved_path).unwrap(); + Arc::new(load_class(bytecode).unwrap()) + }); + Ok(entry.clone()) } - pub fn load_class(&mut self, name: &str) -> Result<(), Error> { - let resolved_path = find_class(&self.classpath, name)?; - let bytecode = read_class_file(resolved_path)?; - self.classes.insert(name.to_owned(), load_class(bytecode)?); - Ok(()) - } - pub fn new_instance(&self, class: Rc) { + pub fn new_instance(&self, class: Arc) -> Object { let mut data = HashMap::new(); for f in &class.fields { let value = match f.type_of().as_str() { @@ -73,92 +70,113 @@ impl Vm { "L" => Value::Null, _ => Value::Void }; - data.insert(f.name_index, value); + data.insert(f.name_index, Arc::new(value)); } - Object::new(class.clone(), data); + Object::new(class.clone(), data) } - pub fn execute(&mut self, class_name: &str, method_name: &str) -> Option { - let class = self.classes.get(class_name); - if let Some(c) = class { - let method = c.get_method(method_name); - if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() { - let mut stack = StackFrame::new(); - let mut pc: usize = 0; - while pc < code.opcodes.len() { - let opcode = &code.opcodes[pc]; - pc += 1; - println!("{}", opcode); - match opcode { - &opcodes::BIPUSH => { - let c = code.opcodes[pc] as i32; - stack.push(Value::I32(c)); - pc += 1; - } - &opcodes::LDC => { - let cp_index = read_u8(&code.opcodes, pc) as u16; - match method.constant_pool.get(&cp_index).unwrap() { - CpEntry::Integer(i) => { - stack.push(Value::I32(*i)); - } - CpEntry::Float(f) => { - stack.push(Value::F32(*f)); - } - _ => {} - } - pc += 1; - } - &opcodes::LDC_W => { - let cp_index = read_u16(&code.opcodes, pc); - match method.constant_pool.get(&cp_index).unwrap() { - CpEntry::Integer(i) => { - stack.push(Value::I32(*i)); - } - CpEntry::Float(f) => { - stack.push(Value::F32(*f)); - } - _ => { panic!("unexpected") } - } - pc += 2; - } - &opcodes::LDC2_W => { - let cp_index = read_u16(&code.opcodes, pc); - match method.constant_pool.get(&cp_index).unwrap() { - CpEntry::Double(d) => { - stack.push(Value::F64(*d)); - } - CpEntry::Long(l) => { - stack.push(Value::I64(*l)); - } - _ => { panic!("unexpected") } - } - - pc += 2; - } - &opcodes::ALOAD_0 => {} - &opcodes::IRETURN => { - return stack.pop(); - } - &opcodes::DRETURN => { - return stack.pop(); - } - &opcodes::FRETURN => { - return stack.pop(); - } - &opcodes::NEW => { - let cp_index = read_u16(&code.opcodes, pc); - if let CpEntry::ClassRef(class_name_index) = method.constant_pool.get(&cp_index).unwrap() { - if let CpEntry::Utf8(class) = method.constant_pool.get(class_name_index).unwrap() {} - } - } - //TODO implement all opcodes - _ => { panic!("opcode not implemented") } + pub fn execute(&mut self, class_name: &str, method_name: &str, instance: Option>) -> Result, Error> { + let class = self.get_class(class_name)?; + let method = class.get_method(method_name); + if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() { + let mut stack = StackFrame::new(); + let mut pc: usize = 0; + while pc < code.opcodes.len() { + let opcode = &code.opcodes[pc]; + pc += 1; + println!("{}", opcode); + match opcode { + &opcodes::BIPUSH => { + let c = code.opcodes[pc] as i32; + stack.push(Arc::new(Value::I32(c))); + pc += 1; } + &opcodes::LDC => { + let cp_index = read_u8(&code.opcodes, pc) as u16; + match method.constant_pool.get(&cp_index).unwrap() { + CpEntry::Integer(i) => { + stack.push(Arc::new(Value::I32(*i))); + } + CpEntry::Float(f) => { + stack.push(Arc::new(Value::F32(*f))); + } + _ => {} + } + pc += 1; + } + &opcodes::LDC_W => { + let cp_index = read_u16(&code.opcodes, pc); + match method.constant_pool.get(&cp_index).unwrap() { + CpEntry::Integer(i) => { + stack.push(Arc::new(Value::I32(*i))); + } + CpEntry::Float(f) => { + stack.push(Arc::new(Value::F32(*f))); + } + _ => { panic!("unexpected") } + } + pc += 2; + } + &opcodes::LDC2_W => { + let cp_index = read_u16(&code.opcodes, pc); + match method.constant_pool.get(&cp_index).unwrap() { + CpEntry::Double(d) => { + stack.push(Arc::new(Value::F64(*d))); + } + CpEntry::Long(l) => { + stack.push(Arc::new(Value::I64(*l))); + } + _ => { panic!("unexpected") } + } + + pc += 2; + } + &opcodes::ALOAD_0 => { + match instance.clone() { + Some(r) => { + stack.push(Arc::new(Value::Ref(r))); + } + None => { panic!("static context") } + } + } + &opcodes::IRETURN => { + return stack.pop(); + } + &opcodes::DRETURN => { + return stack.pop(); + } + &opcodes::FRETURN => { + return stack.pop(); + } + &opcodes::GETFIELD => { + let cp_index = read_u16(&code.opcodes, pc); + if let CpEntry::Fieldref(class_index, name_and_type_index) = method.constant_pool.get(&cp_index).unwrap() { + if let Value::Ref(inst) = &*stack.pop()? { + if let CpEntry::NameAndType(name, _) = method.constant_pool.get(name_and_type_index).unwrap() { + let value = inst.data.get(&name).unwrap(); + println!("{:?}", value); + stack.push(value.clone()); + } + } + } + pc += 2; + } + &opcodes::NEW => { + let cp_index = read_u16(&code.opcodes, pc); + if let CpEntry::ClassRef(class_name_index) = method.constant_pool.get(&cp_index).unwrap() { + if let CpEntry::Utf8(class) = method.constant_pool.get(class_name_index).unwrap() { + let class = self.get_class(class_name)?; + let object = Arc::new(self.new_instance(class)); + stack.push(Arc::new(Value::Ref(object.clone()))); + self.heap.new_object(object); + } + } + } + //TODO implement all opcodes + _ => { panic!("opcode not implemented") } } } - None // TODO error situation - } else { - panic!("class not found"); } + Err(anyhow!("should not happen")) } } \ No newline at end of file diff --git a/tests/class_tests.rs b/tests/class_tests.rs index 0f45d75..2f3d1ee 100644 --- a/tests/class_tests.rs +++ b/tests/class_tests.rs @@ -1,39 +1,40 @@ mod test { use std::rc::Rc; + use std::sync::Arc; use classfile_reader::{classloader::load_class, io}; use classfile_reader::class::Value; use classfile_reader::vm::Vm; #[test] fn get_constant_int() { - let mut vm = Vm::new("."); - let class = vm.get_class("Float").expect("ClassNotFound"); - assert_eq!((55, 0), class.get_version()); - - - if let Value::I32(v) = Vm::new("").execute("Float", "public static get()I").unwrap() { - assert_eq!(v, 42); - } else { - panic!("fail"); - } + // let mut vm = Vm::new("."); + // let class = vm.get_class("Float").expect("ClassNotFound"); + // assert_eq!((55, 0), class.get_version()); + // + // + // if let Value::I32(v) = Vm::new("").execute("Float", "public static get()I", None).unwrap() { + // assert_eq!(v, 42); + // } else { + // panic!("fail"); + // } } #[test] fn get_constant_double() { - let mut vm = Vm::new("."); - let class = vm.get_class("Double").expect("ClassNotFound"); - assert_eq!((55, 0), class.get_version()); - if let Value::F64(v) = Vm::new("").execute("Double", "public static get()D").unwrap() { - assert_eq!(v, 42.0); - } else { - panic!("fail"); - } + // let mut vm = Vm::new("."); + // let class = vm.get_class("Double").expect("ClassNotFound"); + // assert_eq!((55, 0), class.get_version()); + // if let Value::F64(v) = Vm::new("").execute("Double", "public static get()D", None).unwrap() { + // assert_eq!(v, 42.0); + // } else { + // panic!("fail"); + // } } #[test] fn get_constant_foat() { let mut vm = Vm::new("."); - vm.load_class("Float").expect("ClassNotFound"); + // vm.load_class("Float").expect("ClassNotFound"); // assert_eq!((55, 0), class.get_version()); // if let Value::F32(v) = Vm::new().execute(class.methods.get("public static getF()F").unwrap()).unwrap() { // assert_eq!(v, 42.0); @@ -45,9 +46,12 @@ mod test { #[test] fn get_float() { // assert_eq!((55, 0), class.get_version()); + let mut vm = Vm::new("/Users/FJ19WK/RustroverProjects/classfile_reader/tests"); - vm.load_class("Float").expect("ClassNotFound"); - if let Value::F32(v) = vm.execute("Float","public getF2()F").unwrap() { + + let c = vm.get_class("Float").unwrap(); + let object = Arc::new(vm.new_instance(c)); + if let Value::F32(v) = *vm.execute("Float","public getF2()F", Some(object)).unwrap() { assert_eq!(v, 0.0); } else { panic!("fail");