lot of bugfixes
This commit is contained in:
parent
2f7442228b
commit
92a4fa96a3
10 changed files with 309 additions and 199 deletions
52
Cargo.lock
generated
52
Cargo.lock
generated
|
|
@ -217,6 +217,17 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.3"
|
||||
|
|
@ -266,6 +277,7 @@ dependencies = [
|
|||
"env_logger",
|
||||
"log",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"whoami",
|
||||
"zip",
|
||||
]
|
||||
|
|
@ -290,9 +302,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.148"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
|
|
@ -356,6 +368,12 @@ version = "0.3.27"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.67"
|
||||
|
|
@ -374,11 +392,35 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
|
|
@ -525,6 +567,12 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.87"
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@ zip = { version = "0.6", features = ["zstd"] }
|
|||
log = "0.4"
|
||||
env_logger = "0.10"
|
||||
whoami = "1.4.1"
|
||||
rand="0.8"
|
||||
32
src/class.rs
32
src/class.rs
|
|
@ -1,4 +1,9 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, LinkedList};
|
||||
use std::rc::Rc;
|
||||
|
||||
use log::debug;
|
||||
use rand::random;
|
||||
|
||||
use crate::class::ObjectRef::*;
|
||||
|
||||
|
|
@ -41,7 +46,7 @@ impl Class {
|
|||
.iter()
|
||||
.map(|(_, v)| v.len())
|
||||
.reduce(|acc, e| acc + e)
|
||||
.unwrap()
|
||||
.unwrap_or(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +76,7 @@ impl Value {
|
|||
if let Value::I32(v) = self {
|
||||
v
|
||||
} else {
|
||||
panic!();
|
||||
panic!("{:?} is not I32", self);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +101,7 @@ pub enum ObjectRef {
|
|||
CharArray(Vec<char>),
|
||||
StringArray(Vec<String>),
|
||||
ObjectArray(ClassId, Vec<ObjectRef>),
|
||||
Object(Object),
|
||||
Object(Rc<RefCell<Object>>),
|
||||
//Box necessary??
|
||||
Class(Class),
|
||||
}
|
||||
|
|
@ -170,10 +175,11 @@ fn into_vec_i8(v: Vec<u8>) -> Vec<i8> {
|
|||
unsafe { Vec::from_raw_parts(p as *mut i8, len, cap) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct Object {
|
||||
// locked: bool,
|
||||
// hashcode: i32,
|
||||
pub id: u32,
|
||||
pub class_id: ClassId,
|
||||
pub data: Vec<Value>,
|
||||
} //arrays
|
||||
|
|
@ -183,6 +189,7 @@ impl Object {
|
|||
pub fn new(class: &Class) -> Self {
|
||||
let instance_data = Object::init_fields(class);
|
||||
Self {
|
||||
id: random(),
|
||||
class_id: class.id,
|
||||
data: instance_data,
|
||||
}
|
||||
|
|
@ -190,7 +197,7 @@ impl Object {
|
|||
|
||||
// initializes all non-static fields to their default values
|
||||
pub(crate) fn init_fields(class: &Class) -> Vec<Value> {
|
||||
let mut field_data = Vec::with_capacity(class.n_object_fields());
|
||||
let mut field_data = vec![Value::Null;class.n_object_fields()];
|
||||
|
||||
for (_, fields) in &class.object_field_mapping {
|
||||
for (_, type_index) in fields {
|
||||
|
|
@ -204,15 +211,16 @@ impl Object {
|
|||
"D" => Value::F64(0.0),
|
||||
_ => Value::Null,
|
||||
};
|
||||
field_data.push(value.into());
|
||||
field_data[type_index.index] = value.into();
|
||||
}
|
||||
}
|
||||
|
||||
field_data
|
||||
}
|
||||
|
||||
pub fn set(&mut self, class: &Class, declared_type: &str, field_name: &str, value: Value) {
|
||||
let type_index = class
|
||||
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
|
||||
.get(declared_type)
|
||||
.unwrap()
|
||||
|
|
@ -221,14 +229,16 @@ impl Object {
|
|||
self.data[type_index.index] = value;
|
||||
}
|
||||
|
||||
pub fn get(&mut self, instancedef: &Class, declared_type: &String, field_name: &String) -> &Value {
|
||||
let type_index = instancedef
|
||||
pub fn get(&self, runtime_type: &Class, declared_type: &String, field_name: &String) -> &Value {
|
||||
let type_index = runtime_type
|
||||
.object_field_mapping
|
||||
.get(declared_type)
|
||||
.unwrap()
|
||||
.get(field_name)
|
||||
.unwrap();
|
||||
&self.data[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()
|
||||
}
|
||||
|
||||
// fn get_field_name(&self, cp_index: &u16) -> &str {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, E
|
|||
maybe_path.push('/');
|
||||
maybe_path.push_str(class_name);
|
||||
maybe_path.push_str(".class");
|
||||
// println!("{}", maybe_path);
|
||||
if fs::metadata(&maybe_path)?.is_file() {
|
||||
return Ok(maybe_path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ fn check_magic(bytecode: &[u8], pos: &mut usize) {
|
|||
|
||||
fn read_constant_pool_entry(cp_index: &mut u16, index: &mut usize, bytecode: &[u8]) -> CpEntry {
|
||||
let tag = read_u8(bytecode, index);
|
||||
// println!("tag {}", tag);
|
||||
// debug!("tag {}", tag);
|
||||
match tag {
|
||||
1 => {
|
||||
let len = read_u16(bytecode, index) as usize;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, LinkedList};
|
||||
use std::rc::Rc;
|
||||
use log::debug;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
|
|
@ -27,7 +29,7 @@ pub fn set_classpath(classpath: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_class_by_id(id: ClassId) -> Option<&'static Class> {
|
||||
pub fn get_class_by_id(id: &ClassId) -> Option<&'static Class> {
|
||||
unsafe {
|
||||
CLASSMANAGER.get_class_by_id(id)
|
||||
}
|
||||
|
|
@ -127,14 +129,14 @@ impl ClassManager {
|
|||
.collect();
|
||||
}
|
||||
|
||||
fn get_class_by_id(&mut self, id: ClassId) -> Option<&Class> {
|
||||
if !self.classes.contains_key(&id) {
|
||||
let name = self.classdef_name(&id);
|
||||
fn get_class_by_id(&mut self, id: &ClassId) -> Option<&Class> {
|
||||
if !self.classes.contains_key(id) {
|
||||
let name = self.classdef_name(id);
|
||||
if name.is_some() {
|
||||
self.add_class(&name.unwrap());
|
||||
}
|
||||
}
|
||||
self.classes.get(&id)
|
||||
self.classes.get(id)
|
||||
}
|
||||
|
||||
fn classdef_name(&self, id: &ClassId) -> Option<String> {
|
||||
|
|
@ -156,7 +158,6 @@ impl ClassManager {
|
|||
self.add_class(name);
|
||||
}
|
||||
None => {
|
||||
|
||||
self.add_class(name);
|
||||
}
|
||||
}
|
||||
|
|
@ -212,14 +213,13 @@ impl ClassManager {
|
|||
interfaces: interface_ids,
|
||||
object_field_mapping,
|
||||
static_field_mapping,
|
||||
// static_field_data: static_values,
|
||||
});
|
||||
|
||||
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()));
|
||||
let instance = Ref(ObjectRef::Object(instance));
|
||||
let instance = Ref(ObjectRef::Object(Rc::new(RefCell::new(instance))));
|
||||
|
||||
self.class_objects.insert(this_classid, instance);
|
||||
}
|
||||
|
|
@ -234,8 +234,8 @@ impl ClassManager {
|
|||
|
||||
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,
|
||||
object_field_map_index: &mut usize,
|
||||
static_field_map_index: &mut usize,
|
||||
current_classdef: &ClassDef) {
|
||||
let mut instance_field_mappings: HashMap<String, TypeIndex> = HashMap::new();
|
||||
let mut static_field_mappings: HashMap<String, TypeIndex> = HashMap::new();
|
||||
|
|
@ -295,7 +295,6 @@ impl ClassManager {
|
|||
"D" => F64(0.0),
|
||||
_ => Null,
|
||||
};
|
||||
// println!("{} = {:?}", name, value);
|
||||
field_data[type_index.index] = value.into();
|
||||
}
|
||||
}
|
||||
|
|
@ -323,3 +322,73 @@ pub(crate) fn inspect_dependencies(classdef: &ClassDef) -> Vec<String> {
|
|||
}
|
||||
classes_to_load
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::rc::Rc;
|
||||
use crate::classloader::classdef::{CpEntry, Field};
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn add_class() {
|
||||
let mut names = HashMap::new();
|
||||
names.insert("C".to_owned(), 1);
|
||||
names.insert("java/lang/String".to_owned(), 2);
|
||||
names.insert("java/lang/Class".to_owned(), 3);
|
||||
|
||||
let mut constant_pool = HashMap::new();
|
||||
constant_pool.insert(0, CpEntry::ClassRef(1));
|
||||
constant_pool.insert(1, CpEntry::Utf8("C".into()));
|
||||
constant_pool.insert(2, CpEntry::NameAndType(3, 4));
|
||||
constant_pool.insert(3, CpEntry::Utf8("name".into()));
|
||||
constant_pool.insert(4, CpEntry::Utf8("java/lang/String".into()));
|
||||
constant_pool.insert(5, CpEntry::Utf8("Ljava/lang/String;".into()));
|
||||
constant_pool.insert(6, CpEntry::ClassRef(4));
|
||||
constant_pool.insert(7, CpEntry::Utf8("java/lang/Class".into()));
|
||||
constant_pool.insert(8, CpEntry::ClassRef(7));
|
||||
constant_pool.insert(9, CpEntry::Utf8("value1".into()));
|
||||
constant_pool.insert(10, CpEntry::Utf8("value2".into()));
|
||||
let constant_pool = Rc::new(constant_pool);
|
||||
|
||||
// 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));
|
||||
|
||||
// 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));
|
||||
|
||||
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()));
|
||||
|
||||
// preload java.lang.String
|
||||
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()));
|
||||
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: true, 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(),
|
||||
classes,
|
||||
class_objects: HashMap::new(),
|
||||
classdefs,
|
||||
current_id: 1,
|
||||
names,
|
||||
classpath: Vec::new(),
|
||||
vm: Vm::new(&mut vec![]),
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
#![allow(non_snake_case)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use anyhow::Error;
|
||||
use log::{debug, info};
|
||||
use log::debug;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::class::{ObjectRef, Value};
|
||||
|
|
@ -41,14 +43,14 @@ fn cmdProps(vm: &mut Vm, stackframes: &mut Vec<StackFrame>) -> Result<Value, Err
|
|||
classmanager::load_class_by_name("java/util/HashMap");
|
||||
let hashmap_class = classmanager::get_class_by_name("java/util/HashMap").unwrap();
|
||||
let hashmap = Vm::new_instance(hashmap_class);
|
||||
let hashmap = Value::Ref(Object(hashmap));
|
||||
vm.execute_special(stackframes, "java/util/HashMap", "<init>()V", vec![hashmap.clone()]);
|
||||
let hashmap = Value::Ref(Object(Rc::new(RefCell::new(hashmap))));
|
||||
vm.execute_special(stackframes, "java/util/HashMap", "<init>()V", vec![hashmap.clone()])?;
|
||||
Ok(hashmap)
|
||||
}
|
||||
|
||||
fn vmProperties(vm: &mut Vm, stackframes: &mut Vec<StackFrame>) -> Result<Value, Error> {
|
||||
fn vmProperties(_vm: &mut Vm, _stackframes: &mut Vec<StackFrame>) -> Result<Value, Error> {
|
||||
let props: Lazy<Vec<String>> = Lazy::new(|| {
|
||||
let mut vec: Vec<String> = Vec::new();
|
||||
let vec: Vec<String> = Vec::new();
|
||||
//TODO insert some values
|
||||
vec
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,10 +23,6 @@ impl StackFrame {
|
|||
self.data.push(val);
|
||||
}
|
||||
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
pub(crate) fn pop(&mut self) -> Result<Value, Error> {
|
||||
Ok(self.data.pop().unwrap())
|
||||
}
|
||||
|
|
|
|||
269
src/vm/vm.rs
269
src/vm/vm.rs
|
|
@ -1,13 +1,16 @@
|
|||
use std::cell::RefCell;
|
||||
use std::io::Write;
|
||||
use std::rc::Rc;
|
||||
|
||||
use anyhow::Error;
|
||||
use log::debug;
|
||||
use log::{debug, error};
|
||||
|
||||
use crate::class::{Class, Object, ObjectRef, Value};
|
||||
use crate::class::Value::{F32, F64, I32, I64, Null, Ref, Utf8, Void};
|
||||
use crate::classloader::classdef::{AttributeType, CpEntry, Modifier};
|
||||
use crate::classloader::io::{read_u16, read_u8};
|
||||
use crate::classmanager;
|
||||
use crate::classmanager::get_class_by_id;
|
||||
use crate::vm::array::{array_load, array_store};
|
||||
use crate::vm::native::invoke_native;
|
||||
use crate::vm::opcodes;
|
||||
|
|
@ -38,7 +41,7 @@ impl Vm {
|
|||
.format(|buf, record| {
|
||||
writeln!(buf, "{}: {}", record.level(), record.args())
|
||||
})
|
||||
.try_init();
|
||||
.try_init().unwrap();
|
||||
let mut vm_instance = Self {};
|
||||
classmanager::init();
|
||||
Vm::init(&mut vm_instance, stack);
|
||||
|
|
@ -48,13 +51,6 @@ impl Vm {
|
|||
fn init(vm: &mut Vm, stack: &mut Vec<StackFrame>) {
|
||||
classmanager::load_class_by_name("java/lang/Class");
|
||||
vm.execute_static(stack, "java/lang/System", "initPhase1()V", vec![]).expect("cannot create VM");
|
||||
// classmanager::load_class_by_name("java/lang/String");
|
||||
}
|
||||
|
||||
|
||||
fn current_frame(stackframes: &mut Vec<StackFrame>) -> &mut StackFrame {
|
||||
let i = stackframes.len() - 1;
|
||||
stackframes.get_mut(i).unwrap()
|
||||
}
|
||||
|
||||
pub fn new_instance(class: &Class) -> Object {
|
||||
|
|
@ -82,22 +78,25 @@ impl Vm {
|
|||
}
|
||||
if let Ref(this) = &args[0] {
|
||||
if let ObjectRef::Object(this) = this {
|
||||
let cd = classmanager::get_classdef(&this.class_id);
|
||||
let thisb= this.borrow();
|
||||
let cd = classmanager::get_classdef(&thisb.class_id);
|
||||
let method = cd.get_method(method_name);
|
||||
if let Some(method) = method {
|
||||
classmanager::load_class_by_name(class_name);
|
||||
let class = classmanager::get_class_by_name(class_name).unwrap();
|
||||
return self.execute_class(stack, class, method.name().as_str(), args.clone());
|
||||
} else {
|
||||
let name = classmanager::classdef_name(&this.class_id);
|
||||
let name = classmanager::classdef_name(&this.borrow().class_id);
|
||||
if let Some(name) = name {
|
||||
classmanager::load_class_by_name(&name);
|
||||
let class = classmanager::get_class_by_name(&name).unwrap();
|
||||
|
||||
for parent_id in &class.parents {
|
||||
if let Some(method) = method {
|
||||
return self.execute_class(stack, class, method_name, args);
|
||||
} else {
|
||||
debug!("not {:?}", parent_id);
|
||||
let classdef = classmanager::get_classdef(parent_id);
|
||||
let method = classdef.get_method(method_name);
|
||||
if let Some(_) = method {
|
||||
let class= get_class_by_id(parent_id).unwrap();
|
||||
return self.execute_class(stack, class, method_name, args.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -163,98 +162,90 @@ impl Vm {
|
|||
let pc = &mut 0;
|
||||
while *pc < code.opcodes.len() {
|
||||
let opcode = read_u8(&code.opcodes, pc);
|
||||
let cur_frame = Self::current_frame(stackframes);
|
||||
debug!("\t{} #{} {} - {}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.len());
|
||||
let cur_frame = current_frame(stackframes);
|
||||
debug!("\t{} #{} {} - {:?}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.data);
|
||||
match opcode {
|
||||
ACONST_NULL => {
|
||||
Self::current_frame(stackframes).push(Value::Null);
|
||||
current_frame(stackframes).push(Value::Null);
|
||||
}
|
||||
ICONST_M1 => {
|
||||
Self::current_frame(stackframes).push(I32(-1));
|
||||
current_frame(stackframes).push(I32(-1));
|
||||
}
|
||||
ICONST_0 => {
|
||||
Self::current_frame(stackframes).push(I32(0));
|
||||
current_frame(stackframes).push(I32(0));
|
||||
}
|
||||
ICONST_1 => {
|
||||
Self::current_frame(stackframes).push(I32(1));
|
||||
current_frame(stackframes).push(I32(1));
|
||||
}
|
||||
ICONST_2 => {
|
||||
Self::current_frame(stackframes).push(I32(2));
|
||||
current_frame(stackframes).push(I32(2));
|
||||
}
|
||||
ICONST_3 => {
|
||||
Self::current_frame(stackframes).push(I32(3));
|
||||
current_frame(stackframes).push(I32(3));
|
||||
}
|
||||
ICONST_4 => {
|
||||
Self::current_frame(stackframes).push(I32(4));
|
||||
current_frame(stackframes).push(I32(4));
|
||||
}
|
||||
ICONST_5 => {
|
||||
Self::current_frame(stackframes).push(I32(5));
|
||||
current_frame(stackframes).push(I32(5));
|
||||
}
|
||||
LCONST_0 => {
|
||||
Self::current_frame(stackframes).push(I64(0));
|
||||
current_frame(stackframes).push(I64(0));
|
||||
}
|
||||
LCONST_1 => {
|
||||
Self::current_frame(stackframes).push(I64(1));
|
||||
current_frame(stackframes).push(I64(1));
|
||||
}
|
||||
FCONST_0 => {
|
||||
Self::current_frame(stackframes).push(F32(0.0));
|
||||
current_frame(stackframes).push(F32(0.0));
|
||||
}
|
||||
FCONST_1 => {
|
||||
Self::current_frame(stackframes).push(F32(1.0));
|
||||
current_frame(stackframes).push(F32(1.0));
|
||||
}
|
||||
FCONST_2 => {
|
||||
Self::current_frame(stackframes).push(F32(2.0));
|
||||
current_frame(stackframes).push(F32(2.0));
|
||||
}
|
||||
DCONST_0 => {
|
||||
Self::current_frame(stackframes).push(F64(0.0));
|
||||
current_frame(stackframes).push(F64(0.0));
|
||||
}
|
||||
DCONST_1 => {
|
||||
Self::current_frame(stackframes).push(F64(1.0));
|
||||
current_frame(stackframes).push(F64(1.0));
|
||||
}
|
||||
SIPUSH => {
|
||||
let s = read_u16(&code.opcodes, pc) as i32;
|
||||
Self::current_frame(stackframes).push(I32(s));
|
||||
current_frame(stackframes).push(I32(s));
|
||||
}
|
||||
BIPUSH => {
|
||||
let c = read_u8(&code.opcodes, pc) as i32;
|
||||
Self::current_frame(stackframes).push(I32(c));
|
||||
current_frame(stackframes).push(I32(c));
|
||||
}
|
||||
LDC => {
|
||||
let cp_index = read_u8(&code.opcodes, pc) as u16;
|
||||
let c = method.constant_pool.get(&cp_index).unwrap();
|
||||
match c {
|
||||
CpEntry::Integer(i) => {
|
||||
Self::current_frame(stackframes).push(I32(*i));
|
||||
current_frame(stackframes).push(I32(*i));
|
||||
}
|
||||
CpEntry::Float(f) => {
|
||||
Self::current_frame(stackframes).push(Value::F32(*f));
|
||||
current_frame(stackframes).push(Value::F32(*f));
|
||||
}
|
||||
CpEntry::Double(d) => {
|
||||
Self::current_frame(stackframes).push(Value::F64(*d));
|
||||
current_frame(stackframes).push(Value::F64(*d));
|
||||
}
|
||||
CpEntry::StringRef(utf8) => {
|
||||
//TODO
|
||||
let string = classmanager::get_classdef(&this_class.id).cp_utf8(utf8);
|
||||
let string: Vec<u8> = string.as_bytes().into();
|
||||
classmanager::load_class_by_name("java/lang/String");
|
||||
let stringclass = classmanager::get_class_by_name("java/lang/String").unwrap();
|
||||
let stringinstance =
|
||||
Ref(ObjectRef::Object(Vm::new_instance(stringclass)));
|
||||
let mut stringinstance = Vm::new_instance(stringclass);
|
||||
stringinstance.set(stringclass, "java/lang/String", "value", Value::Ref(ObjectRef::new_byte_array(string)));
|
||||
|
||||
// let string = classmanager::get_classdef(&this_class.id).cp_utf8(utf8);
|
||||
debug!("new string \"{}\"", utf8);
|
||||
// let string: Vec<u8> = string.as_bytes().into();
|
||||
|
||||
// self.execute_special(stackframes,
|
||||
// "java/lang/String",
|
||||
// "<init>([B)V",
|
||||
// vec![
|
||||
// stringinstance.clone(),
|
||||
// Ref(ObjectRef::new_byte_array(string)),
|
||||
// ],
|
||||
// )?;
|
||||
Self::current_frame(stackframes).push(stringinstance);
|
||||
current_frame(stackframes).push(Ref(ObjectRef::Object(Rc::new(RefCell::new(stringinstance)))));
|
||||
}
|
||||
CpEntry::Long(l) => {
|
||||
Self::current_frame(stackframes).push(Value::I64(*l));
|
||||
current_frame(stackframes).push(Value::I64(*l));
|
||||
}
|
||||
CpEntry::ClassRef(utf8) => {
|
||||
let classdef = classmanager::get_classdef(&this_class.id);
|
||||
|
|
@ -262,7 +253,7 @@ impl Vm {
|
|||
classmanager::load_class_by_name(class_name);
|
||||
let klass_id = classmanager::get_classid(class_name);
|
||||
if let Some(class) = classmanager::get_classobject(klass_id) {
|
||||
Self::current_frame(stackframes).push(class.clone());
|
||||
current_frame(stackframes).push(class.clone());
|
||||
} else {
|
||||
unreachable!("should not be here");
|
||||
}
|
||||
|
|
@ -277,18 +268,18 @@ impl Vm {
|
|||
let cp_entry = method.constant_pool.get(&cp_index).unwrap();
|
||||
match cp_entry {
|
||||
CpEntry::Integer(i) => {
|
||||
Self::current_frame(stackframes).push(I32(*i));
|
||||
current_frame(stackframes).push(I32(*i));
|
||||
}
|
||||
CpEntry::Float(f) => {
|
||||
Self::current_frame(stackframes).push(F32(*f));
|
||||
current_frame(stackframes).push(F32(*f));
|
||||
}
|
||||
CpEntry::StringRef(utf8_index) => {
|
||||
if let CpEntry::Utf8(s) = method.constant_pool.get(utf8_index).unwrap() {
|
||||
Self::current_frame(stackframes).push(Utf8(s.to_owned()));
|
||||
current_frame(stackframes).push(Utf8(s.to_owned()));
|
||||
} else {}
|
||||
}
|
||||
_ => {
|
||||
println!("{:?}", cp_entry);
|
||||
error!("{:?}", cp_entry);
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
|
@ -297,10 +288,10 @@ impl Vm {
|
|||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
match method.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Double(d) => {
|
||||
Self::current_frame(stackframes).push(Value::F64(*d));
|
||||
current_frame(stackframes).push(Value::F64(*d));
|
||||
}
|
||||
CpEntry::Long(l) => {
|
||||
Self::current_frame(stackframes).push(Value::I64(*l));
|
||||
current_frame(stackframes).push(Value::I64(*l));
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
|
|
@ -310,29 +301,29 @@ impl Vm {
|
|||
ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => {
|
||||
// omitting the type checks so far
|
||||
let n = read_u8(&code.opcodes, pc) as usize;
|
||||
Self::current_frame(stackframes)
|
||||
current_frame(stackframes)
|
||||
.push(local_params[n].as_ref().unwrap().clone());
|
||||
}
|
||||
ILOAD_0 | LLOAD_0 | FLOAD_0 | DLOAD_0 | ALOAD_0 => {
|
||||
Self::current_frame(stackframes)
|
||||
current_frame(stackframes)
|
||||
.push(local_params[0].as_ref().unwrap().clone());
|
||||
}
|
||||
ILOAD_1 | LLOAD_1 | FLOAD_1 | DLOAD_1 | ALOAD_1 => {
|
||||
Self::current_frame(stackframes)
|
||||
current_frame(stackframes)
|
||||
.push(local_params[1].as_ref().unwrap().clone());
|
||||
}
|
||||
ILOAD_2 | LLOAD_2 | FLOAD_2 | DLOAD_2 | ALOAD_2 => {
|
||||
Self::current_frame(stackframes)
|
||||
current_frame(stackframes)
|
||||
.push(local_params[2].as_ref().unwrap().clone());
|
||||
}
|
||||
ILOAD_3 | LLOAD_3 | FLOAD_3 | DLOAD_3 | ALOAD_3 => {
|
||||
Self::current_frame(stackframes)
|
||||
current_frame(stackframes)
|
||||
.push(local_params[3].as_ref().unwrap().clone());
|
||||
}
|
||||
IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => {
|
||||
let index = Self::current_frame(stackframes).pop()?;
|
||||
let arrayref = Self::current_frame(stackframes).pop()?;
|
||||
Self::current_frame(stackframes).push(array_load(index, arrayref)?);
|
||||
let index = current_frame(stackframes).pop()?;
|
||||
let arrayref = current_frame(stackframes).pop()?;
|
||||
current_frame(stackframes).push(array_load(index, arrayref)?);
|
||||
}
|
||||
ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => {
|
||||
let index = read_u8(&code.opcodes, pc) as usize;
|
||||
|
|
@ -352,49 +343,55 @@ impl Vm {
|
|||
}
|
||||
BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE
|
||||
| AASTORE => {
|
||||
let value = Self::current_frame(stackframes).pop()?;
|
||||
let index = Self::current_frame(stackframes).pop()?;
|
||||
let arrayref = Self::current_frame(stackframes).pop()?;
|
||||
let value = current_frame(stackframes).pop()?;
|
||||
let index = current_frame(stackframes).pop()?;
|
||||
let arrayref = current_frame(stackframes).pop()?;
|
||||
array_store(value, index, arrayref)?
|
||||
}
|
||||
POP => {
|
||||
Self::current_frame(stackframes).pop()?;
|
||||
current_frame(stackframes).pop()?;
|
||||
}
|
||||
DUP => {
|
||||
let value = Self::current_frame(stackframes).pop()?;
|
||||
Self::current_frame(stackframes).push(value.clone());
|
||||
Self::current_frame(stackframes).push(value);
|
||||
let value = current_frame(stackframes).pop()?;
|
||||
current_frame(stackframes).push(value.clone());
|
||||
current_frame(stackframes).push(value);
|
||||
}
|
||||
IADD => {
|
||||
let stack = Self::current_frame(stackframes);
|
||||
let value2 = stack.pop()?;
|
||||
let value1 = stack.pop()?;
|
||||
stack.push(I32(value1.into_i32() + value2.into_i32()));
|
||||
let value2 = current_frame(stackframes).pop()?;
|
||||
let value1 = current_frame(stackframes).pop()?;
|
||||
debug!("{:?}+{:?}", value1, value2);
|
||||
current_frame(stackframes).push(I32(value1.into_i32() + value2.into_i32()));
|
||||
}
|
||||
IDIV => {
|
||||
let value2 = Self::current_frame(stackframes).pop()?;
|
||||
let value1 = Self::current_frame(stackframes).pop()?;
|
||||
Self::current_frame(stackframes).push(I32(value1.into_i32() / value2.into_i32()));
|
||||
let value2 = current_frame(stackframes).pop()?;
|
||||
let value1 = current_frame(stackframes).pop()?;
|
||||
current_frame(stackframes).push(I32(value1.into_i32() / value2.into_i32()));
|
||||
}
|
||||
ISHR => {
|
||||
let value2 = current_frame(stackframes).pop()?;
|
||||
let value1 = current_frame(stackframes).pop()?;
|
||||
debug!("{:?} shr {:?}", value1, value2);
|
||||
current_frame(stackframes).push(I32(value1.into_i32() >> (value2.into_i32() & 0b00011111)));
|
||||
}
|
||||
|
||||
IFEQ | IFNE | IFLT | IFGE | IFGT | IFLE => {
|
||||
let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode
|
||||
let value = Self::current_frame(stackframes).pop()?;
|
||||
let value = current_frame(stackframes).pop()?;
|
||||
Self::if_cmp(pc, opcode, jmp_to, &value, &I32(0));
|
||||
}
|
||||
|
||||
IF_ICMPEQ | IF_ICMPNE | IF_ICMPGT | IF_ICMPGE | IF_ICMPLT | IF_ICMPLE => {
|
||||
let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode
|
||||
let value1 = Self::current_frame(stackframes).pop()?;
|
||||
let value2 = Self::current_frame(stackframes).pop()?;
|
||||
let value1 = current_frame(stackframes).pop()?;
|
||||
let value2 = current_frame(stackframes).pop()?;
|
||||
Self::if_cmp(pc, opcode, jmp_to, &value1, &value2);
|
||||
}
|
||||
GOTO => {
|
||||
let jmp_to = read_u16(&code.opcodes, pc) - 3;
|
||||
*pc += jmp_to as usize;
|
||||
debug!("GOTO {}", *pc)
|
||||
}
|
||||
IRETURN | FRETURN | DRETURN | ARETURN => {
|
||||
let result = Self::current_frame(stackframes).pop();
|
||||
let result = current_frame(stackframes).pop();
|
||||
stackframes.pop();
|
||||
return result;
|
||||
}
|
||||
|
|
@ -406,7 +403,7 @@ impl Vm {
|
|||
let field_index = read_u16(&code.opcodes, pc);
|
||||
let field_value = get_static(this_class, field_index)?;
|
||||
|
||||
Self::current_frame(stackframes).push(field_value);
|
||||
current_frame(stackframes).push(field_value);
|
||||
}
|
||||
PUTSTATIC => {
|
||||
let classdef = classmanager::get_classdef(&this_class.id);
|
||||
|
|
@ -416,29 +413,16 @@ impl Vm {
|
|||
let (name_index, _) =
|
||||
classdef.cp_name_and_type(field_name_and_type_index);
|
||||
let name = classdef.cp_utf8(name_index);
|
||||
let class_name_index = classdef.cp_class_ref(class_index);
|
||||
let that_class_name = classdef.cp_utf8(class_name_index);
|
||||
|
||||
let val_index = if &this_class.name == that_class_name {
|
||||
// may have to apply this in GETSTATIC too
|
||||
this_class
|
||||
.static_field_mapping
|
||||
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 = classmanager::get_class_by_name(that_class_name).unwrap();
|
||||
let val_index = that_class.static_field_mapping
|
||||
.get(that_class_name)
|
||||
.unwrap()
|
||||
.get(name)
|
||||
.unwrap()
|
||||
.index
|
||||
} else {
|
||||
classmanager::load_class_by_name(that_class_name);
|
||||
let that = classmanager::get_class_by_name(that_class_name).unwrap();
|
||||
that.static_field_mapping
|
||||
.get(that_class_name)
|
||||
.unwrap()
|
||||
.get(name)
|
||||
.unwrap()
|
||||
.index
|
||||
};
|
||||
let value = Self::current_frame(stackframes).pop()?;
|
||||
.index;
|
||||
let value = current_frame(stackframes).pop()?;
|
||||
classmanager::set_static(&this_class.id, val_index, value);
|
||||
}
|
||||
GETFIELD => {
|
||||
|
|
@ -450,13 +434,16 @@ impl Vm {
|
|||
classdef.cp_name_and_type(field_name_and_type_index);
|
||||
let class_name_index = classdef.cp_class_ref(class_index);
|
||||
let declared_type = classdef.cp_utf8(class_name_index);
|
||||
let field_name = classdef.cp_utf8(field_name_index);
|
||||
|
||||
let objectref = Self::current_frame(stackframes).pop()?;
|
||||
let field_name = classdef.cp_utf8(field_name_index);
|
||||
debug!("get field {}.{}",declared_type, field_name);
|
||||
let objectref = current_frame(stackframes).pop()?;
|
||||
if let Ref(instance) = objectref {
|
||||
if let ObjectRef::Object(mut object) = instance {
|
||||
let value = object.get(this_class, declared_type, field_name);
|
||||
Self::current_frame(stackframes).push(value.clone());
|
||||
if let ObjectRef::Object(object) = instance {
|
||||
let runtime_type = classmanager::get_class_by_id(&object.borrow().class_id).unwrap();
|
||||
let object = object.borrow();
|
||||
let value = object.get(runtime_type, declared_type, field_name);
|
||||
current_frame(stackframes).push(value.clone());
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
|
@ -475,11 +462,12 @@ impl Vm {
|
|||
let declared_type = classdef.cp_utf8(class_name_index);
|
||||
let field_name = classdef.cp_utf8(field_name_index);
|
||||
|
||||
let value = Self::current_frame(stackframes).pop()?;
|
||||
let objectref = Self::current_frame(stackframes).pop()?;
|
||||
let value = current_frame(stackframes).pop()?;
|
||||
let objectref = current_frame(stackframes).pop()?;
|
||||
if let Ref(instance) = objectref {
|
||||
if let ObjectRef::Object(mut object) = instance {
|
||||
object.set(this_class, declared_type, field_name, value);
|
||||
if let ObjectRef::Object(object) = instance {
|
||||
let runtime_type = classmanager::get_class_by_id(&object.borrow().class_id).unwrap();
|
||||
object.borrow_mut().set(runtime_type, declared_type, field_name, value);
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
|
|
@ -494,9 +482,9 @@ impl Vm {
|
|||
debug!("invoke {:?}", invocation);
|
||||
let mut args = Vec::with_capacity(invocation.method.num_args);
|
||||
for _ in 0..invocation.method.num_args {
|
||||
args.insert(0, Self::current_frame(stackframes).pop()?.clone());
|
||||
args.insert(0, current_frame(stackframes).pop()?.clone());
|
||||
}
|
||||
args.insert(0, Self::current_frame(stackframes).pop()?);
|
||||
args.insert(0, current_frame(stackframes).pop()?);
|
||||
let return_value = self.execute_special(stackframes,
|
||||
&invocation.class_name,
|
||||
&invocation.method.name,
|
||||
|
|
@ -512,10 +500,9 @@ impl Vm {
|
|||
match return_value {
|
||||
Void => {}
|
||||
_ => {
|
||||
Self::current_frame(stackframes).push(return_value.clone());
|
||||
current_frame(stackframes).push(return_value.clone());
|
||||
}
|
||||
}
|
||||
// println!("stack {} at {}", Self::current_frame(stack).len(), Self::current_frame(stack).at)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
|
@ -529,9 +516,9 @@ impl Vm {
|
|||
debug!("invoke {:?}", invocation);
|
||||
let mut args = Vec::with_capacity(invocation.method.num_args);
|
||||
for _ in 0..invocation.method.num_args {
|
||||
args.insert(0, Self::current_frame(stackframes).pop()?.clone());
|
||||
args.insert(0, current_frame(stackframes).pop()?.clone());
|
||||
}
|
||||
args.insert(0, Self::current_frame(stackframes).pop()?);
|
||||
args.insert(0, current_frame(stackframes).pop()?);
|
||||
let return_value = self.execute_virtual(
|
||||
stackframes,
|
||||
&invocation.class_name,
|
||||
|
|
@ -548,7 +535,7 @@ impl Vm {
|
|||
match return_value {
|
||||
Void => {}
|
||||
_ => {
|
||||
Self::current_frame(stackframes).push(return_value.clone());
|
||||
current_frame(stackframes).push(return_value.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -562,7 +549,7 @@ impl Vm {
|
|||
{
|
||||
let mut args = Vec::with_capacity(invocation.method.num_args);
|
||||
for _ in 0..invocation.method.num_args {
|
||||
args.insert(0, Self::current_frame(stackframes).pop()?.clone());
|
||||
args.insert(0, current_frame(stackframes).pop()?.clone());
|
||||
}
|
||||
let return_value = self.execute_static(stackframes,
|
||||
&invocation.class_name,
|
||||
|
|
@ -579,7 +566,7 @@ impl Vm {
|
|||
match return_value {
|
||||
Void => {}
|
||||
_ => {
|
||||
Self::current_frame(stackframes).push(return_value.clone());
|
||||
current_frame(stackframes).push(return_value.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -594,16 +581,16 @@ impl Vm {
|
|||
classmanager::load_class_by_name(class_name);
|
||||
let class_to_instantiate = classmanager::get_class_by_name(class_name).unwrap();
|
||||
|
||||
let object = ObjectRef::Object(Vm::new_instance(
|
||||
let object = ObjectRef::Object(Rc::new(RefCell::new(Vm::new_instance(
|
||||
class_to_instantiate,
|
||||
));
|
||||
Self::current_frame(stackframes).push(Ref(object));
|
||||
))));
|
||||
current_frame(stackframes).push(Ref(object));
|
||||
}
|
||||
NEWARRAY =>{
|
||||
NEWARRAY => {
|
||||
let arraytype = read_u8(&code.opcodes, pc);
|
||||
let count = Self::current_frame(stackframes).pop()?;
|
||||
let count = current_frame(stackframes).pop()?;
|
||||
let array = ObjectRef::new_array(arraytype, count.into_i32() as usize);
|
||||
Self::current_frame(stackframes).push(Ref(array));
|
||||
current_frame(stackframes).push(Ref(array));
|
||||
}
|
||||
ANEWARRAY => {
|
||||
let classdef = classmanager::get_classdef(&this_class.id);
|
||||
|
|
@ -612,26 +599,24 @@ impl Vm {
|
|||
let class_name = classdef.cp_utf8(class_name_index);
|
||||
classmanager::load_class_by_name(class_name);
|
||||
let arraytype = classmanager::get_class_by_name(class_name).unwrap();
|
||||
let count = Self::current_frame(stackframes).pop()?;
|
||||
if let I32(count) = count {
|
||||
let count = current_frame(stackframes).pop()?.into_i32();
|
||||
let array = ObjectRef::new_object_array(arraytype, count as usize);
|
||||
Self::current_frame(stackframes).push(Ref(array));
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
current_frame(stackframes).push(Ref(array));
|
||||
}
|
||||
ARRAYLENGTH => {
|
||||
let val = Self::current_frame(stackframes).pop()?;
|
||||
let val = current_frame(stackframes).pop()?;
|
||||
if let Ref(val) = val {
|
||||
Self::current_frame(stackframes).push(I32(val.get_array_length() as i32));
|
||||
current_frame(stackframes).push(I32(val.get_array_length() as i32));
|
||||
} else {
|
||||
unreachable!("array length {:?}", val);
|
||||
}
|
||||
}
|
||||
MONITORENTER | MONITOREXIT => {
|
||||
Self::current_frame(stackframes).pop()?;
|
||||
current_frame(stackframes).pop()?;
|
||||
} //TODO implement
|
||||
IFNULL | IFNONNULL => {
|
||||
let jmp_to = read_u16(&code.opcodes, pc) - 3;
|
||||
let value = Self::current_frame(stackframes).pop()?;
|
||||
let value = current_frame(stackframes).pop()?;
|
||||
let its_null = if let Null = value { true } else { false };
|
||||
|
||||
if its_null && opcode == IFNULL {
|
||||
|
|
@ -691,7 +676,7 @@ impl Vm {
|
|||
local_params: &mut Vec<Option<Value>>,
|
||||
index: usize,
|
||||
) -> Result<(), Error> {
|
||||
let value = Self::current_frame(stack).pop()?;
|
||||
let value = current_frame(stack).pop()?;
|
||||
while local_params.len() < index + 1 {
|
||||
local_params.push(None);
|
||||
}
|
||||
|
|
@ -730,3 +715,7 @@ impl MethodSignature {
|
|||
}
|
||||
}
|
||||
|
||||
fn current_frame(stackframes: &mut Vec<StackFrame>) -> &mut StackFrame {
|
||||
let i = stackframes.len() - 1;
|
||||
stackframes.get_mut(i).unwrap()
|
||||
}
|
||||
|
|
@ -8,8 +8,7 @@ mod test {
|
|||
let mut stackframes = Vec::new();
|
||||
let mut vm = Vm::new(&mut stackframes);
|
||||
set_classpath("/Users/Shautvast/dev/java/tests");
|
||||
let ret = vm.execute_virtual(&mut stackframes,"testclasses.IfCmp", "i_is_1()Z", vec![]).unwrap();
|
||||
unsafe {
|
||||
let ret = vm.execute_virtual(&mut stackframes, "testclasses.IfCmp", "i_is_1()Z", vec![]).unwrap();
|
||||
if let Value::I32(b) = ret {
|
||||
// internally a boolean is an int
|
||||
assert_eq!(0, b);
|
||||
|
|
@ -18,7 +17,6 @@ mod test {
|
|||
assert!(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn consts() {
|
||||
|
|
@ -28,7 +26,6 @@ mod test {
|
|||
let ret = vm
|
||||
.execute_static(&mut stackframes, "testclasses.Const", "hello()Ljava/lang/String;", vec![])
|
||||
.unwrap();
|
||||
unsafe {
|
||||
if let Value::Ref(s) = ret {
|
||||
// internally a boolean is an int
|
||||
if let ObjectRef::Object(a) = s {
|
||||
|
|
@ -39,5 +36,4 @@ mod test {
|
|||
assert!(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue