diff --git a/src/class.rs b/src/class.rs index aa40223..15699b3 100644 --- a/src/class.rs +++ b/src/class.rs @@ -10,10 +10,7 @@ pub(crate) struct TypeIndex { impl TypeIndex { pub(crate) fn new(type_name: String, index: usize) -> Self { - Self { - type_name, - index, - } + Self { type_name, index } } } @@ -40,4 +37,4 @@ impl Class { .reduce(|acc, e| acc + e) .unwrap_or(0) } -} \ No newline at end of file +} diff --git a/src/classloader/classdef.rs b/src/classloader/classdef.rs index 7af49b4..3bd4149 100644 --- a/src/classloader/classdef.rs +++ b/src/classloader/classdef.rs @@ -21,7 +21,7 @@ pub(crate) struct ClassDef { pub attributes: HashMap, } -impl Debug for ClassDef{ +impl Debug for ClassDef { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{}", self.cp_class_name(&self.this_class)) } diff --git a/src/classloader/code_parser.rs b/src/classloader/code_parser.rs index e60908f..e21992c 100644 --- a/src/classloader/code_parser.rs +++ b/src/classloader/code_parser.rs @@ -1,7 +1,9 @@ -use std::collections::{BTreeMap}; use log::debug; +use std::collections::BTreeMap; -use crate::classloader::io::{read_i16, read_i32, read_lookupswitch, read_tableswitch, read_u16, read_u8, read_wide_opcode}; +use crate::classloader::io::{ + read_i16, read_i32, read_lookupswitch, read_tableswitch, read_u16, read_u8, read_wide_opcode, +}; use crate::vm::opcodes::Opcode::{self, *}; pub(crate) fn parse_code(opcodes: &[u8]) -> Vec { @@ -19,56 +21,28 @@ pub(crate) fn parse_code(opcodes: &[u8]) -> Vec { // for jumps, map index of opcode as u8 to index of opcode as enum debug!("{:?}", code); - code.into_iter().map(|(_, (_, opcode))| - match opcode { - IFNULL(goto) => { - IFNULL(code2.get(&goto).unwrap().0) - } - IFNONNULL(goto) => { - IFNONNULL(code2.get(&goto).unwrap().0) - } + code.into_iter() + .map(|(_, (_, opcode))| match opcode { + IFNULL(goto) => IFNULL(code2.get(&goto).unwrap().0), + IFNONNULL(goto) => IFNONNULL(code2.get(&goto).unwrap().0), - IF_ICMPEQ(goto) => { - IF_ICMPEQ(code2.get(&goto).unwrap().0) - } - IF_ICMPNE(goto) => { - IF_ICMPNE(code2.get(&goto).unwrap().0) - } - IF_ICMPGT(goto) => { - IF_ICMPGT(code2.get(&goto).unwrap().0) - } - IF_ICMPGE(goto) => { - IF_ICMPGE(code2.get(&goto).unwrap().0) - } - IF_ICMPLT(goto) => { - IF_ICMPLT(code2.get(&goto).unwrap().0) - } - IF_ICMPLE(goto) => { - IF_ICMPLE(code2.get(&goto).unwrap().0) - } - IFEQ(goto) => { - IFEQ(code2.get(&goto).unwrap().0) - } - IFNE(goto) => { - IFNE(code2.get(&goto).unwrap().0) - } - IFGT(goto) => { - IFGT(code2.get(&goto).unwrap().0) - } - IFGE(goto) => { - IFGE(code2.get(&goto).unwrap().0) - } - IFLT(goto) => { - IFLT(code2.get(&goto).unwrap().0) - } - IFLE(goto) => { - IFLE(code2.get(&goto).unwrap().0) - } + IF_ICMPEQ(goto) => IF_ICMPEQ(code2.get(&goto).unwrap().0), + IF_ICMPNE(goto) => IF_ICMPNE(code2.get(&goto).unwrap().0), + IF_ICMPGT(goto) => IF_ICMPGT(code2.get(&goto).unwrap().0), + IF_ICMPGE(goto) => IF_ICMPGE(code2.get(&goto).unwrap().0), + IF_ICMPLT(goto) => IF_ICMPLT(code2.get(&goto).unwrap().0), + IF_ICMPLE(goto) => IF_ICMPLE(code2.get(&goto).unwrap().0), + IFEQ(goto) => IFEQ(code2.get(&goto).unwrap().0), + IFNE(goto) => IFNE(code2.get(&goto).unwrap().0), + IFGT(goto) => IFGT(code2.get(&goto).unwrap().0), + IFGE(goto) => IFGE(code2.get(&goto).unwrap().0), + IFLT(goto) => IFLT(code2.get(&goto).unwrap().0), + IFLE(goto) => IFLE(code2.get(&goto).unwrap().0), //TODO more jump instructions - _ => opcode - } - ).collect() + _ => opcode, + }) + .collect() } fn get_opcode(opcodes: &[u8], c: &mut usize) -> Opcode { @@ -280,23 +254,19 @@ fn get_opcode(opcodes: &[u8], c: &mut usize) -> Opcode { 195 => MONITOREXIT, 196 => WIDE(Box::new(read_wide_opcode(opcodes, c))), 197 => MULTIANEWARRAY(read_u16(opcodes, c), read_u8(opcodes, c)), - 198 => { - IFNULL(offset(opcodes, c)) - } - 199 => { - IFNONNULL(offset(opcodes, c)) - } + 198 => IFNULL(offset(opcodes, c)), + 199 => IFNONNULL(offset(opcodes, c)), 200 => GOTOW(read_i32(opcodes, c)), 201 => JSR_W(read_i32(opcodes, c)), _ => panic!("{}", opcode_u8), }; - debug!("{}: {:?}", c, opcode); + // debug!("{}: {:?}", c, opcode); opcode } fn offset(opcodes: &[u8], c: &mut usize) -> u16 { let j = read_i16(opcodes, c); - debug!("JUMP TO {} + {}",c, j); + // debug!("JUMP TO {} + {}",c, j); (*c as i16 + j - 3) as u16 -} \ No newline at end of file +} diff --git a/src/classloader/io.rs b/src/classloader/io.rs index 8891a62..56f862a 100644 --- a/src/classloader/io.rs +++ b/src/classloader/io.rs @@ -1,8 +1,8 @@ use std::fs::{self}; -use anyhow::{anyhow, Error}; use crate::vm::opcodes::Opcode; use crate::vm::opcodes::Opcode::*; +use anyhow::{anyhow, Error}; #[cfg(target_family = "unix")] pub const PATH_SEPARATOR: char = ':'; @@ -44,7 +44,6 @@ pub fn find_class(classpath: &Vec, class_name: &str) -> Result u8 { @@ -137,7 +136,12 @@ pub(crate) fn read_tableswitch(data: &[u8], pos: &mut usize) -> Tableswitch { for _ in low..=high { offsets.push(read_i32(data, pos)); } - Tableswitch { default, low, high, offsets } + Tableswitch { + default, + low, + high, + offsets, + } } pub(crate) fn read_lookupswitch(data: &[u8], pos: &mut usize) -> Lookupswitch { @@ -150,7 +154,10 @@ pub(crate) fn read_lookupswitch(data: &[u8], pos: &mut usize) -> Lookupswitch { for _ in 0..npairs { match_offset_pairs.push((read_i32(data, pos), read_i32(data, pos))); } - Lookupswitch { default, match_offset_pairs } + Lookupswitch { + default, + match_offset_pairs, + } } pub(crate) fn read_wide_opcode(data: &[u8], pos: &mut usize) -> Opcode { @@ -171,7 +178,9 @@ pub(crate) fn read_wide_opcode(data: &[u8], pos: &mut usize) -> Opcode { 57 => WIDE_DSTORE(index), 58 => WIDE_ASTORE(index), 169 => WIDE_RET(index), - _ => { unreachable!("unknown opcode for WIDE") } + _ => { + unreachable!("unknown opcode for WIDE") + } } } } @@ -188,4 +197,4 @@ pub(crate) struct Tableswitch { pub(crate) struct Lookupswitch { default: i32, match_offset_pairs: Vec<(i32, i32)>, -} \ No newline at end of file +} diff --git a/src/classloader/mod.rs b/src/classloader/mod.rs index c4902a8..03792a5 100644 --- a/src/classloader/mod.rs +++ b/src/classloader/mod.rs @@ -7,15 +7,19 @@ use std::rc::Rc; use anyhow::Error; use log::debug; -use crate::classloader::io::{find_class, read_bytes, read_f32, read_f64, read_i32, read_i64, read_u16, read_u32, read_u8}; -use crate::classloader::classdef::{AttributeType, ClassDef, CpEntry, Exception, Field, Method, MethodCode}; +use crate::classloader::classdef::{ + AttributeType, ClassDef, CpEntry, Exception, Field, Method, MethodCode, +}; use crate::classloader::code_parser::parse_code; +use crate::classloader::io::{ + find_class, read_bytes, read_f32, read_f64, read_i32, read_i64, read_u16, read_u32, read_u8, +}; pub mod classdef; -pub(crate) mod io; mod code_parser; +pub(crate) mod io; -pub(crate) fn get_classdef(classpath: &Vec, class_name: &str) -> Result { +pub(crate) fn get_classdef(classpath: &Vec, class_name: &str) -> Result { debug!("read class {} ", class_name); let resolved_path = find_class(classpath, class_name)?; let bytecode = read_bytecode(resolved_path)?; @@ -64,7 +68,11 @@ fn load_class(bytecode: Vec) -> Result { let access_flags = read_u16(&bytecode, pos); let this_class = read_u16(&bytecode, pos); let super_class = read_u16(&bytecode, pos); - let super_class = if super_class != 0 { Some(super_class) } else { None }; + let super_class = if super_class != 0 { + Some(super_class) + } else { + None + }; let interfaces_count = read_u16(&bytecode, pos); let mut interfaces = vec![]; for _ in 0..interfaces_count { @@ -96,8 +104,6 @@ fn load_class(bytecode: Vec) -> Result { } } - - Ok(ClassDef::new( minor_version, major_version, @@ -243,10 +249,9 @@ fn read_method( } } - let code = - if let Some(AttributeType::Code(code)) = attributes.get("Code") { + let code = if let Some(AttributeType::Code(code)) = attributes.get("Code") { parse_code(&code.opcodes) - } else{ + } else { vec![] }; @@ -256,7 +261,7 @@ fn read_method( name_index, descriptor_index, attributes, - code + code, ) } @@ -319,12 +324,11 @@ fn read_attribute( "InnerClasses" => Some(("".into(), AttributeType::InnerClasses)), //stub "Signature" => Some(("".into(), AttributeType::Signature)), //stub "NestHost" => Some(("".into(), AttributeType::NestHost)), //stub - "EnclosingMethod" => Some(("".into(), AttributeType::EnclosingMethod)), //stub - "PermittedSubclasses" => Some(("".into(), AttributeType::PermittedSubclasses)), //stub + "EnclosingMethod" => Some(("".into(), AttributeType::EnclosingMethod)), //stub + "PermittedSubclasses" => Some(("".into(), AttributeType::PermittedSubclasses)), //stub //TODO more actual attribute implementations _ => None, }; } None } - diff --git a/src/classmanager.rs b/src/classmanager.rs index 9c9ce7e..03c531e 100644 --- a/src/classmanager.rs +++ b/src/classmanager.rs @@ -8,12 +8,13 @@ use once_cell::sync::Lazy; use crate::class::{Class, ClassId, TypeIndex}; use crate::classloader; use crate::classloader::classdef::{ClassDef, Method, Modifier}; -use crate::vm::object::{Object, ObjectRef}; use crate::value::Value; use crate::value::Value::*; +use crate::vm::object::{Object, ObjectRef}; use crate::vm::runtime::Vm; -static PRIMITIVES: Lazy> = Lazy::new(|| vec!["B", "S", "I", "J", "F", "D", "Z", "J", "C"]); +static PRIMITIVES: Lazy> = + Lazy::new(|| vec!["B", "S", "I", "J", "F", "D", "Z", "J", "C"]); //TODO less pubs pub struct ClassManager { @@ -112,8 +113,10 @@ impl ClassManager { // in cache? let id = self.names.get(&type_name); match id { - Some(id) => if self.classes.get(id).is_none() { - self.add_class(&type_name); + Some(id) => { + if self.classes.get(id).is_none() { + self.add_class(&type_name); + } } None => { self.add_class(&type_name); @@ -167,42 +170,58 @@ impl ClassManager { while let Some(c) = current_id { parents.push_front(current_id.unwrap()); current_classdef = self.classdefs.get(&c).unwrap(); - Self::add_fields_for_this_or_parents(&mut object_field_mapping, &mut static_field_mapping, object_field_map_index, static_field_map_index, current_classdef); + Self::add_fields_for_this_or_parents( + &mut object_field_mapping, + &mut static_field_mapping, + object_field_map_index, + static_field_map_index, + current_classdef, + ); - current_id = current_classdef.super_class.as_ref() + current_id = current_classdef + .super_class + .as_ref() .map(|i| current_classdef.cp_class_name(i).to_owned()) .map(|n| *self.names.get(&n).unwrap()); } //handrolled references to superclass and interfaces - let superclass_id = this_classdef.super_class.as_ref() + let superclass_id = this_classdef + .super_class + .as_ref() .map(|i| this_classdef.cp_class_name(i).to_owned()) .map(|n| *self.names.get(&n).unwrap()); - let interface_ids: Vec = this_classdef.interfaces.iter() + let interface_ids: Vec = this_classdef + .interfaces + .iter() .map(|i| this_classdef.cp_class_name(i).to_owned()) .map(|n| *self.names.get(n.as_str()).unwrap()) .collect(); // initial values for static fields (before static init) - self.static_class_data.insert(this_classid, Self::set_field_data(&static_field_mapping)); + self.static_class_data + .insert(this_classid, Self::set_field_data(&static_field_mapping)); - self.classes.insert(this_classid, Class { - id: this_classid, - initialized: false, - name: name.into(), - superclass: superclass_id, - parents, - interfaces: interface_ids, - object_field_mapping, - static_field_mapping, - }); + self.classes.insert( + this_classid, + Class { + id: this_classid, + initialized: false, + name: name.into(), + superclass: superclass_id, + parents, + interfaces: interface_ids, + object_field_mapping, + static_field_mapping, + }, + ); // add a new Class instance 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())); + instance.set(cls, "java/lang/Class", "name", Utf8(name.into())); let instance = Ref(ObjectRef::Object(Rc::new(RefCell::new(instance)))); self.class_objects.insert(this_classid, instance); @@ -210,28 +229,34 @@ impl ClassManager { // run static init if this_classdef.methods.contains_key("()V") { - Vm { stack: Vec::new()}.run2(self, this_classid,"()V"); + Vm { stack: Vec::new() }.run2(self, this_classid, "()V"); } this_classid } /// like described above - 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, - current_classdef: &ClassDef) { + 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, + current_classdef: &ClassDef, + ) { let mut instance_field_mappings: HashMap = HashMap::new(); let mut static_field_mappings: HashMap = HashMap::new(); for (field_name, field) in ¤t_classdef.fields { if !field.is(Modifier::Static) { - instance_field_mappings.insert(field_name.to_owned(), - TypeIndex::new(field.type_of().to_owned(), *object_field_map_index)); + instance_field_mappings.insert( + field_name.to_owned(), + TypeIndex::new(field.type_of().to_owned(), *object_field_map_index), + ); *object_field_map_index += 1; } else { - static_field_mappings.insert(field_name.to_owned(), - TypeIndex::new(field.type_of().to_owned(), *static_field_map_index)); + static_field_mappings.insert( + field_name.to_owned(), + TypeIndex::new(field.type_of().to_owned(), *static_field_map_index), + ); *static_field_map_index += 1; } } @@ -258,9 +283,9 @@ impl ClassManager { let class_name = class_name.to_owned().replace(".", "/"); let id = self.get_or_new_id(class_name.clone()); - let classdef = self.classdefs - .entry(id) - .or_insert_with(|| classloader::get_classdef(&self.classpath, class_name.as_str()).expect("ClassNotFound")); + let classdef = self.classdefs.entry(id).or_insert_with(|| { + classloader::get_classdef(&self.classpath, class_name.as_str()).expect("ClassNotFound") + }); (id, inspect_dependencies(classdef)) } @@ -272,7 +297,9 @@ impl ClassManager { id } - pub(crate) fn set_field_data(field_mapping: &HashMap>) -> Vec { + pub(crate) fn set_field_data( + field_mapping: &HashMap>, + ) -> Vec { let mut field_data = vec![Null; n_fields(field_mapping)]; for (_, this_class) in field_mapping { @@ -346,27 +373,99 @@ mod test { // 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)); + 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)); + 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())); + 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())); + 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())); + 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: false, name: "".into(), superclass: None, parents: LinkedList::new(), interfaces: vec![], object_field_mapping: class_field_mapping, static_field_mapping: 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: false, + 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(), @@ -381,7 +480,25 @@ mod test { 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); + 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/lib.rs b/src/lib.rs index 580a3c0..e35d9d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ +mod class; pub mod classloader; pub mod classmanager; mod value; -mod class; -pub mod vm; \ No newline at end of file +pub mod vm; diff --git a/src/main.rs b/src/main.rs index df0260b..814f931 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,9 @@ use java_rs::vm::runtime::Vm; fn main() { let mut vm = Vm::new(); - vm.run("/Users/Shautvast/dev/java.rs/tests", "testclasses/Main", "main([Ljava/lang/String;)V"); + vm.run( + "/Users/Shautvast/dev/java.rs/tests", + "testclasses/Main", + "main([Ljava/lang/String;)V", + ); } - diff --git a/src/value.rs b/src/value.rs index d56f5a8..c5528b7 100644 --- a/src/value.rs +++ b/src/value.rs @@ -29,6 +29,14 @@ impl Value { } } + pub fn into_f32(self) -> f32 { + if let Value::F32(v) = self { + v + } else { + panic!("{:?} is not F32", self); + } + } + pub fn into_object(self) -> ObjectRef { if let Value::Ref(v) = self { v @@ -36,4 +44,4 @@ impl Value { panic!(); } } -} \ No newline at end of file +} diff --git a/src/vm/array.rs b/src/vm/array.rs index 1d55d66..8b1e3a3 100644 --- a/src/vm/array.rs +++ b/src/vm/array.rs @@ -1,10 +1,9 @@ -use anyhow::{anyhow, Error}; use crate::vm::object::ObjectRef::*; +use anyhow::{anyhow, Error}; use crate::value::Value; use crate::value::Value::*; - pub(crate) fn array_load(index: Value, arrayref: Value) -> Result { if let I32(index) = index { let index = index as usize; @@ -100,7 +99,7 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result } else { unreachable!() } - } + }, LongArray(ref mut array) => { if let I64(value) = value { array[index as usize] = value; @@ -143,4 +142,4 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result unreachable!() } Ok(()) -} \ No newline at end of file +} diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 2128f3b..f7fa0a2 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,5 +1,5 @@ mod array; +mod native; pub(crate) mod object; pub(crate) mod opcodes; -pub mod runtime; -mod native; \ No newline at end of file +pub mod runtime; \ No newline at end of file diff --git a/src/vm/native.rs b/src/vm/native.rs index 22eb6e7..0dfcfe9 100644 --- a/src/vm/native.rs +++ b/src/vm/native.rs @@ -1,65 +1,124 @@ #![allow(non_snake_case)] use std::cell::RefCell; +use std::collections::HashMap; +use std::future::Future; use std::rc::Rc; use anyhow::Error; use log::debug; use once_cell::sync::Lazy; + use crate::classmanager::ClassManager; use crate::value::Value; -use crate::value::Value::{I32, Void}; -use crate::vm::object::ObjectRef; +use crate::value::Value::{Utf8, Void, I32}; use crate::vm::object::ObjectRef::Object; -use crate::vm::runtime::{Stackframe, Vm}; +use crate::vm::object::{self, ObjectRef}; +use crate::vm::runtime::Stackframe; +const primitive_name_classes: Lazy> = Lazy::new(|| { + let mut mapping = HashMap::new(); + mapping.insert("B", "byte"); + mapping.insert("S", "short"); + mapping.insert("I", "int"); + mapping.insert("J", "long"); + mapping.insert("F", "float"); + mapping.insert("D", "double"); + mapping.insert("C", "char"); + mapping.insert("Z", "boolean"); + mapping +}); +static mut PRIMITIVE_CLASSES: Lazy> = Lazy::new(|| HashMap::new()); -pub fn invoke_native(class_manager: &mut ClassManager, class_name: &str, method_name: &str, _args: Vec) -> Result { +pub fn invoke_native( + class_manager: &mut ClassManager, + class_name: &str, + method_name: &str, + args: Vec, +) -> Result { debug!("native {}.{}", class_name, method_name); match class_name { - "java/lang/Class" => java_lang_Class(method_name), + "java/lang/Class" => java_lang_Class(class_manager, 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!("") + "jdk/internal/util/SystemProps$Raw" => { + jdk_internal_util_SystemProps_Raw(class_manager, method_name) + } + _ => unimplemented!(""), } } -fn java_lang_Class(method_name: &str) -> Result { +fn java_lang_Class( + class_manager: &mut ClassManager, + method_name: &str, + args: Vec, +) -> Result { Ok(match method_name { "desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false), - _ => Void + "getPrimitiveClass(Ljava/lang/String;)Ljava/lang/Class;" => { + get_primitive_class(class_manager, args) + } + _ => Void, }) } fn java_lang_System(method_name: &str) -> Result { Ok(match method_name { - _ => Void + _ => Void, }) } +fn get_primitive_class(class_manager: &mut ClassManager, args: Vec) -> Value { + if let Utf8(primitive) = args.get(0).unwrap().to_owned() { + unsafe { + PRIMITIVE_CLASSES + .entry(primitive.clone()) + .or_insert_with(|| { + let cls = class_manager.get_class_by_name("java/lang/Class").unwrap(); + let mut instance = object::Object::new(cls); + instance.set( + cls, + "java/lang/Class", + primitive_name_classes.get(primitive.as_str()).unwrap(), + Utf8("name".into()), + ); + Value::Ref(Object(Rc::new(RefCell::new(instance)))) + }); + } + } + + Value::Null +} + fn jdk_internal_misc_Unsafe(method_name: &str) -> Result { Ok(match method_name { "arrayBaseOffset0(Ljava/lang/Class;)I" => I32(0), //TODO surely this is not right "arrayIndexScale0(Ljava/lang/Class;)I" => I32(0), //TODO surely this is not right - _ => Void + _ => Void, }) } -fn jdk_internal_util_SystemProps_Raw(class_manager: &mut ClassManager, method_name: &str) -> Result { +fn jdk_internal_util_SystemProps_Raw( + class_manager: &mut ClassManager, + method_name: &str, +) -> Result { match method_name { "platformProperties()[Ljava/lang/String;" => platformProperties(), "cmdProperties()Ljava/util/HashMap;" => cmdProps(class_manager), //TODO ability to instantiate classes here "vmProperties()[Ljava/lang/String;" => vmProperties(), - _ => Ok(Void) + _ => Ok(Void), } } fn cmdProps(class_manager: &mut ClassManager) -> Result { class_manager.load_class_by_name("java/util/HashMap"); - let hashmap_class = class_manager.get_class_by_name("java/util/HashMap").unwrap(); - let hashmap = Value::Ref(Object(Rc::new(RefCell::new(crate::vm::object::Object::new(hashmap_class))))); // this is convoluted + let hashmap_class = class_manager + .get_class_by_name("java/util/HashMap") + .unwrap(); + let hashmap = Value::Ref(Object(Rc::new(RefCell::new(object::Object::new( + hashmap_class, + ))))); // this is convoluted Stackframe::new(vec![hashmap.clone()]).run(class_manager, hashmap_class.id, "()V"); Ok(hashmap) } @@ -95,7 +154,7 @@ fn platformProperties() -> Result { vec.push("format_variant".into()); //null in jdk21 vec.push("ftp_nonProxyHosts".into()); if let Ok(ftp_proxy) = std::env::var("ftp_proxy") { - vec.push(ftp_proxy.to_owned());//TODO + vec.push(ftp_proxy.to_owned()); //TODO vec.push(ftp_proxy); } else { vec.push("".to_owned()); @@ -105,7 +164,7 @@ fn platformProperties() -> Result { vec.push("http_nonProxyHosts".into()); if let Ok(http_proxy) = std::env::var("http_proxy") { vec.push(http_proxy.to_owned()); - vec.push(http_proxy);//TODO + vec.push(http_proxy); //TODO } else { vec.push("".to_owned()); vec.push("".to_owned()); @@ -158,4 +217,4 @@ fn platformProperties() -> Result { vec }); Ok(Value::Ref(ObjectRef::StringArray(props.to_vec()))) -} \ No newline at end of file +} diff --git a/src/vm/object.rs b/src/vm/object.rs index eb3b801..89cefdc 100644 --- a/src/vm/object.rs +++ b/src/vm/object.rs @@ -1,14 +1,14 @@ -use std::cell::RefCell; -use std::rc::Rc; +use crate::class::{Class, ClassId}; +use crate::value::Value; +use crate::vm::object::ObjectRef::*; use log::debug; use rand::random; -use crate::class::{Class, ClassId}; -use crate::vm::object::ObjectRef::*; -use crate::value::Value; +use std::cell::RefCell; +use std::rc::Rc; #[derive(Debug, Clone)] pub enum ObjectRef { - ByteArray(Vec), + ByteArray(Vec), //maybe use arrays? ShortArray(Vec), IntArray(Vec), LongArray(Vec), @@ -35,7 +35,7 @@ impl ObjectRef { CharArray(d) => d.len(), StringArray(d) => d.len(), ObjectArray(_, d) => d.len(), - _ => unreachable!("not an array {:?}", self) + _ => unreachable!("not an array {:?}", self), } } } @@ -58,15 +58,15 @@ impl ObjectRef { pub fn new_array(arraytype: u8, size: usize) -> Self { match arraytype { - 8 => ByteArray(Vec::with_capacity(size)), - 9 => ShortArray(Vec::with_capacity(size)), - 10 => IntArray(Vec::with_capacity(size)), - 11 => LongArray(Vec::with_capacity(size)), - 6 => FloatArray(Vec::with_capacity(size)), - 7 => DoubleArray(Vec::with_capacity(size)), - 4 => BooleanArray(Vec::with_capacity(size)), - 5 => CharArray(Vec::with_capacity(size)), - _ => unreachable!("impossible array type") + 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 as char;size]), + _ => unreachable!("impossible array type"), } } @@ -135,7 +135,13 @@ impl Object { field_data } - pub fn set(&mut self, runtime_type: &Class, declared_type: &str, field_name: &str, value: Value) { + 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 @@ -153,8 +159,11 @@ impl Object { .unwrap() .get(field_name) .unwrap(); - debug!("get {:?}:{}.{}:{} @{}", runtime_type, declared_type, field_name, type_index.type_name, 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() } -} \ No newline at end of file +} diff --git a/src/vm/opcodes.rs b/src/vm/opcodes.rs index ffc1d10..58c1a93 100644 --- a/src/vm/opcodes.rs +++ b/src/vm/opcodes.rs @@ -93,14 +93,14 @@ pub(crate) enum Opcode { LOR, IXOR, LXOR, - IINC(u8,u8), + IINC(u8, u8), I2L, I2F, I2D, L2I, L2F, L2D, - WIDE_IINC(u16,u16), + WIDE_IINC(u16, u16), F2I, F2L, F2D, @@ -165,7 +165,4 @@ pub(crate) enum Opcode { IFNONNULL(u16), GOTOW(i32), JSR_W(i32), - } - - diff --git a/src/vm/runtime.rs b/src/vm/runtime.rs index b27f95e..08743f1 100644 --- a/src/vm/runtime.rs +++ b/src/vm/runtime.rs @@ -11,13 +11,13 @@ use crate::classloader::io::PATH_SEPARATOR; use crate::classmanager::ClassManager; use crate::value::Value::{self, *}; use crate::vm::array::{array_load, array_store}; +use crate::vm::native::invoke_native; use crate::vm::object; use crate::vm::object::ObjectRef; use crate::vm::object::ObjectRef::Object; use crate::vm::opcodes::Opcode; use crate::vm::opcodes::Opcode::*; use std::io::Write; -use crate::vm::native::invoke_native; const MASK_LOWER_5BITS: i32 = 0b00011111; @@ -28,18 +28,14 @@ pub struct Vm { impl Vm { pub fn new() -> Self { env_logger::builder() - .format(|buf, record| { - writeln!(buf, "{}: {}", record.level(), record.args()) - }) - .try_init().unwrap(); - Self { - stack: vec![] - } + .format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args())) + .try_init() + .unwrap(); + Self { stack: vec![] } } pub fn run(mut self, classpath: &str, class_name: &str, method_name: &str) { - let classpath = classpath.split(PATH_SEPARATOR).map(|s| s.into()) - .collect(); + let classpath = classpath.split(PATH_SEPARATOR).map(|s| s.into()).collect(); let mut class_manager = ClassManager::new(classpath); class_manager.load_class_by_name("java/lang/Class"); @@ -47,7 +43,6 @@ impl Vm { class_manager.load_class_by_name("java/lang/String"); class_manager.load_class_by_name("java/util/Collections"); - class_manager.load_class_by_name(class_name); let system_id = *class_manager.get_classid("java/lang/System"); self.run2(&mut class_manager, system_id, "initPhase1()V"); @@ -55,7 +50,12 @@ impl Vm { // self.run2(&mut class_manager, class_id, method_name); } - pub(crate) fn run2(&mut self, class_manager: &mut ClassManager, class_id: ClassId, method_name: &str) { + pub(crate) fn run2( + &mut self, + class_manager: &mut ClassManager, + class_id: ClassId, + method_name: &str, + ) { Stackframe::default().run(class_manager, class_id, method_name); } } @@ -91,16 +91,38 @@ impl Stackframe { self.stack.pop().unwrap() } - pub fn run(&mut self, class_manager: &mut ClassManager, class_id: ClassId, method_name: &str) -> Value { - let classname = class_manager.get_class_by_id(&class_id).unwrap().name.to_owned(); + pub fn run( + &mut self, + class_manager: &mut ClassManager, + class_id: ClassId, + method_name: &str, + ) -> Value { + let classname = class_manager + .get_class_by_id(&class_id) + .unwrap() + .name + .to_owned(); - let code = class_manager.get_classdef(&class_id).get_method(method_name).unwrap().code.clone(); - let constant_pool = class_manager.get_classdef(&class_id).get_method(method_name).unwrap().constant_pool.clone(); + let code = class_manager + .get_classdef(&class_id) + .get_method(method_name) + .unwrap() + .code + .clone(); + let constant_pool = class_manager + .get_classdef(&class_id) + .get_method(method_name) + .unwrap() + .constant_pool + .clone(); let len = code.len(); while self.pc < len { let opcode: &Opcode = code.get(self.pc).unwrap(); - debug!("\tat {}.{}: {} #{:?} - {:?}", classname, method_name, self.pc, opcode, self.stack); + debug!( + "\tat {}.{}: {} #{:?} - {:?}", + classname, method_name, self.pc, opcode, self.stack + ); self.pc += 1; match opcode { NOP => {} @@ -142,9 +164,15 @@ impl Stackframe { let string = class_manager.get_classdef(&class_id).cp_utf8(&utf8); let string: Vec = string.as_bytes().into(); class_manager.load_class_by_name("java/lang/String"); - let stringclass = class_manager.get_class_by_name("java/lang/String").unwrap(); + let stringclass = + class_manager.get_class_by_name("java/lang/String").unwrap(); let mut stringinstance = object::Object::new(stringclass); - stringinstance.set(stringclass, "java/lang/String", "value", Ref(ObjectRef::new_byte_array(string))); + stringinstance.set( + stringclass, + "java/lang/String", + "value", + Ref(ObjectRef::new_byte_array(string)), + ); self.push(Ref(Object(Rc::new(RefCell::new(stringinstance))))); } @@ -152,7 +180,10 @@ impl Stackframe { self.push(I64(*l)); } CpEntry::ClassRef(utf8_index) => { - let class_name = class_manager.get_classdef(&class_id).cp_utf8(&utf8_index).to_owned(); + let class_name = class_manager + .get_classdef(&class_id) + .cp_utf8(&utf8_index) + .to_owned(); class_manager.load_class_by_name(&class_name); let klass_id = class_manager.get_classid(&class_name); if let Some(class) = class_manager.get_classobject(klass_id) { @@ -178,12 +209,11 @@ impl Stackframe { ISTORE(c) | LSTORE(c) | FSTORE(c) | DSTORE(c) | ASTORE(c) => { self.store(*c).unwrap(); } - BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE - | AASTORE => { + BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE | AASTORE => { let value = self.pop(); let index = self.pop(); let arrayref = self.pop(); - array_store(value, index, arrayref).unwrap()//TODO + array_store(value, index, arrayref).unwrap() //TODO } POP => { self.pop(); @@ -214,20 +244,39 @@ impl Stackframe { let value2 = self.pop(); let value1 = self.pop(); debug!("{:?} shl {:?}", value1, value2); - self.push(I32(value1.into_i32() << (value2.into_i32() & MASK_LOWER_5BITS))); + self.push(I32( + value1.into_i32() << (value2.into_i32() & MASK_LOWER_5BITS) + )); } ISHR => { let value2 = self.pop(); let value1 = self.pop(); debug!("{:?} shr {:?}", value1, value2); - self.push(I32(value1.into_i32() >> (value2.into_i32() & MASK_LOWER_5BITS))); + self.push(I32( + value1.into_i32() >> (value2.into_i32() & MASK_LOWER_5BITS) + )); } - IFEQ(jmp_to) | IFNE(jmp_to) | IFLT(jmp_to) | IFGE(jmp_to) | IFGT(jmp_to) | IFLE(jmp_to) => { + FCMPG | FCMPL => { + let value2 = self.pop().into_f32(); + let value1 = self.pop().into_f32(); + if value1 == value2 { + self.push(I32(0)) + } else if value1 < value2 { + self.push(I32(-1)) + } else if value1 > value2 { + self.push(I32(1)) + } + //TODO something with NaN + } + + IFEQ(jmp_to) | IFNE(jmp_to) | IFLT(jmp_to) | IFGE(jmp_to) | IFGT(jmp_to) + | IFLE(jmp_to) => { let value = self.pop(); if_cmp(&mut self.pc, opcode, jmp_to, &value, &I32(0)); } - IF_ICMPEQ(jmp_to) | IF_ICMPNE(jmp_to) | IF_ICMPGT(jmp_to) | IF_ICMPGE(jmp_to) | IF_ICMPLT(jmp_to) | IF_ICMPLE(jmp_to) => { + IF_ICMPEQ(jmp_to) | IF_ICMPNE(jmp_to) | IF_ICMPGT(jmp_to) | IF_ICMPGE(jmp_to) + | IF_ICMPLT(jmp_to) | IF_ICMPLE(jmp_to) => { let value1 = self.pop(); let value2 = self.pop(); if_cmp(&mut self.pc, opcode, jmp_to, &value1, &value2); @@ -237,9 +286,7 @@ impl Stackframe { // debug!("GOTO {}", *pc) } INVOKEVIRTUAL(c) => { - if let Some(invocation) = - get_signature_for_invoke(&constant_pool, *c) - { + if let Some(invocation) = get_signature_for_invoke(&constant_pool, *c) { let mut args = Vec::with_capacity(invocation.method.num_args); for _ in 0..invocation.method.num_args { args.insert(0, self.pop().clone()); @@ -247,7 +294,6 @@ impl Stackframe { let this_ref = self.pop(); args.insert(0, this_ref.clone()); - debug!("invoke {:?}", invocation); let mut invoke_class: Option = None; if let Null = this_ref { @@ -255,11 +301,14 @@ impl Stackframe { } if let Ref(this) = this_ref { if let Object(this) = this { - let invoke_classdef = class_manager.get_classdef(&this.borrow().class_id); - let invoke_method = invoke_classdef.get_method(&invocation.method.name); + let invoke_classdef = + class_manager.get_classdef(&this.borrow().class_id); + let invoke_method = + invoke_classdef.get_method(&invocation.method.name); if invoke_method.is_some() { class_manager.load_class_by_name(&invocation.class_name); - invoke_class = Some(*class_manager.get_classid(&invocation.class_name)); + invoke_class = + Some(*class_manager.get_classid(&invocation.class_name)); } else { let name = class_manager.classdef_name(&this.borrow().class_id); if let Some(name) = name { @@ -277,34 +326,50 @@ impl Stackframe { panic!("ClassNotFound"); } } - } else if let ObjectRef::Class(_class) = this { // special case for Class ? + } else if let ObjectRef::Class(_class) = this { + // special case for Class ? invoke_class = Some(*class_manager.get_classid("java/lang/Class")); } } if invoke_class.is_none() { - panic!("method {:?}.{} not found", invocation.class_name, invocation.method.name); + panic!( + "method {:?}.{} not found", + invocation.class_name, invocation.method.name + ); } - let return_value = - if class_manager.get_classdef(&invoke_class.unwrap()).get_method(&invocation.method.name).unwrap().is(Modifier::Native) { - invoke_native(class_manager, invocation.class_name.as_str(), invocation.method.name.as_str(), args).unwrap() - // TODO remove unwrap in line above, error handling - } else { - let mut new_stackframe = Stackframe::new(args); - new_stackframe.run(class_manager, invoke_class.unwrap(), &invocation.method.name) - }; + let return_value = if class_manager + .get_classdef(&invoke_class.unwrap()) + .get_method(&invocation.method.name) + .unwrap() + .is(Modifier::Native) + { + invoke_native( + class_manager, + invocation.class_name.as_str(), + invocation.method.name.as_str(), + args, + ) + .unwrap() + // TODO remove unwrap in line above, error handling + } else { + let mut new_stackframe = Stackframe::new(args); + new_stackframe.run( + class_manager, + invoke_class.unwrap(), + &invocation.method.name, + ) + }; match return_value { Void => {} - _ => self.push(return_value) + _ => self.push(return_value), } } else { unreachable!() } } INVOKESPECIAL(c) | INVOKESTATIC(c) => { - if let Some(invocation) = - get_signature_for_invoke(&constant_pool, *c) - { + if let Some(invocation) = get_signature_for_invoke(&constant_pool, *c) { debug!("invoke {:?}", invocation); let mut args = Vec::with_capacity(invocation.method.num_args); for _ in 0..invocation.method.num_args { @@ -315,20 +380,35 @@ impl Stackframe { } class_manager.load_class_by_name(invocation.class_name.as_str()); - let invoke_class = class_manager.get_classid(invocation.class_name.as_str()); + let invoke_class = + class_manager.get_classid(invocation.class_name.as_str()); - let return_value = - if class_manager.get_classdef(&invoke_class).get_method(&invocation.method.name).unwrap().is(Modifier::Native) { - invoke_native(class_manager, invocation.class_name.as_str(), invocation.method.name.as_str(), args).unwrap() - // TODO remove unwrap in line above, error handling - } else { - let mut new_stackframe = Stackframe::new(args); - new_stackframe.run(class_manager, *invoke_class, &invocation.method.name) - }; + let return_value = if class_manager + .get_classdef(&invoke_class) + .get_method(&invocation.method.name) + .unwrap() + .is(Modifier::Native) + { + invoke_native( + class_manager, + invocation.class_name.as_str(), + invocation.method.name.as_str(), + args, + ) + .unwrap() + // TODO remove unwrap in line above, error handling + } else { + let mut new_stackframe = Stackframe::new(args); + new_stackframe.run( + class_manager, + *invoke_class, + &invocation.method.name, + ) + }; debug!("returning {:?}", return_value); match return_value { Void => {} - _ => self.push(return_value) + _ => self.push(return_value), } } else { unreachable!() @@ -338,17 +418,18 @@ impl Stackframe { let classdef = class_manager.get_classdef(&class_id); let (class_index, field_name_and_type_index) = classdef.cp_field_ref(&field_index); // all these unwraps are safe as long as the class is valid - let (name_index, _) = - classdef.cp_name_and_type(field_name_and_type_index); + let (name_index, _) = classdef.cp_name_and_type(field_name_and_type_index); let field_name = classdef.cp_utf8(name_index).to_owned(); - let that_class_name = classdef.cp_utf8(classdef.cp_class_ref(class_index)).to_owned(); + let that_class_name = classdef + .cp_utf8(classdef.cp_class_ref(class_index)) + .to_owned(); class_manager.load_class_by_name(&that_class_name); let that_class = class_manager.get_class_by_name(&that_class_name).unwrap(); let type_index = that_class .static_field_mapping .get(&that_class_name) - .unwrap()// safe because class for static field must be there + .unwrap() // safe because class for static field must be there .get(&field_name) .unwrap(); // safe because field must be there @@ -360,13 +441,13 @@ impl Stackframe { let classdef = class_manager.get_classdef(&class_id); let (class_index, field_name_and_type_index) = classdef.cp_field_ref(&field_index); // all these unwraps are safe as long as the class is valid - let (name_index, _) = - classdef.cp_name_and_type(field_name_and_type_index); + let (name_index, _) = classdef.cp_name_and_type(field_name_and_type_index); let name = classdef.cp_utf8(name_index); 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 = class_manager.get_class_by_name(that_class_name).unwrap(); - let val_index = that_class.static_field_mapping + let val_index = that_class + .static_field_mapping .get(that_class_name) .unwrap() .get(name) @@ -380,14 +461,18 @@ impl Stackframe { classdef.cp_field_ref(&field_index); let (field_name_index, _) = classdef.cp_name_and_type(field_name_and_type_index); - let declared_type = classdef.cp_utf8(classdef.cp_class_ref(class_index)).to_owned(); + let declared_type = classdef + .cp_utf8(classdef.cp_class_ref(class_index)) + .to_owned(); let field_name = classdef.cp_utf8(field_name_index).to_owned(); - debug!("get field {}.{}",declared_type, field_name); + debug!("get field {}.{}", declared_type, field_name); let objectref = self.pop(); if let Ref(instance) = objectref { if let Object(object) = instance { - let runtime_type = class_manager.get_class_by_id(&object.borrow().class_id).unwrap(); + let runtime_type = class_manager + .get_class_by_id(&object.borrow().class_id) + .unwrap(); let object = object.borrow(); let value = object.get(runtime_type, &declared_type, &field_name); self.push(value.clone()); @@ -412,18 +497,31 @@ impl Stackframe { let objectref = self.pop(); if let Ref(instance) = objectref { if let Object(object) = instance { - let runtime_type = class_manager.get_class_by_id(&object.borrow().class_id).unwrap(); - object.borrow_mut().set(runtime_type, &declared_type, &field_name, value); + let runtime_type = class_manager + .get_class_by_id(&object.borrow().class_id) + .unwrap(); + object.borrow_mut().set( + runtime_type, + &declared_type, + &field_name, + value, + ); } } else { unreachable!() } } NEW(class_index) => { - let class_name_index = *class_manager.get_classdef(&class_id).cp_class_ref(class_index); - let class_name = class_manager.get_classdef(&class_id).cp_utf8(&class_name_index).to_owned(); + let class_name_index = *class_manager + .get_classdef(&class_id) + .cp_class_ref(class_index); + let class_name = class_manager + .get_classdef(&class_id) + .cp_utf8(&class_name_index) + .to_owned(); class_manager.load_class_by_name(&class_name); - let class_to_instantiate = class_manager.get_class_by_name(&class_name).unwrap(); + let class_to_instantiate = + class_manager.get_class_by_name(&class_name).unwrap(); let object = Object(Rc::new(RefCell::new(object::Object::new( class_to_instantiate, @@ -432,12 +530,18 @@ impl Stackframe { } NEWARRAY(arraytype) => { let count = self.pop(); + debug!("create array with size {:?}", count); let array = ObjectRef::new_array(*arraytype, count.into_i32() as usize); self.push(Ref(array)); } ANEWARRAY(class_index) => { - let class_name_index = *class_manager.get_classdef(&class_id).cp_class_ref(class_index); - let class_name = class_manager.get_classdef(&class_id).cp_utf8(&class_name_index).to_owned(); + let class_name_index = *class_manager + .get_classdef(&class_id) + .cp_class_ref(class_index); + let class_name = class_manager + .get_classdef(&class_id) + .cp_utf8(&class_name_index) + .to_owned(); class_manager.load_class_by_name(&class_name); let arraytype = class_manager.get_class_by_name(&class_name).unwrap(); let count = self.pop().into_i32(); @@ -462,8 +566,16 @@ impl Stackframe { IFNULL(_) | IFNONNULL(_) => { let value = self.pop(); match value { - Null => if let IFNULL(goto) = opcode { self.pc = *goto as usize; } - _ => if let IFNONNULL(goto) = opcode { self.pc = *goto as usize; } + Null => { + if let IFNULL(goto) = opcode { + self.pc = *goto as usize; + } + } + _ => { + if let IFNONNULL(goto) = opcode { + self.pc = *goto as usize; + } + } }; } DUP => { @@ -477,16 +589,15 @@ impl Stackframe { RETURN_VOID => { return Void; } - _ => { panic!("opcode not implemented") } + _ => { + panic!("opcode not implemented") + } } } Void } - fn store( - &mut self, - index: u8, - ) -> Result<(), Error> { + fn store(&mut self, index: u8) -> Result<(), Error> { let index = index as usize; let value = self.pop(); while self.locals.len() < index + 1 { @@ -497,17 +608,17 @@ impl Stackframe { } } -pub(crate) fn get_signature_for_invoke(cp: &HashMap, index: u16) -> Option { +pub(crate) fn get_signature_for_invoke( + cp: &HashMap, + 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(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::new( - class_name.into(), - method_signature) - ); + return Some(Invocation::new(class_name.into(), method_signature)); } } } @@ -584,10 +695,7 @@ pub(crate) struct Invocation { impl Invocation { pub fn new(class_name: String, method: MethodSignature) -> Self { - Self { - class_name, - method, - } + Self { class_name, method } } } @@ -599,9 +707,6 @@ pub(crate) struct MethodSignature { impl MethodSignature { pub(crate) fn new(name: String, num_args: usize) -> Self { - MethodSignature { - name, - num_args, - } + MethodSignature { name, num_args } } -} \ No newline at end of file +} diff --git a/tests/class_tests.rs b/tests/class_tests.rs index 29f8a97..319bf76 100644 --- a/tests/class_tests.rs +++ b/tests/class_tests.rs @@ -1,18 +1,23 @@ mod test { use java_rs::vm::runtime::Vm; - - #[test] fn if_cmp() { let vm = Vm::new(); - vm.run("/Users/Shautvast/dev/java/tests", "testclasses.IfCmp", "i_is_1()Z"); + vm.run( + "/Users/Shautvast/dev/java/tests", + "testclasses.IfCmp", + "i_is_1()Z", + ); } #[test] fn consts() { - let vm = Vm::new(); - vm.run("/Users/Shautvast/dev/java/tests", "testclasses.Const", "hello()Ljava/lang/String;") + vm.run( + "/Users/Shautvast/dev/java/tests", + "testclasses.Const", + "hello()Ljava/lang/String;", + ) } } diff --git a/tests/method_tests.rs b/tests/method_tests.rs index f3ef655..d725553 100644 --- a/tests/method_tests.rs +++ b/tests/method_tests.rs @@ -1,7 +1,7 @@ mod test { + use java_rs::classloader::classdef::{Method, Modifier}; use std::collections::HashMap; use std::rc::Rc; - use java_rs::classloader::classdef::{Method, Modifier}; #[test] fn access_flags() { @@ -16,8 +16,4 @@ mod test { assert!(m.is(Modifier::Static)); assert!(!m.is(Modifier::Private)); } - - - - }