diff --git a/src/classloader/code_parser.rs b/src/classloader/code_parser.rs index e21992c..de25a82 100644 --- a/src/classloader/code_parser.rs +++ b/src/classloader/code_parser.rs @@ -38,6 +38,7 @@ pub(crate) fn parse_code(opcodes: &[u8]) -> Vec { IFGE(goto) => IFGE(code2.get(&goto).unwrap().0), IFLT(goto) => IFLT(code2.get(&goto).unwrap().0), IFLE(goto) => IFLE(code2.get(&goto).unwrap().0), + GOTO(goto) => GOTO(code2.get(&goto).unwrap().0), //TODO more jump instructions _ => opcode, @@ -214,8 +215,8 @@ fn get_opcode(opcodes: &[u8], c: &mut usize) -> Opcode { 164 => IF_ICMPLE(offset(opcodes, c)), 165 => IF_ACMPEQ(offset(opcodes, c)), 166 => IF_ACMPNE(offset(opcodes, c)), - 167 => GOTO(read_u16(opcodes, c)), - 168 => JSR(read_u16(opcodes, c)), + 167 => GOTO(offset(opcodes, c)), + 168 => JSR(offset(opcodes, c)), 169 => RET(read_u8(opcodes, c)), 170 => TABLESWITCH(read_tableswitch(opcodes, c)), 171 => LOOKUPSWITCH(read_lookupswitch(opcodes, c)), diff --git a/src/main.rs b/src/main.rs index 3855b39..814f931 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,6 @@ use java_rs::vm::runtime::Vm; -use std::cmp::Ordering::Equal; fn main() { - let a = 0.0; - println!("{}", 1.0 / a); let mut vm = Vm::new(); vm.run( "/Users/Shautvast/dev/java.rs/tests", diff --git a/src/vm/array.rs b/src/vm/array.rs index 838187c..b240def 100644 --- a/src/vm/array.rs +++ b/src/vm/array.rs @@ -3,12 +3,13 @@ use anyhow::{anyhow, Error}; use crate::value::Value; use crate::value::Value::*; +use crate::vm::object::ObjectRef; pub(crate) fn array_load(index: Value, arrayref: Value) -> Result { if let I32(index) = index { let index = index as usize; - if let Null = arrayref { + if let Value::Null = arrayref { return Err(anyhow!("NullpointerException")); } if let Ref(objectref) = arrayref { @@ -49,6 +50,9 @@ pub(crate) fn array_load(index: Value, arrayref: Value) -> Result Object(_) => { panic!("should be array") } //throw error? + ObjectRef::Null => { + return Ok(Value::Null); + } } } } @@ -56,7 +60,7 @@ pub(crate) fn array_load(index: Value, arrayref: Value) -> Result } pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result<(), Error> { - if let Null = arrayref { + if let Value::Null = arrayref { return Err(anyhow!("NullpointerException")); } @@ -135,7 +139,7 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result unreachable!() } } - Object(_) | Class(_) => {} //throw error? + Object(_) | Class(_) | ObjectRef::Null => {} //throw error? } } } else { diff --git a/src/vm/native.rs b/src/vm/native.rs index 0dfcfe9..084a8ca 100644 --- a/src/vm/native.rs +++ b/src/vm/native.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use std::collections::HashMap; -use std::future::Future; use std::rc::Rc; use anyhow::Error; @@ -13,7 +12,7 @@ use crate::classmanager::ClassManager; use crate::value::Value; use crate::value::Value::{Utf8, Void, I32}; use crate::vm::object::ObjectRef::Object; -use crate::vm::object::{self, ObjectRef}; +use crate::vm::object::{self, Array, ObjectRef}; use crate::vm::runtime::Stackframe; const primitive_name_classes: Lazy> = Lazy::new(|| { @@ -40,12 +39,13 @@ pub fn invoke_native( match class_name { "java/lang/Class" => java_lang_Class(class_manager, method_name, args), + "java/lang/Object" => java_lang_Object(method_name, args), "java/lang/System" => java_lang_System(method_name), "jdk/internal/misc/Unsafe" => jdk_internal_misc_Unsafe(method_name), "jdk/internal/util/SystemProps$Raw" => { jdk_internal_util_SystemProps_Raw(class_manager, method_name) } - _ => unimplemented!(""), + _ => unimplemented!("{}", class_name), } } @@ -63,6 +63,25 @@ fn java_lang_Class( }) } +fn java_lang_Object(method_name: &str, args: Vec) -> Result { + Ok(match method_name { + "hashCode()I" => { + if let Value::Ref(object_ref) = args.get(0).unwrap() { + if let Object(p) = object_ref { + I32(p.borrow().id as i32) // system hashcode + } else { + I32(0) //todo implement for arrays + } + } else { + unreachable!() + } + } + _ => { + unimplemented!("{}", method_name); + } + }) +} + fn java_lang_System(method_name: &str) -> Result { Ok(match method_name { _ => Void, @@ -129,7 +148,9 @@ fn vmProperties() -> Result { //TODO insert some values vec }); - Ok(Value::Ref(ObjectRef::StringArray(props.to_vec()))) + Ok(Value::Ref(ObjectRef::StringArray(Array::from_vec( + props.to_vec(), + )))) } fn platformProperties() -> Result { @@ -216,5 +237,7 @@ fn platformProperties() -> Result { vec }); - Ok(Value::Ref(ObjectRef::StringArray(props.to_vec()))) + Ok(Value::Ref(ObjectRef::StringArray(Array::from_vec( + props.to_vec(), + )))) } diff --git a/src/vm/object.rs b/src/vm/object.rs index 2ec6edd..575b6c4 100644 --- a/src/vm/object.rs +++ b/src/vm/object.rs @@ -7,37 +7,91 @@ use std::cell::RefCell; use std::fmt::{Debug, Formatter, Pointer}; use std::rc::Rc; +#[derive(Clone)] +pub struct Array +where + T: Clone, +{ + id: u32, + data: Vec, +} + +impl Array +where + T: Clone, +{ + pub fn new(init: T, size: usize) -> Self { + Self { + id: random::() >> 1, + data: vec![init; size], + } + } + + pub fn from_vec(vec: Vec) -> Self { + Self { + id: random::() >> 1, + data: vec, + } + } + pub fn len(&self) -> usize { + self.data.len() + } +} + +impl std::ops::Index for Array +where + T: Clone, +{ + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self.data[index] + } +} + +impl std::ops::IndexMut for Array +where + T: Clone, +{ + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.data[index] + } +} + #[derive(Clone)] pub enum ObjectRef { - ByteArray(Vec), //maybe use arrays? - ShortArray(Vec), - IntArray(Vec), - LongArray(Vec), - FloatArray(Vec), - DoubleArray(Vec), - BooleanArray(Vec), - CharArray(Vec), - StringArray(Vec), + ByteArray(Array), + //maybe use arrays? + ShortArray(Array), + IntArray(Array), + LongArray(Array), + FloatArray(Array), + DoubleArray(Array), + BooleanArray(Array), + CharArray(Array), + StringArray(Array), ObjectArray(ClassId, Vec), Object(Rc>), Class(Class), + Null, } impl Debug for ObjectRef { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let name = match self { - ByteArray(_) => "[B", //length for arrays - ShortArray(_) => "[S", - IntArray(_) => "[I]", - LongArray(_) => "[J", - FloatArray(_) => "[F", - DoubleArray(_) => "[D]", - BooleanArray(_) => "[Z", - CharArray(_) => "[C", - StringArray(_) => "[Ljava/lang/String]", - ObjectArray(_, _) => "[L", - Object(_) => "L", - Class(_) => "Class", + ByteArray(a) => format!("[B;{}", a.len()), + ShortArray(a) => format!("[S;{}", a.len()), + IntArray(a) => format!("[I;{}", a.len()), + LongArray(a) => format!("[J;{}", a.len()), + FloatArray(a) => format!("[F;{}", a.len()), + DoubleArray(a) => format!("[D;{}", a.len()), + BooleanArray(a) => format!("[Z;{}", a.len()), + CharArray(a) => format!("[C;{}", a.len()), + StringArray(a) => format!("[Ljava/lang/String;{}]", a.len()), + ObjectArray(_, a) => format!("[[Lx;{}]", a.len()), + Object(_) => "L".into(), + Class(_) => "Class".into(), + ObjectRef::Null => "null".into(), }; write!(f, "{}", name) } @@ -74,29 +128,29 @@ pub enum ArrayType { impl ObjectRef { pub fn new_object_array(class: &Class, size: usize) -> Self { - ObjectArray(class.id, Vec::with_capacity(size)) + ObjectArray(class.id, vec![ObjectRef::Null; size]) } pub fn new_array(arraytype: u8, size: usize) -> Self { match arraytype { - 8 => ByteArray(vec![0; size]), - 9 => ShortArray(vec![0; size]), - 10 => IntArray(vec![0; size]), - 11 => LongArray(vec![0; size]), - 6 => FloatArray(vec![0.0; size]), - 7 => DoubleArray(vec![0.0; size]), - 4 => BooleanArray(vec![false; size]), - 5 => CharArray(vec![0; size]), + 8 => ByteArray(Array::new(0, size)), + 9 => ShortArray(Array::new(0, size)), + 10 => IntArray(Array::new(0, size)), + 11 => LongArray(Array::new(0, size)), + 6 => FloatArray(Array::new(0_f32, size)), + 7 => DoubleArray(Array::new(0_f64, size)), + 4 => BooleanArray(Array::new(false, size)), + 5 => CharArray(Array::new(0, size)), _ => unreachable!("impossible array type"), } } pub fn new_int_array(size: usize) -> Self { - IntArray(Vec::with_capacity(size)) + IntArray(Array::new(0, size)) } pub fn new_byte_array(d: Vec) -> Self { - ByteArray(into_vec_i8(d)) + ByteArray(Array::from_vec(into_vec_i8(d))) } } @@ -127,7 +181,7 @@ impl Object { pub fn new(class: &Class) -> Self { let instance_data = Object::init_fields(class); Self { - id: random(), + id: random::() >> 1, class_id: class.id, data: instance_data, } diff --git a/src/vm/runtime.rs b/src/vm/runtime.rs index 2772557..af659f5 100644 --- a/src/vm/runtime.rs +++ b/src/vm/runtime.rs @@ -514,9 +514,13 @@ impl Stackframe { let value1 = self.pop(); if_cmp(&mut self.pc, opcode, jmp_to, &value1, &value2); } - GOTO(jmp_to) => { - self.pc += *jmp_to as usize; + GOTO(jmp_to) | JSR(jmp_to) => { + self.pc = *jmp_to as usize; } + JSR_W(jmp_to) => { + self.pc = *jmp_to as usize; + } + INVOKEVIRTUAL(c) => { if let Some(invocation) = get_signature_for_invoke(&constant_pool, *c) { let mut args = Vec::with_capacity(invocation.method.num_args); @@ -816,7 +820,9 @@ impl Stackframe { self.push(value.clone()); } IRETURN | LRETURN | FRETURN | DRETURN | ARETURN => { - return self.pop(); + let v = self.pop(); + debug!("returning {:?}", v); + return v; } RETURN_VOID => { return Void; @@ -867,9 +873,42 @@ impl Stackframe { if value1 > 0 { self.push(I64(value1 >> value2)); } else { - self.push(Value::I64(((value1 as u64) >> value2) as i64)); + self.push(I64(((value1 as u64) >> value2) as i64)); } } + IAND => { + let value2 = self.pop().into_i32(); + let value1 = self.pop().into_i32(); + self.push(I32(value1 & value2)); + } + + LAND => { + let value2 = self.pop().into_i64(); + let value1 = self.pop().into_i64(); + self.push(I64(value1 & value2)); + } + IOR => { + let value2 = self.pop().into_i32(); + let value1 = self.pop().into_i32(); + self.push(I32(value1 | value2)); + } + LOR => { + let value2 = self.pop().into_i64(); + let value1 = self.pop().into_i64(); + self.push(I64(value1 | value2)); + } + IXOR => { + let value2 = self.pop().into_i32(); + let value1 = self.pop().into_i32(); + self.push(I32(value1 ^ value2)); + } + LXOR => { + let value2 = self.pop().into_i64(); + let value1 = self.pop().into_i64(); + self.push(I64(value1 ^ value2)); + } + + CHECKCAST(_) => {} _ => { panic!("opcode not implemented") }