diff --git a/src/class.rs b/src/class.rs index d71ac5e..48fe119 100644 --- a/src/class.rs +++ b/src/class.rs @@ -32,16 +32,18 @@ pub struct Class { } impl Class { - pub fn new(minor_version: u16, - major_version: u16, - constant_pool: Rc>, - access_flags: u16, - this_class: u16, - super_class_index: u16, - interface_indices: Vec, - fields: HashMap, - methods: HashMap, - attributes: HashMap) -> Self { + pub fn new( + minor_version: u16, + major_version: u16, + constant_pool: Rc>, + access_flags: u16, + this_class: u16, + super_class_index: u16, + interface_indices: Vec, + fields: HashMap, + methods: HashMap, + attributes: HashMap, + ) -> Self { let name = Class::class_name(this_class, constant_pool.clone()).unwrap(); let super_class_name = Class::class_name(super_class_index, constant_pool.clone()); @@ -88,10 +90,17 @@ impl Class { } // part of the initialize procedure - fn map_fields(field_mapping: &mut HashMap>, class: &Class, field_map_index: &mut usize) { + fn map_fields( + field_mapping: &mut HashMap>, + class: &Class, + field_map_index: &mut usize, + ) { let mut this_fields = HashMap::new(); //fields in class are stored per class and every superclass. for field in &class.fields { - this_fields.insert(field.0.to_owned(), (field.1.type_of().to_owned(), *field_map_index)); //name => (type,index) + this_fields.insert( + field.0.to_owned(), + (field.1.type_of().to_owned(), *field_map_index), + ); //name => (type,index) *field_map_index += 1; } let this_name = class.name.to_owned(); @@ -108,10 +117,14 @@ impl Class { .ok_or(anyhow!("Method {} not found", name)) } - fn class_name(super_class_index: u16, constant_pool: Rc>) -> Option { + fn class_name( + super_class_index: u16, + constant_pool: Rc>, + ) -> Option { if super_class_index == 0 { None - } else if let CpEntry::ClassRef(name_index) = constant_pool.get(&super_class_index).unwrap() { + } else if let CpEntry::ClassRef(name_index) = constant_pool.get(&super_class_index).unwrap() + { if let CpEntry::Utf8(name) = constant_pool.get(name_index).unwrap() { Some(name.to_owned()) } else { @@ -124,15 +137,30 @@ impl Class { // convienence methods for data from the constantpool - pub fn get_field_ref(&self, index: &u16) -> Option<(&u16, &u16)> { - if let CpEntry::Fieldref(class_index, name_and_type_index) = self.constant_pool.get(index).unwrap() { + pub fn cp_field_ref(&self, index: &u16) -> Option<(&u16, &u16)> { + if let CpEntry::Fieldref(class_index, name_and_type_index) = + self.constant_pool.get(index).unwrap() + { Some((class_index, name_and_type_index)) } else { None } } - pub fn get_class_ref(&self, index: &u16) -> Option<&u16> { + /// both methodRef and InterfaceMethodRef + /// returns (class_index, name_and_type_index) + pub fn cp_method_ref(&self, index: &u16) -> Option<(&u16, &u16)> { + if let CpEntry::MethodRef(class_index, name_and_type_index) + | CpEntry::InterfaceMethodref(class_index, name_and_type_index) = + self.constant_pool.get(index).unwrap() + { + Some((class_index, name_and_type_index)) + } else { + None + } + } + + pub fn cp_class_ref(&self, index: &u16) -> Option<&u16> { if let CpEntry::ClassRef(name_index) = self.constant_pool.get(index).unwrap() { Some(name_index) } else { @@ -140,7 +168,7 @@ impl Class { } } - pub fn get_utf8(&self, index: &u16) -> Option<&String> { + pub fn cp_utf8(&self, index: &u16) -> Option<&String> { if let CpEntry::Utf8(utf8) = self.constant_pool.get(index).unwrap() { Some(utf8) } else { @@ -148,14 +176,14 @@ impl Class { } } - pub fn get_name_and_type(&self, index: &u16) -> Option<(&u16, &u16)> { - if let CpEntry::NameAndType(name_index, type_index) = self.constant_pool.get(index).unwrap(){ + pub fn cp_name_and_type(&self, index: &u16) -> Option<(&u16, &u16)> { + if let CpEntry::NameAndType(name_index, type_index) = self.constant_pool.get(index).unwrap() + { Some((name_index, type_index)) } else { None } } - } unsafe impl Send for Class {} @@ -208,6 +236,11 @@ impl Method { full_name } + + pub fn is(&self, modifier: Modifier) -> bool { + let m = modifier as u16; + (self.access_flags & m) == m + } } pub struct Field { @@ -263,29 +296,34 @@ impl Field { } } -const MODIFIERS: [(u16, &str); 12] = [ - (0x0001, "public "), - (0x0002, "private "), - (0x0004, "protected "), - (0x0008, "static "), - (0x0010, "final "), - (0x0020, "synchronized "), - (0x0040, "volatile "), - (0x0080, "transient "), - (0x0100, "native "), - (0x0200, "interface "), - (0x0400, "interface "), - (0x0800, "strict "), +const MODIFIERS: [(Modifier, &str); 12] = [ + (Modifier::Public, "public "), + (Modifier::Private, "private "), + (Modifier::Protected, "protected "), + (Modifier::Static, "static "), + (Modifier::Final, "final "), + (Modifier::Synchronized, "synchronized "), + (Modifier::Volatile, "volatile "), + (Modifier::Transient, "transient "), + (Modifier::Native, "native "), + (Modifier::Abstract, "abstract"), + (Modifier::Strict, "strict"), + (Modifier::Synthetic, "synthetic"), ]; -pub fn get_modifier(modifier: u16) -> String { - let mut output = String::new(); - for m in MODIFIERS { - if modifier & m.0 == m.0 { - output.push_str(m.1) - } - } - output +pub enum Modifier { + Public = 0x0001, + Private = 0x0002, + Protected = 0x0004, + Static = 0x0008, + Final = 0x0010, + Synchronized = 0x0020, + Volatile = 0x0040, + Transient = 0x0080, + Native = 0x0100, + Abstract = 0x0400, + Strict = 0x0800, + Synthetic = 0x1000, } //TODO implement more types @@ -384,6 +422,20 @@ pub enum Value { Ref(Arc>), } +impl Value { + pub fn void() -> UnsafeValue { + Arc::new(UnsafeCell::new(Value::Void)) + } +} + +impl Into for Value { + fn into(self) -> UnsafeValue { + Arc::new(UnsafeCell::new(self)) + } +} + +pub type UnsafeValue = Arc>; + unsafe impl Send for Value {} unsafe impl Sync for Value {} diff --git a/src/classloader.rs b/src/classloader.rs index 3ab8f0a..597dbb0 100644 --- a/src/classloader.rs +++ b/src/classloader.rs @@ -4,7 +4,6 @@ use anyhow::Error; use std::collections::HashMap; use std::rc::Rc; - // The native classoader pub fn load_class(bytecode: Vec) -> Result { let pos = &mut 0; @@ -141,7 +140,7 @@ fn read_constant_pool_entry(cp_index: &mut u16, index: &mut usize, bytecode: &[u let descriptor_index = read_u16(bytecode, index); CpEntry::NameAndType(name_index, descriptor_index) } - 15 =>{ + 15 => { let reference_kind = read_u8(bytecode, index); let reference_index = read_u16(bytecode, index); CpEntry::MethodHandle(reference_kind, reference_index) @@ -227,7 +226,7 @@ fn read_attribute( *index += attribute_length; if let CpEntry::Utf8(s) = &constant_pool.get(&attribute_name_index).unwrap() { - println!("Att [{}]", s); + // println!("Att [{}]", s); return match s.as_str() { "ConstantValue" => { assert_eq!(info.len(), 2); @@ -251,8 +250,7 @@ fn read_attribute( let attribute_count = read_u16(&info, ci); let mut code_attributes = HashMap::new(); for _ in 0..attribute_count { - if let Some(att) = read_attribute(constant_pool.clone(), &info, ci) - { + if let Some(att) = read_attribute(constant_pool.clone(), &info, ci) { code_attributes.insert(att.0, att.1); } } @@ -267,12 +265,14 @@ fn read_attribute( ))), )) } - "SourceFile" => Some(("SourceFile".into(), AttributeType::SourceFile)), - "LineNumberTable" => Some(("SourceFile".into(), AttributeType::LineNumberTable)), - "RuntimeVisibleAnnotations" => Some(("".into(), AttributeType::RuntimeInvisibleAnnotations)), //stub - "NestMembers" => Some(("".into(), AttributeType::NestMembers)),//stub - "BootstrapMethods" => Some(("".into(), AttributeType::BootstrapMethods)),//stub - "InnerClasses" => Some(("".into(), AttributeType::InnerClasses)),//stub + "SourceFile" => Some(("SourceFile".into(), AttributeType::SourceFile)), //stub + "LineNumberTable" => Some(("SourceFile".into(), AttributeType::LineNumberTable)), //stub + "RuntimeVisibleAnnotations" => { + Some(("".into(), AttributeType::RuntimeInvisibleAnnotations)) + } //stub + "NestMembers" => Some(("".into(), AttributeType::NestMembers)), //stub + "BootstrapMethods" => Some(("".into(), AttributeType::BootstrapMethods)), //stub + "InnerClasses" => Some(("".into(), AttributeType::InnerClasses)), //stub //TODO more actual attribute implementations _ => None, }; @@ -287,12 +287,12 @@ pub enum CpEntry { Float(f32), Long(i64), Double(f64), - ClassRef(u16), - StringRef(u16), - Fieldref(u16, u16), - MethodRef(u16, u16), - InterfaceMethodref(u16, u16), - NameAndType(u16, u16), + ClassRef(u16), // (utf8) + StringRef(u16), // (utf8) + Fieldref(u16, u16), // (class, name_and_type) + MethodRef(u16, u16), // (class, name_and_type) + InterfaceMethodref(u16, u16), // (class, name_and_type) + NameAndType(u16, u16), // (name, descriptor) MethodHandle(u8, u16), MethodType(u16), InvokeDynamic(u16, u16), diff --git a/src/heap.rs b/src/heap.rs index 25f225a..cbe2637 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -2,7 +2,7 @@ use std::cell::UnsafeCell; use std::fmt; use std::sync::Arc; -use crate::class::{Class, Value}; +use crate::class::{Class, UnsafeValue, Value}; use crate::classloader::CpEntry; // trying to implement efficient object instance storage @@ -10,8 +10,8 @@ pub struct Object { // locked: bool, // hashcode: i32, pub class: Arc, - pub data: Vec>>, -}//arrays + pub data: Vec, +} //arrays // can contain object or array #[derive(Debug)] @@ -36,11 +36,14 @@ unsafe impl Sync for Object {} impl Object { pub fn new(class: Arc) -> Self { let instance_data = Object::init_fields(&class); - Self { class, data: instance_data} + Self { + class, + data: instance_data, + } } // initializes all non-static fields to their default values - pub(crate) fn init_fields(class: &Class) -> Vec>>{ + pub(crate) fn init_fields(class: &Class) -> Vec { let mut field_data = Vec::with_capacity(class.n_fields()); for (_, fields) in class.field_mapping.as_ref().unwrap() { @@ -56,20 +59,36 @@ impl Object { "L" => Value::Null, _ => Value::Void, }; - field_data.push(Arc::new(UnsafeCell::new(value))); + field_data.push(value.into()); } } field_data } - pub fn set(&mut self, class_name: &String, field_name: &String, value: Arc>) { - let (_type, index) = self.class.field_mapping.as_ref().unwrap().get(class_name).unwrap().get(field_name).unwrap(); + pub fn set(&mut self, class_name: &String, field_name: &String, value: UnsafeValue) { + let (_type, index) = self + .class + .field_mapping + .as_ref() + .unwrap() + .get(class_name) + .unwrap() + .get(field_name) + .unwrap(); self.data[*index] = value; } - pub fn get(&mut self, class_name: &String, field_name: &String) -> &Arc> { - let (_type, index) = &self.class.field_mapping.as_ref().unwrap().get(class_name).unwrap().get(field_name).unwrap(); + pub fn get(&mut self, class_name: &String, field_name: &String) -> &UnsafeValue { + let (_type, index) = &self + .class + .field_mapping + .as_ref() + .unwrap() + .get(class_name) + .unwrap() + .get(field_name) + .unwrap(); &self.data[*index] } @@ -90,11 +109,7 @@ impl fmt::Debug for Object { // // r // } // ).collect(); - write!( - f, - "{}", - self.class.name - ) + write!(f, "{}", self.class.name) } } diff --git a/src/io.rs b/src/io.rs index e32bea2..a929a62 100644 --- a/src/io.rs +++ b/src/io.rs @@ -53,7 +53,6 @@ pub fn read_bytecode(name: String) -> Result, Error> { Ok(buffer) } - // methods to read values from big-endian binary data pub(crate) fn read_u8(data: &[u8], pos: &mut usize) -> u8 { @@ -125,4 +124,3 @@ pub(crate) fn read_f64(data: &[u8], pos: &mut usize) -> f64 { .expect("slice with incorrect length"), ) } - diff --git a/src/lib.rs b/src/lib.rs index 4611d8e..afd036b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,3 +4,5 @@ mod heap; pub mod io; pub mod opcodes; pub mod vm; + +pub mod native; diff --git a/src/main.rs b/src/main.rs index 08395cf..ab5ebfc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ fn main() -> Result<(), Error> { // TODO build index for package -> jarfile? let mut vm = Vm::new("tests"); - let main_class = "Main"; + let main_class = "Inheritance"; vm.execute(main_class, "main([Ljava/lang/String;)V", vec![]) .unwrap(); diff --git a/src/native.rs b/src/native.rs new file mode 100644 index 0000000..8691b50 --- /dev/null +++ b/src/native.rs @@ -0,0 +1,8 @@ +use std::sync::Arc; + +use crate::class::{Class, Method, UnsafeValue, Value}; + +pub fn invoke_native(class: Arc, method: &Method) -> UnsafeValue { + println!("invoke native {:?}.{:?}", class.name, method.name()); + Value::void() +} diff --git a/src/opcodes.rs b/src/opcodes.rs index e53d7bd..940697e 100644 --- a/src/opcodes.rs +++ b/src/opcodes.rs @@ -7,13 +7,13 @@ pub const ICONST_2: u8 = 5; // (0x5) Push int constant 2 pub const ICONST_3: u8 = 6; // (0x6) Push int constant 3 pub const ICONST_4: u8 = 7; // (0x7) Push int constant 4 pub const ICONST_5: u8 = 8; // (0x8) Push int constant 5 -pub const LCONST_0: u8 = 9; // (0x9) Push long constant 0 -pub const LCONST_1: u8 = 10; // (0xa) Push long constant 1 +pub const LCONST_0: u8 = 9; // (0x9) Push long constant 0 +pub const LCONST_1: u8 = 10; // (0xa) Push long constant 1 pub const FCONST_0: u8 = 11; // (0xb) Push float 0 pub const FCONST_1: u8 = 12; // (0xc) Push float 1 pub const FCONST_2: u8 = 13; // (0xd) Push float 2 -pub const DCONST_0 :u8 = 14; // (0xe) push double 0 -pub const DCONST_1 :u8 = 15; // (0xe) push double 1 +pub const DCONST_0: u8 = 14; // (0xe) push double 0 +pub const DCONST_1: u8 = 15; // (0xe) push double 1 pub const BIPUSH: u8 = 16; // (0x10) Push byte pub const SIPUSH: u8 = 17; // (0x11) Push short pub const LDC: u8 = 18; // (0x12) Push item from run-time pub constant pool @@ -87,51 +87,51 @@ pub const CASTORE: u8 = 85; // (0x55) Store into char array pub const SASTORE: u8 = 86; // (0x56) Store into short array pub const POP: u8 = 87; // (0x57) Pop the top operand stack value pub const DUP: u8 = 89; // (0x59) duplicate the top operand stack value -// pub const dup_x1: u8 = 90; // (0x5a) Duplicate the top operand stack value and insert two values down -// pub const dup_x2: u8 = 91; // (0x5b) Duplicate the top operand stack value and insert two or three values down -// pub const dup2: u8 = 92; // (0x5c) Duplicate the top one or two operand stack values -// 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 fadd: u8 = 98; // (0x62) Add float -// pub const dadd: u8 = 99; // (0x63) add double -// -// 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 fdiv: u8 = 110; // (0x6e) Divide float -// pub const ddiv:u8 = 111; // (0x6f) divide double -// pub const frem: u8 = 114; // (0x72) Remainder float -// pub const drem: u8 = 115; // (0x73) remainder double -// pub const fneg: u8 = 118; // (0x76) Negate float -// pub const dneg: u8 = 119; // (0x77) Negate double -// pub const f2i: u8 = 139; // (0x8b) Convert float to int -// pub const f2l: u8 = 140; // (0x8c) Convert float to long -// pub const f2d: u8 = 141; // (0x8d) Convert float to double -// pub const d2i:u8 = 142; // (0x8e) double to int -// pub const d2l:u8 = 143; // (0x8f) double to long -// pub const d2f: u8 = 144; // (0x90) double to float -// pub const fcmpl:u8 = 149; // (0x95) Compare float (less than) -// pub const fcmpg: u8 = 150; // (0x96) Compare float (greater than) -// pub const dcmpl:u8 = 151; // (0x97) compare double (less than) -// pub const dcmpg:u8 = 152; // (0x98) compare double (greater than) -// +pub const dup_x1: u8 = 90; // (0x5a) Duplicate the top operand stack value and insert two values down +pub const dup_x2: u8 = 91; // (0x5b) Duplicate the top operand stack value and insert two or three values down +pub const dup2: u8 = 92; // (0x5c) Duplicate the top one or two operand stack values +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 fadd: u8 = 98; // (0x62) Add float +pub const dadd: u8 = 99; // (0x63) add double + +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 fdiv: u8 = 110; // (0x6e) Divide float +pub const ddiv: u8 = 111; // (0x6f) divide double +pub const frem: u8 = 114; // (0x72) Remainder float +pub const drem: u8 = 115; // (0x73) remainder double +pub const fneg: u8 = 118; // (0x76) Negate float +pub const dneg: u8 = 119; // (0x77) Negate double + +pub const f2i: u8 = 139; // (0x8b) Convert float to int +pub const f2l: u8 = 140; // (0x8c) Convert float to long +pub const f2d: u8 = 141; // (0x8d) Convert float to double +pub const d2i: u8 = 142; // (0x8e) double to int +pub const d2l: u8 = 143; // (0x8f) double to long +pub const d2f: u8 = 144; // (0x90) double to float + +pub const fcmpl: u8 = 149; // (0x95) Compare float (less than) +pub const fcmpg: u8 = 150; // (0x96) Compare float (greater than) +pub const dcmpl: u8 = 151; // (0x97) compare double (less than) +pub const dcmpg: u8 = 152; // (0x98) compare double (greater than) + pub const IRETURN: u8 = 172; // (0xac) ireturn pub const FRETURN: u8 = 174; // (0xae) Return float from method pub const DRETURN: u8 = 175; // (0xaf) Return double from method - // pub const areturn: u8 = 176; //(0xb0) return reference +pub const areturn: u8 = 176; //(0xb0) return reference pub const RETURN_VOID: u8 = 177; // (0xb1) Return void from method (actually 'return' but that's a keyword) pub const GETSTATIC: u8 = 178; // (0xb2) Get static field from class pub const GETFIELD: u8 = 180; // (0xb4) Fetch field from object3 pub const PUTFIELD: u8 = 181; // (0xb5) Set field in object pub const INVOKEVIRTUAL: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class -pub const NEW: u8 = 187; // (0xbb) Create new object -// pub const INVOKESPECIAL: u8 = 183; // (0xb7) // nvoke instance method; direct invocation of instance initialization methods and methods of the current class and its supertypes - // pub const anewarray: u8 = 189; // (0xbd) - // - // pub const arraylength: u8 = 190; // (0xbe) - // - // pub const athrow: u8 = 191; // (0xbf) - // - // pub const checkcast: u8 = 192; // (0xc0) +pub const INVOKESTATIC: u8 = 184; // (0xb8) Invoke a class (static) method +pub const NEW: u8 = 187; // (0xbb) Create new object +pub const anewarray: u8 = 189; // (0xbd) +pub const arraylength: u8 = 190; // (0xbe) +pub const athrow: u8 = 191; // (0xbf) +pub const checkcast: u8 = 192; // (0xc0) diff --git a/src/vm.rs b/src/vm.rs index cd0669a..aacdac1 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -6,17 +6,18 @@ use std::sync::Arc; use anyhow::{anyhow, Error}; use once_cell::unsync::Lazy; -use crate::class::{AttributeType, Class, Value}; use crate::class::Value::Void; -use crate::classloader::{CpEntry, load_class}; +use crate::class::{AttributeType, Class, Modifier, UnsafeValue, Value}; +use crate::classloader::{load_class, CpEntry}; use crate::heap::{Heap, Object, ObjectRef}; use crate::io::*; +use crate::native::invoke_native; use crate::opcodes::*; #[derive(Debug)] struct StackFrame { at: String, - data: Vec>>, + data: Vec, } // maybe just call frame @@ -32,11 +33,11 @@ impl StackFrame { self.data.push(Arc::new(UnsafeCell::new(val))); } - fn push_arc(&mut self, val: Arc>) { + fn push_arc(&mut self, val: UnsafeValue) { self.data.push(val); } - fn pop(&mut self) -> Result>, Error> { + fn pop(&mut self) -> Result { Ok(self.data.pop().unwrap()) } } @@ -67,7 +68,10 @@ impl Vm { pub fn new(classpath: &'static str) -> Self { Self { - classpath: classpath.split(PATH_SEPARATOR).map(|s| s.to_owned()).collect(), + classpath: classpath + .split(PATH_SEPARATOR) + .map(|s| s.to_owned()) + .collect(), heap: Heap::new(), stack: vec![], } @@ -81,7 +85,7 @@ impl Vm { unsafe { let entry = CLASSDEFS.entry(class_name.into()); let entry = entry.or_insert_with(|| { - // print!("read class {} ", class_name); + println!("read class {} ", class_name); let resolved_path = find_class(&self.classpath, class_name).unwrap(); // println!("full path {}", resolved_path); let bytecode = read_bytecode(resolved_path).unwrap(); @@ -106,19 +110,31 @@ impl Vm { instance } - /// execute the bytecode /// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM pub fn execute( &mut self, class_name: &str, method_name: &str, - args: Vec>>, - ) -> Result>, Error> { - let mut local_params: Vec>>> = args.clone().iter().map(|e| Some(e.clone())).collect(); + args: Vec, + ) -> Result { + let mut local_params: Vec> = + args.clone().iter().map(|e| Some(e.clone())).collect(); println!("execute {}.{}", class_name, method_name); let class = self.get_class(class_name)?; let method = class.get_method(method_name)?; + if method.is(Modifier::Native) { + let return_value = invoke_native(class.clone(), method); + unsafe { + match *return_value.get() { + Void => {} + _ => { + self.local_stack().push_arc(return_value.clone()); + } + } + } + } + if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() { let stackframe = StackFrame::new(class_name, method_name); self.stack.push(stackframe); @@ -221,25 +237,31 @@ impl Vm { } } } - ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => { // omitting the type checks so far + ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => { + // omitting the type checks so far let n = read_u8(&code.opcodes, pc) as usize; - self.local_stack().push_arc(local_params[n].as_ref().unwrap().clone()); + self.local_stack() + .push_arc(local_params[n].as_ref().unwrap().clone()); } ILOAD_0 | LLOAD_0 | FLOAD_0 | DLOAD_0 | ALOAD_0 => { - self.local_stack().push_arc(local_params[0].as_ref().unwrap().clone()); + self.local_stack() + .push_arc(local_params[0].as_ref().unwrap().clone()); } ILOAD_1 | LLOAD_1 | FLOAD_1 | DLOAD_1 | ALOAD_1 => { - self.local_stack().push_arc(local_params[1].as_ref().unwrap().clone()); + self.local_stack() + .push_arc(local_params[1].as_ref().unwrap().clone()); } ILOAD_2 | LLOAD_2 | FLOAD_2 | DLOAD_2 | ALOAD_2 => { - self.local_stack().push_arc(local_params[2].as_ref().unwrap().clone()); + self.local_stack() + .push_arc(local_params[2].as_ref().unwrap().clone()); } ILOAD_3 | LLOAD_3 | FLOAD_3 | DLOAD_3 | ALOAD_3 => { - self.local_stack().push_arc(local_params[3].as_ref().unwrap().clone()); + self.local_stack() + .push_arc(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)?; @@ -256,7 +278,8 @@ impl Vm { 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()? } + BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE + | AASTORE => unsafe { self.array_store()? }, POP => { self.local_stack().pop()?; } @@ -271,41 +294,44 @@ impl Vm { } RETURN_VOID => { self.stack.pop(); // Void is also returned as a value - return Ok(Arc::new(UnsafeCell::new(Void))); + return Ok(Value::void()); } GETSTATIC => { let cp_index = read_u16(&code.opcodes, pc); - let (class_index, _field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid - let class_name_index = class.get_class_ref(class_index).unwrap(); - let class_name = class.get_utf8(class_name_index).unwrap(); + let (class_index, _field_name_and_type_index) = + class.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid + let class_name_index = class.cp_class_ref(class_index).unwrap(); + let class_name = class.cp_utf8(class_name_index).unwrap(); let class = self.get_class(class_name.as_str())?; - println!("{:?}", class); //TODO + // println!("{:?}", class); //TODO } - GETFIELD => { - unsafe { - let cp_index = read_u16(&code.opcodes, pc); - let (class_index, field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap(); - let (field_name_index, _) = class.get_name_and_type(field_name_and_type_index).unwrap(); - let class_name_index = class.get_class_ref(class_index).unwrap(); - let class_name = class.get_utf8(class_name_index).unwrap(); - let field_name = class.get_utf8(field_name_index).unwrap(); + GETFIELD => unsafe { + let cp_index = read_u16(&code.opcodes, pc); + let (class_index, field_name_and_type_index) = + class.cp_field_ref(&cp_index).unwrap(); + let (field_name_index, _) = + class.cp_name_and_type(field_name_and_type_index).unwrap(); + let class_name_index = class.cp_class_ref(class_index).unwrap(); + let class_name = class.cp_utf8(class_name_index).unwrap(); + let field_name = class.cp_utf8(field_name_index).unwrap(); - let mut objectref = self.local_stack().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.local_stack().push_arc(Arc::clone(value)); - } + let mut objectref = self.local_stack().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.local_stack().push_arc(Arc::clone(value)); } } - } + }, PUTFIELD => unsafe { let cp_index = read_u16(&code.opcodes, pc); - let (class_index, field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap(); - let (field_name_index, _) = class.get_name_and_type(field_name_and_type_index).unwrap(); - let class_name_index = class.get_class_ref(class_index).unwrap(); - let class_name = class.get_utf8(class_name_index).unwrap(); - let field_name = class.get_utf8(field_name_index).unwrap(); + let (class_index, field_name_and_type_index) = + class.cp_field_ref(&cp_index).unwrap(); + let (field_name_index, _) = + class.cp_name_and_type(field_name_and_type_index).unwrap(); + let class_name_index = class.cp_class_ref(class_index).unwrap(); + let class_name = class.cp_utf8(class_name_index).unwrap(); + let field_name = class.cp_utf8(field_name_index).unwrap(); let value = self.local_stack().pop()?; let mut objectref = self.local_stack().pop()?; @@ -314,29 +340,61 @@ impl Vm { object.set(class_name, field_name, value); } } - } + }, INVOKEVIRTUAL | INVOKESPECIAL => unsafe { let cp_index = read_u16(&code.opcodes, pc); - if let Some(invocation) = get_signature_for_invoke(&method.constant_pool, cp_index) { + 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.local_stack().pop()?); } args.insert(0, self.local_stack().pop()?); - let mut returnvalue = self.execute(&invocation.class_name, &invocation.method.name, args)?; - match *returnvalue.get() { + let mut return_value = self.execute( + &invocation.class_name, + &invocation.method.name, + args, + )?; + match *return_value.get() { Void => {} - _ => { self.local_stack().push_arc(returnvalue.clone()); } + _ => { + self.local_stack().push_arc(return_value.clone()); + } } } - } + }, + 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.local_stack().pop()?); + } + let mut returnvalue = self.execute( + &invocation.class_name, + &invocation.method.name, + args, + )?; + match *returnvalue.get() { + Void => {} + _ => { + self.local_stack().push_arc(returnvalue.clone()); + } + } + } + }, NEW => { let class_index = &read_u16(&code.opcodes, pc); - let class_name_index = class.get_class_ref(class_index).unwrap(); - let class_name = class.get_utf8(class_name_index).unwrap(); + let class_name_index = class.cp_class_ref(class_index).unwrap(); + let class_name = class.cp_utf8(class_name_index).unwrap(); let class = self.get_class(class_name)?; - let object = Arc::new(UnsafeCell::new(ObjectRef::Object(Box::new(Vm::new_instance(class))))); + let object = Arc::new(UnsafeCell::new(ObjectRef::Object(Box::new( + Vm::new_instance(class), + )))); self.local_stack().push(Value::Ref(Arc::clone(&object))); self.heap.new_object(object); } @@ -386,7 +444,8 @@ impl Vm { self.local_stack().push(Value::F64(array[index])); } ObjectRef::ObjectArray(ref array) => { - self.local_stack().push(Value::Ref(array.get(index).unwrap().clone())); + self.local_stack() + .push(Value::Ref(array.get(index).unwrap().clone())); } ObjectRef::Object(_) => {} //throw error? } @@ -408,12 +467,14 @@ impl Vm { if let Value::Ref(ref mut objectref) = arrayref { match &mut *objectref.get() { ObjectRef::ByteArray(ref mut array) => { - if let Value::I32(value) = *value.get() { // is i32 correct? + if let Value::I32(value) = *value.get() { + // is i32 correct? array[*index as usize] = value as i8; } } ObjectRef::ShortArray(ref mut array) => { - if let Value::I32(value) = *value.get() { // is i32 correct? + if let Value::I32(value) = *value.get() { + // is i32 correct? array[*index as usize] = value as i16; } } @@ -452,14 +513,18 @@ impl Vm { array[*index as usize] = value.clone(); } } - ObjectRef::Object(_) => {}//throw error? + ObjectRef::Object(_) => {} //throw error? } } } Ok(()) } - fn store(&mut self, local_params: &mut Vec>>>, index: usize) -> Result<(), Error> { + fn store( + &mut self, + local_params: &mut Vec>, + index: usize, + ) -> Result<(), Error> { let value = self.local_stack().pop()?; while local_params.len() < index + 1 { local_params.push(None); @@ -469,7 +534,6 @@ impl Vm { } } - struct Invocation { class_name: String, method: MethodSignature, @@ -480,8 +544,11 @@ struct MethodSignature { 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) = cp.get(&index).unwrap() { + 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() { @@ -503,14 +570,16 @@ fn get_name_and_type(cp: Rc>, index: u16) -> Option usize { let mut num = 0; let mut i = 1; @@ -531,4 +600,4 @@ fn get_hum_args(signature: &str) -> usize { } } num -} \ No newline at end of file +} diff --git a/tests/class_tests.rs b/tests/class_tests.rs index 344e4e9..cf01887 100644 --- a/tests/class_tests.rs +++ b/tests/class_tests.rs @@ -1,8 +1,6 @@ mod test { - use classfile_reader::class::Value; - use classfile_reader::vm::Vm; - use classfile_reader::{classloader::load_class, io}; - use std::rc::Rc; + use java_rs::class::Value; + use java_rs::vm::Vm; use std::sync::Arc; #[test] diff --git a/tests/method_tests.rs b/tests/method_tests.rs new file mode 100644 index 0000000..1f58d08 --- /dev/null +++ b/tests/method_tests.rs @@ -0,0 +1,19 @@ +mod test { + use java_rs::class::{Method, Modifier}; + use std::collections::HashMap; + use std::rc::Rc; + + #[test] + fn access_flags() { + let m = Method::new( + Rc::new(HashMap::new()), + Modifier::Public as u16 | Modifier::Static as u16, + 0, + 0, + HashMap::new(), + ); + assert!(m.is(Modifier::Public)); + assert!(m.is(Modifier::Static)); + assert!(!m.is(Modifier::Private)); + } +}