use std::cell::{RefCell, UnsafeCell}; use std::collections::HashMap; use std::ops::Deref; use std::rc::Rc; use std::string; use std::sync::Arc; use anyhow::{anyhow, Error}; use crate::class::{AttributeType, Class, get_class, Modifier, unsafe_ref, unsafe_val, UnsafeValue, Value}; use crate::class::Value::Void; use crate::classloader::CpEntry; use crate::heap::{Heap, Object, ObjectRef}; use crate::io::*; use crate::native::invoke_native; use crate::opcodes::*; #[derive(Debug)] pub(crate) struct StackFrame { at: String, data: Vec, } // maybe just call frame impl StackFrame { fn new(at_class: &str, at_method: &str) -> Self { let mut at: String = at_class.into(); at.push('.'); at.push_str(at_method); Self { at, data: vec![] } } fn push(&mut self, val: Value) { self.data.push(unsafe_val(val)); } fn push_ref(&mut self, val: UnsafeValue) { self.data.push(val); } fn pop(&mut self) -> Result { Ok(self.data.pop().unwrap()) } fn len(&self) -> usize { self.data.len() } } pub struct Vm { pub classpath: Vec, heap: Heap, pub(crate) stackframes: Vec, } #[cfg(target_family = "unix")] const PATH_SEPARATOR: char = ':'; #[cfg(target_family = "windows")] const PATH_SEPARATOR: char = ';'; /// The singlethreaded VM (maybe a future Thread) //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() } pub fn new(classpath: &'static str) -> Self { Self { classpath: classpath .split(PATH_SEPARATOR) .map(|s| s.to_owned()) .collect(), heap: Heap::new(), stackframes: vec![], } } pub fn new_instance(class: Arc>) -> Object { let mut instance = Object::new(class.clone()); instance } /// execute the bytecode /// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM pub fn execute( &mut self, calling_class_name: Option<&str>, class_name: &str, method_name: &str, args: Vec, ) -> Result { let class = get_class(self, calling_class_name, class_name)?; self.execute_class(class, method_name, args) } pub fn execute_class( &mut self, class: Arc>, method_name: &str, args: Vec, ) -> Result { let this_class = class; println!("execute {}.{}", this_class.borrow().name, method_name); let method = this_class.clone().borrow().get_method(method_name)?.clone(); let mut local_params: Vec> = args.clone().iter().map(|e| Some(e.clone())).collect(); if method.is(Modifier::Native) { return Ok(invoke_native(method, 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 mut pc = &mut 0; while *pc < code.opcodes.len() { let opcode = read_u8(&code.opcodes, pc); println!("stack {} opcode {} ", self.current_frame().len(), opcode); match opcode { ACONST_NULL => { self.current_frame().push(Value::Null); } ICONST_M1 => { self.current_frame().push(Value::I32(-1)); } ICONST_0 => { println!("ICONST_0"); self.current_frame().push(Value::I32(0)); } ICONST_1 => { println!("ICONST_1"); self.current_frame().push(Value::I32(1)); } ICONST_2 => { self.current_frame().push(Value::I32(2)); } ICONST_3 => { self.current_frame().push(Value::I32(3)); } ICONST_4 => { self.current_frame().push(Value::I32(4)); } ICONST_5 => { self.current_frame().push(Value::I32(5)); } LCONST_0 => { self.current_frame().push(Value::I64(0)); } LCONST_1 => { self.current_frame().push(Value::I64(1)); } FCONST_0 => { self.current_frame().push(Value::F32(0.0)); } FCONST_1 => { self.current_frame().push(Value::F32(1.0)); } FCONST_2 => { self.current_frame().push(Value::F32(2.0)); } DCONST_0 => { self.current_frame().push(Value::F64(0.0)); } DCONST_1 => { self.current_frame().push(Value::F64(1.0)); } SIPUSH => { let s = read_u16(&code.opcodes, pc) as i32; self.current_frame().push(Value::I32(s)); } BIPUSH => { let c = read_u8(&code.opcodes, pc) as i32; self.current_frame().push(Value::I32(c)); } LDC => { println!("LDC"); let cp_index = read_u8(&code.opcodes, pc) as u16; let c = method.constant_pool.get(&cp_index).unwrap(); println!("{:?}", c); match c { CpEntry::Integer(i) => { self.current_frame().push(Value::I32(*i)); } CpEntry::Float(f) => { self.current_frame().push(Value::F32(*f)); } CpEntry::Double(d) => { self.current_frame().push(Value::F64(*d)); } CpEntry::StringRef(utf8) => { //TODO let stringclass = get_class(self, Some(&this_class.borrow().name), "java/lang/String").unwrap(); let stringinstance = unsafe_val( Value::Ref(unsafe_ref(ObjectRef::Object(Box::new( Vm::new_instance(stringclass.clone())))))); let string: Vec = this_class.borrow().cp_utf8(utf8).unwrap().to_owned().as_bytes().into(); self.execute_class(stringclass, "([B)V", vec![stringinstance.clone(), unsafe_val(Value::Ref(ObjectRef::new_byte_array(string)))])?; self.current_frame().push_ref(stringinstance); } CpEntry::Long(l) => { self.current_frame().push(Value::I64(*l)); } _ => {} } } LDC_W => { println!("LDC_W"); let cp_index = read_u16(&code.opcodes, pc); match method.constant_pool.get(&cp_index).unwrap() { CpEntry::Integer(i) => { self.current_frame().push(Value::I32(*i)); } CpEntry::Float(f) => { self.current_frame().push(Value::F32(*f)); } _ => { unreachable!() } } } LDC2_W => { println!("LDC2_W"); 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)); } CpEntry::Long(l) => { self.current_frame().push(Value::I64(*l)); } _ => { unreachable!() } } } ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => { // omitting the type checks so far let n = read_u8(&code.opcodes, pc) as usize; self.current_frame() .push_ref(local_params[n].as_ref().unwrap().clone()); } ILOAD_0 | LLOAD_0 | FLOAD_0 | DLOAD_0 | ALOAD_0 => { println!("LOAD"); self.current_frame() .push_ref(local_params[0].as_ref().unwrap().clone()); } ILOAD_1 | LLOAD_1 | FLOAD_1 | DLOAD_1 | ALOAD_1 => { self.current_frame() .push_ref(local_params[1].as_ref().unwrap().clone()); } ILOAD_2 | LLOAD_2 | FLOAD_2 | DLOAD_2 | ALOAD_2 => { self.current_frame() .push_ref(local_params[2].as_ref().unwrap().clone()); } ILOAD_3 | LLOAD_3 | FLOAD_3 | DLOAD_3 | ALOAD_3 => { self.current_frame() .push_ref(local_params[3].as_ref().unwrap().clone()); } IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => unsafe { self.array_load()?; }, ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => { let index = read_u8(&code.opcodes, pc) as usize; self.store(&mut local_params, index)?; } ISTORE_0 | LSTORE_0 | DSTORE_0 | ASTORE_0 | FSTORE_0 => { self.store(&mut local_params, 0)?; } ISTORE_1 | LSTORE_1 | DSTORE_1 | ASTORE_1 | FSTORE_1 => { println!("STORE"); self.store(&mut local_params, 1)?; } ISTORE_2 | LSTORE_2 | DSTORE_2 | ASTORE_2 | FSTORE_2 => { self.store(&mut local_params, 2)?; } ISTORE_3 | LSTORE_3 | DSTORE_3 | ASTORE_3 | FSTORE_3 => { self.store(&mut local_params, 3)?; } BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE | AASTORE => unsafe { self.array_store()? }, POP => { self.current_frame().pop()?; } DUP => { let value = self.current_frame().pop()?; println!("{:?}", value); self.current_frame().push_ref(value.clone()); self.current_frame().push_ref(value); } IRETURN | FRETURN | DRETURN => { println!("RETURN"); let result = self.current_frame().pop(); self.stackframes.pop(); return result; } RETURN_VOID => { println!("RETURN void"); self.stackframes.pop(); return Ok(Value::void()); } GETSTATIC => { let borrow = this_class.borrow(); let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) = borrow.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap(); let (name) = borrow.cp_utf8(name_index).unwrap(); let that_class_name_index = borrow.cp_class_ref(class_index).unwrap(); let that_class_name = borrow.cp_utf8(that_class_name_index).unwrap(); let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?; let that_borrow = that.borrow(); let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap(); println!("get static field {}", name); self.current_frame().push_ref(borrow.static_data.get(*val_index).unwrap().as_ref().unwrap().clone()); } PUTSTATIC => { println!("PUTSTATIC"); let mut borrow = this_class.borrow_mut(); let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) = borrow.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap(); let (name) = borrow.cp_utf8(name_index).unwrap(); let class_name_index = borrow.cp_class_ref(class_index).unwrap(); println!("field {}", name); let that_class_name = borrow.cp_utf8(class_name_index).unwrap(); if &borrow.name == that_class_name {// may have to apply this in GETSTATIC too let (_, val_index) = borrow.static_field_mapping.get(that_class_name).unwrap().get(name).as_ref().unwrap(); let val_index = *val_index; let value = self.current_frame().pop()?; borrow.static_data[val_index] = Some(value); } else { let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?; let that_borrow = that.borrow(); // if already borrowed, then that_class == this_class let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap(); let value = self.current_frame().pop()?; borrow.static_data[*val_index] = Some(value); } unsafe { for v in &borrow.static_data { let v = &*v.as_ref().unwrap().get(); if let Value::Ref(vv) = v { println!("{:?}", &*vv.get()) } else { println!("{:?}", *v); } } } } GETFIELD => unsafe { let borrow = this_class.borrow(); let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) = borrow.cp_field_ref(&cp_index).unwrap(); let (field_name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap(); let class_name_index = borrow.cp_class_ref(class_index).unwrap(); let class_name = borrow.cp_utf8(class_name_index).unwrap(); let field_name = borrow.cp_utf8(field_name_index).unwrap(); let mut objectref = self.current_frame().pop()?; if let Value::Ref(instance) = &mut *objectref.get() { if let ObjectRef::Object(ref mut object) = &mut *instance.get() { let value = object.get(class_name, field_name); self.current_frame().push_ref(Arc::clone(value)); } else { unreachable!() } } else { unreachable!() } }, PUTFIELD => unsafe { let borrow = this_class.borrow(); let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) = borrow.cp_field_ref(&cp_index).unwrap(); let (field_name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap(); let class_name_index = borrow.cp_class_ref(class_index).unwrap(); let class_name = borrow.cp_utf8(class_name_index).unwrap(); let field_name = borrow.cp_utf8(field_name_index).unwrap(); let value = self.current_frame().pop()?; let mut objectref = self.current_frame().pop()?; if let Value::Ref(instance) = &mut *objectref.get() { if let ObjectRef::Object(ref mut object) = &mut *instance.get() { object.set(class_name, field_name, value); } } else { unreachable!() } }, INVOKEVIRTUAL | INVOKESPECIAL => unsafe { println!("INVOKE"); // 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()?); } args.insert(0, self.current_frame().pop()?); let mut return_value = self.execute( Some(this_class.borrow().name.as_str()), &invocation.class_name, &invocation.method.name, args, )?; match *return_value.get() { Void => {} _ => { self.current_frame().push_ref(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()?); } let mut returnvalue = self.execute( Some(this_class.borrow().name.as_str()), &invocation.class_name, &invocation.method.name, args, )?; match *returnvalue.get() { Void => {} _ => { self.current_frame().push_ref(returnvalue.clone()); } } } else { unreachable!() } }, NEW => { println!("NEW"); let class_index = &read_u16(&code.opcodes, pc); let borrow = this_class.borrow(); let class_name_index = borrow.cp_class_ref(class_index).unwrap(); let class_name = borrow.cp_utf8(class_name_index).unwrap(); let class_to_instantiate = get_class(self, Some(&borrow.name), 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 { println!("ANEWARRAY"); let class_index = &read_u16(&code.opcodes, pc); let borrow = this_class.borrow(); let class_name_index = borrow.cp_class_ref(class_index).unwrap(); let class_name = borrow.cp_utf8(class_name_index).unwrap(); let arraytype = get_class(self, Some(&borrow.name), class_name)?; let count = self.current_frame().pop()?; if let Value::I32(count) = *count.get() { // why does pop()?.get() give weird results? let array = ObjectRef::new_object_array(arraytype, count as usize); let array = unsafe_ref(array); self.current_frame().push(Value::Ref(Arc::clone(&array))); println!("{}", self.current_frame().len()); self.heap.new_object(array); } else { panic!(); } } //TODO implement all opcodes _ => { panic!("opcode not implemented {:?}", self.stackframes) //TODO implement proper --stacktraces-- error handling } } } } panic!("should not happen") } unsafe fn array_load(&mut self) -> Result<(), Error> { let value = self.current_frame().pop()?; if let Value::I32(index) = &*value.get() { let index = *index as usize; let arrayref = self.current_frame().pop()?; if let Value::Null = &*arrayref.get() { return Err(anyhow!("NullpointerException")); } if let Value::Ref(objectref) = &*arrayref.get() { match &*objectref.get() { ObjectRef::ByteArray(array) => { self.current_frame().push(Value::I32(array[index] as i32)); } ObjectRef::ShortArray(array) => { self.current_frame().push(Value::I32(array[index] as i32)); } ObjectRef::IntArray(array) => { self.current_frame().push(Value::I32(array[index])); } ObjectRef::BooleanArray(array) => { self.current_frame().push(Value::I32(array[index] as i32)); } ObjectRef::CharArray(array) => { self.current_frame().push(Value::CHAR(array[index])); } ObjectRef::LongArray(array) => { self.current_frame().push(Value::I64(array[index])); } ObjectRef::FloatArray(array) => { self.current_frame().push(Value::F32(array[index])); } ObjectRef::DoubleArray(array) => { self.current_frame().push(Value::F64(array[index])); } ObjectRef::ObjectArray(_arraytype, data) => { self.current_frame() .push(Value::Ref(data[index].clone())); } ObjectRef::Object(_) => { panic!("should be array") } //throw error? } } } Ok(()) } unsafe fn array_store(&mut self) -> Result<(), Error> { let value = self.current_frame().pop()?; let index = &*self.current_frame().pop()?; let mut arrayref = &mut self.current_frame().pop()?; if let Value::Null = &*arrayref.get() { return Err(anyhow!("NullpointerException")); } if let Value::I32(index) = &*index.get() { if let Value::Ref(ref mut objectref) = &mut *arrayref.get() { match &mut *objectref.get() { ObjectRef::ByteArray(ref mut array) => { if let Value::I32(value) = *value.get() { // is i32 correct? array[*index as usize] = value as i8; } else { unreachable!() } } ObjectRef::ShortArray(ref mut array) => { if let Value::I32(value) = *value.get() { // is i32 correct? array[*index as usize] = value as i16; } else { unreachable!() } } ObjectRef::IntArray(ref mut array) => { if let Value::I32(value) = *value.get() { array[*index as usize] = value; } else { unreachable!() } } ObjectRef::BooleanArray(ref mut array) => { if let Value::I32(value) = *value.get() { array[*index as usize] = value > 0; } else { unreachable!() } } ObjectRef::CharArray(ref mut array) => { if let Value::I32(value) = *value.get() { array[*index as usize] = char::from_u32_unchecked(value as u32); } else { unreachable!() } } ObjectRef::LongArray(ref mut array) => { if let Value::I64(value) = *value.get() { array[*index as usize] = value; } else { unreachable!() } } ObjectRef::FloatArray(ref mut array) => { if let Value::F32(value) = *value.get() { array[*index as usize] = value } else { unreachable!() } } ObjectRef::DoubleArray(ref mut array) => { if let Value::F64(value) = *value.get() { array[*index as usize] = value } else { unreachable!() } } ObjectRef::ObjectArray(arraytype, ref mut array) => { if let Value::Ref(ref value) = *value.get() { array[*index as usize] = value.clone(); } else { unreachable!() } } ObjectRef::Object(_) => {} //throw error? } } } else { unreachable!() } Ok(()) } fn store( &mut self, local_params: &mut Vec>, index: usize, ) -> Result<(), Error> { let value = self.current_frame().pop()?; while local_params.len() < index + 1 { local_params.push(None); } local_params[index] = Some(value.clone()); Ok(()) } } struct Invocation { class_name: String, method: MethodSignature, } struct MethodSignature { name: String, num_args: usize, } // TODO can be simplified now, using cp_ methods in Class fn get_signature_for_invoke(cp: &Rc>, 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 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 { class_name: class_name.into(), method: method_signature, }); } } } } None } fn get_name_and_type(cp: Rc>, 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() { let mut method_signature: String = method_name.into(); let num_args = get_hum_args(signature); method_signature.push_str(signature); return Some(MethodSignature { name: method_signature, num_args, }); } } } None } fn get_hum_args(signature: &str) -> usize { let mut num = 0; let mut i = 1; let chars: Vec = signature.chars().collect(); while i < chars.len() { if chars[i] == 'L' { i += 1; while chars[i] != ';' { i += 1; } num += 1; } else if chars[i] == ')' { break; } else { i += 1; num += 1; } } num }