primitiveClasses, fix arrays

This commit is contained in:
Shautvast 2023-11-27 22:12:31 +01:00
parent dae02cec32
commit d9985df822
17 changed files with 567 additions and 289 deletions

View file

@ -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 }
}
}

View file

@ -21,7 +21,7 @@ pub(crate) struct ClassDef {
pub attributes: HashMap<String, AttributeType>,
}
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))
}

View file

@ -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<Opcode> {
@ -19,56 +21,28 @@ pub(crate) fn parse_code(opcodes: &[u8]) -> Vec<Opcode> {
// 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
}

View file

@ -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<String>, class_name: &str) -> Result<String, E
Err(anyhow!("Class not found {}", class_name))
}
// methods to read values from big-endian binary data
pub(crate) fn read_u8(data: &[u8], pos: &mut usize) -> 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")
}
}
}
}

View file

@ -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<String>, class_name: &str) -> Result<ClassDef,Error> {
pub(crate) fn get_classdef(classpath: &Vec<String>, class_name: &str) -> Result<ClassDef, Error> {
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<u8>) -> Result<ClassDef, Error> {
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<u8>) -> Result<ClassDef, Error> {
}
}
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,
)
}
@ -327,4 +332,3 @@ fn read_attribute(
}
None
}

View file

@ -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<Vec<&str>> = Lazy::new(|| vec!["B", "S", "I", "J", "F", "D", "Z", "J", "C"]);
static PRIMITIVES: Lazy<Vec<&str>> =
Lazy::new(|| vec!["B", "S", "I", "J", "F", "D", "Z", "J", "C"]);
//TODO less pubs
pub struct ClassManager {
@ -112,9 +113,11 @@ impl ClassManager {
// in cache?
let id = self.names.get(&type_name);
match id {
Some(id) => if self.classes.get(id).is_none() {
Some(id) => {
if self.classes.get(id).is_none() {
self.add_class(&type_name);
}
}
None => {
self.add_class(&type_name);
}
@ -167,27 +170,42 @@ 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<ClassId> = this_classdef.interfaces.iter()
let interface_ids: Vec<ClassId> = 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 {
self.classes.insert(
this_classid,
Class {
id: this_classid,
initialized: false,
name: name.into(),
@ -196,13 +214,14 @@ impl ClassManager {
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("<clinit>()V") {
Vm { stack: Vec::new()}.run2(self, this_classid,"<clinit>()V");
Vm { stack: Vec::new() }.run2(self, this_classid, "<clinit>()V");
}
this_classid
}
/// like described above
fn add_fields_for_this_or_parents(object_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
fn add_fields_for_this_or_parents(
object_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
static_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
object_field_map_index: &mut usize,
static_field_map_index: &mut usize,
current_classdef: &ClassDef) {
current_classdef: &ClassDef,
) {
let mut instance_field_mappings: HashMap<String, TypeIndex> = HashMap::new();
let mut static_field_mappings: HashMap<String, TypeIndex> = HashMap::new();
for (field_name, field) in &current_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<String, HashMap<String, TypeIndex>>) -> Vec<Value> {
pub(crate) fn set_field_data(
field_mapping: &HashMap<String, HashMap<String, TypeIndex>>,
) -> Vec<Value> {
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
);
}
}

View file

@ -1,5 +1,5 @@
mod class;
pub mod classloader;
pub mod classmanager;
mod value;
mod class;
pub mod vm;

View file

@ -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",
);
}

View file

@ -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

View file

@ -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<Value, Error> {
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;

View file

@ -1,5 +1,5 @@
mod array;
mod native;
pub(crate) mod object;
pub(crate) mod opcodes;
pub mod runtime;
mod native;

View file

@ -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<HashMap<&str, &str>> = 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<HashMap<String, Value>> = Lazy::new(|| HashMap::new());
pub fn invoke_native(class_manager: &mut ClassManager, class_name: &str, method_name: &str, _args: Vec<Value>) -> Result<Value, Error> {
pub fn invoke_native(
class_manager: &mut ClassManager,
class_name: &str,
method_name: &str,
args: Vec<Value>,
) -> Result<Value, Error> {
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<Value, Error> {
fn java_lang_Class(
class_manager: &mut ClassManager,
method_name: &str,
args: Vec<Value>,
) -> Result<Value, Error> {
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<Value, Error> {
Ok(match method_name {
_ => Void
_ => Void,
})
}
fn get_primitive_class(class_manager: &mut ClassManager, args: Vec<Value>) -> 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<Value, Error> {
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<Value, Error> {
fn jdk_internal_util_SystemProps_Raw(
class_manager: &mut ClassManager,
method_name: &str,
) -> Result<Value, Error> {
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<Value, Error> {
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, "<init>()V");
Ok(hashmap)
}
@ -95,7 +154,7 @@ fn platformProperties() -> Result<Value, Error> {
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<Value, Error> {
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());

View file

@ -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<i8>),
ByteArray(Vec<i8>), //maybe use arrays?
ShortArray(Vec<i16>),
IntArray(Vec<i32>),
LongArray(Vec<i64>),
@ -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,7 +159,10 @@ 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()
}

View file

@ -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),
}

View file

@ -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<u8> = 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<ClassId> = 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()
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)
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()
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)
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<u16, CpEntry>, index: u16) -> Option<Invocation> {
pub(crate) fn get_signature_for_invoke(
cp: &HashMap<u16, CpEntry>,
index: u16,
) -> Option<Invocation> {
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 }
}
}

View file

@ -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;",
)
}
}

View file

@ -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));
}
}