some new opcodes
This commit is contained in:
parent
66983b0783
commit
40a7c6cd1e
8 changed files with 354 additions and 286 deletions
|
|
@ -21,3 +21,4 @@ actually:
|
||||||
|
|
||||||
**Ultimate goal**
|
**Ultimate goal**
|
||||||
* Hello world domination
|
* Hello world domination
|
||||||
|
``
|
||||||
|
|
@ -7,6 +7,7 @@ use rand::random;
|
||||||
|
|
||||||
use crate::class::ObjectRef::*;
|
use crate::class::ObjectRef::*;
|
||||||
|
|
||||||
|
/// ClassId facilitates loose coupling between classes, classdefs and objects
|
||||||
pub type ClassId = usize;
|
pub type ClassId = usize;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -24,20 +25,17 @@ impl TypeIndex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// could move classdef into here. Saves one hashmap lookup
|
|
||||||
// have to look at ownership though
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Class {
|
pub struct Class {
|
||||||
pub id: ClassId,
|
pub id: ClassId,
|
||||||
pub initialized: bool,
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub superclass: Option<ClassId>,
|
pub superclass: Option<ClassId>,
|
||||||
pub parents: LinkedList<ClassId>,
|
pub parents: LinkedList<ClassId>,
|
||||||
pub interfaces: Vec<ClassId>,
|
pub interfaces: Vec<ClassId>,
|
||||||
// lookup index and type from the name
|
// lookup index and type from the name of the declared class and then field
|
||||||
pub(crate) object_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
pub(crate) object_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
||||||
pub(crate) static_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
pub(crate) static_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
||||||
// pub(crate) static_field_data: Vec<Value>,
|
// pub(crate) static_field_data: Vec<Value> // moved to classmanager
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Class {
|
impl Class {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, LinkedList};
|
use std::collections::{HashMap, LinkedList};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
|
@ -12,6 +13,7 @@ use crate::classloader::io::PATH_SEPARATOR;
|
||||||
use crate::vm::Vm;
|
use crate::vm::Vm;
|
||||||
|
|
||||||
static mut CLASSMANAGER: Lazy<ClassManager> = Lazy::new(|| ClassManager::new());
|
static mut CLASSMANAGER: Lazy<ClassManager> = Lazy::new(|| ClassManager::new());
|
||||||
|
static PRIMITIVES: Lazy<Vec<&str>> = Lazy::new(|| vec!["B", "S", "I", "J", "F", "D", "Z", "J", "C"]);
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -151,23 +153,64 @@ impl ClassManager {
|
||||||
self.classdefs.get(&id).unwrap()
|
self.classdefs.get(&id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// loads the class if not already there
|
||||||
fn load_class_by_name(&mut self, name: &str) {
|
fn load_class_by_name(&mut self, name: &str) {
|
||||||
let id = self.names.get(name);
|
debug!("load class {}", name);
|
||||||
|
// determine no of dimensions and get type of array if any
|
||||||
|
let mut chars = name.chars();
|
||||||
|
let mut num_dims = 0;
|
||||||
|
while let Some(c) = chars.nth(num_dims) {
|
||||||
|
if c == '[' {
|
||||||
|
num_dims += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut type_name = name[num_dims..name.len()].to_owned();
|
||||||
|
|
||||||
|
if num_dims > 0 {
|
||||||
|
if !PRIMITIVES.contains(&type_name.as_str()){
|
||||||
|
type_name = type_name[1..type_name.len()].to_owned();
|
||||||
|
}
|
||||||
|
let id = self.get_or_new_id(name);
|
||||||
|
if !self.class_objects.contains_key(&id) {
|
||||||
|
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(Rc::new(RefCell::new(instance))));
|
||||||
|
|
||||||
|
self.class_objects.insert(id, instance);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// in cache?
|
||||||
|
let id = self.names.get(&type_name);
|
||||||
match id {
|
match id {
|
||||||
Some(id) => if self.classes.get(id).is_none() {
|
Some(id) => if self.classes.get(id).is_none() {
|
||||||
self.add_class(name);
|
self.add_class(&type_name);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.add_class(name);
|
self.add_class(&type_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get optional classid from cache
|
||||||
fn get_class_by_name(&self, name: &str) -> Option<&Class> {
|
fn get_class_by_name(&self, name: &str) -> Option<&Class> {
|
||||||
let id = self.names.get(name);
|
let id = self.names.get(name);
|
||||||
self.classes.get(id.unwrap())
|
self.classes.get(id.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// adds the class and calculates the 'offset' of it's fields (static and non-static)
|
||||||
|
/// this is a map (declared-class -> map (field-name -> type_index))
|
||||||
|
/// -> fields are not polymorphic, meaning a field can exist in the class and in the superclass and can be addressed individually (no hiding)
|
||||||
|
/// -> the bytecode will know what declared type field is needed
|
||||||
|
///
|
||||||
|
/// type_index is tuple (field-type, index)
|
||||||
|
/// field-type is a string
|
||||||
|
/// index is an index into the list of values that object instances will use to store the values
|
||||||
|
///
|
||||||
|
/// the function also instantiates a (java.lang.) Class object for each loaded class
|
||||||
fn add_class(&mut self, name: &str) -> ClassId {
|
fn add_class(&mut self, name: &str) -> ClassId {
|
||||||
debug!("add class {}", name);
|
debug!("add class {}", name);
|
||||||
let this_classid = self.load(name);
|
let this_classid = self.load(name);
|
||||||
|
|
@ -202,11 +245,11 @@ impl ClassManager {
|
||||||
.map(|n| *self.names.get(n.as_str()).unwrap())
|
.map(|n| *self.names.get(n.as_str()).unwrap())
|
||||||
.collect();
|
.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,
|
id: this_classid,
|
||||||
initialized: false,
|
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
superclass: superclass_id,
|
superclass: superclass_id,
|
||||||
parents,
|
parents,
|
||||||
|
|
@ -215,6 +258,7 @@ impl ClassManager {
|
||||||
static_field_mapping,
|
static_field_mapping,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// add a new Class instance
|
||||||
if name != "java/lang/Class" {
|
if name != "java/lang/Class" {
|
||||||
let cls = self.get_class_by_name("java/lang/Class").unwrap();
|
let cls = self.get_class_by_name("java/lang/Class").unwrap();
|
||||||
let mut instance = Object::new(cls);
|
let mut instance = Object::new(cls);
|
||||||
|
|
@ -223,15 +267,16 @@ impl ClassManager {
|
||||||
|
|
||||||
self.class_objects.insert(this_classid, instance);
|
self.class_objects.insert(this_classid, instance);
|
||||||
}
|
}
|
||||||
let clinit = this_classdef.methods.contains_key("<clinit>()V");
|
|
||||||
|
|
||||||
if clinit {
|
// run static init
|
||||||
|
if this_classdef.methods.contains_key("<clinit>()V") {
|
||||||
self.vm.execute_special(&mut vec![], name, "<clinit>()V", vec![]).unwrap();
|
self.vm.execute_special(&mut vec![], name, "<clinit>()V", vec![]).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
this_classid
|
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>>,
|
static_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
|
||||||
object_field_map_index: &mut usize,
|
object_field_map_index: &mut usize,
|
||||||
|
|
@ -269,10 +314,7 @@ impl ClassManager {
|
||||||
|
|
||||||
/// loads the class and returns it's dependencies
|
/// loads the class and returns it's dependencies
|
||||||
fn load_class_and_deps(&mut self, name: &str) -> (ClassId, Vec<String>) {
|
fn load_class_and_deps(&mut self, name: &str) -> (ClassId, Vec<String>) {
|
||||||
let id = *self.names.entry(name.to_string()).or_insert_with(|| {
|
let id = self.get_or_new_id(name);
|
||||||
self.current_id += 1;
|
|
||||||
self.current_id
|
|
||||||
});
|
|
||||||
|
|
||||||
let classdef = self.classdefs
|
let classdef = self.classdefs
|
||||||
.entry(id)
|
.entry(id)
|
||||||
|
|
@ -280,6 +322,14 @@ impl ClassManager {
|
||||||
(id, inspect_dependencies(classdef))
|
(id, inspect_dependencies(classdef))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_or_new_id(&mut self, name: &str) -> ClassId {
|
||||||
|
let id = *self.names.entry(name.to_string()).or_insert_with(|| {
|
||||||
|
self.current_id += 1;
|
||||||
|
self.current_id
|
||||||
|
});
|
||||||
|
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)];
|
let mut field_data = vec![Null; n_fields(field_mapping)];
|
||||||
|
|
||||||
|
|
@ -326,7 +376,9 @@ pub(crate) fn inspect_dependencies(classdef: &ClassDef) -> Vec<String> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::classloader::classdef::{CpEntry, Field};
|
use crate::classloader::classdef::{CpEntry, Field};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -372,7 +424,7 @@ mod test {
|
||||||
let mut fields_declared_by_java_lang_class = 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 });
|
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);
|
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() });
|
classes.insert(3, Class { id: 3, name: "".into(), superclass: None, parents: LinkedList::new(), interfaces: vec![], object_field_mapping: class_field_mapping, static_field_mapping: HashMap::new() });
|
||||||
|
|
||||||
let mut cm = ClassManager {
|
let mut cm = ClassManager {
|
||||||
static_class_data: HashMap::new(),
|
static_class_data: HashMap::new(),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
|
|
||||||
use crate::class::ObjectRef;
|
use crate::class::ObjectRef::*;
|
||||||
use crate::class::Value::{self, *};
|
use crate::class::Value::{self, *};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -13,40 +13,40 @@ pub(crate) fn array_load(index: Value, arrayref: Value) -> Result<Value, Error>
|
||||||
}
|
}
|
||||||
if let Ref(objectref) = arrayref {
|
if let Ref(objectref) = arrayref {
|
||||||
match objectref {
|
match objectref {
|
||||||
ObjectRef::ByteArray(array) => {
|
ByteArray(array) => {
|
||||||
return Ok(I32(array[index] as i32));
|
return Ok(I32(array[index] as i32));
|
||||||
}
|
}
|
||||||
ObjectRef::ShortArray(array) => {
|
ShortArray(array) => {
|
||||||
return Ok(I32(array[index] as i32));
|
return Ok(I32(array[index] as i32));
|
||||||
}
|
}
|
||||||
ObjectRef::IntArray(array) => {
|
IntArray(array) => {
|
||||||
return Ok(I32(array[index]));
|
return Ok(I32(array[index]));
|
||||||
}
|
}
|
||||||
ObjectRef::BooleanArray(array) => {
|
BooleanArray(array) => {
|
||||||
return Ok(I32(array[index] as i32));
|
return Ok(I32(array[index] as i32));
|
||||||
}
|
}
|
||||||
ObjectRef::CharArray(array) => {
|
CharArray(array) => {
|
||||||
return Ok(CHAR(array[index]));
|
return Ok(CHAR(array[index]));
|
||||||
}
|
}
|
||||||
ObjectRef::LongArray(array) => {
|
LongArray(array) => {
|
||||||
return Ok(I64(array[index]));
|
return Ok(I64(array[index]));
|
||||||
}
|
}
|
||||||
ObjectRef::FloatArray(array) => {
|
FloatArray(array) => {
|
||||||
return Ok(F32(array[index]));
|
return Ok(F32(array[index]));
|
||||||
}
|
}
|
||||||
ObjectRef::DoubleArray(array) => {
|
DoubleArray(array) => {
|
||||||
return Ok(F64(array[index]));
|
return Ok(F64(array[index]));
|
||||||
}
|
}
|
||||||
ObjectRef::ObjectArray(_arraytype, data) => {
|
ObjectArray(_arraytype, data) => {
|
||||||
return Ok(Ref(data[index].clone()));
|
return Ok(Ref(data[index].clone()));
|
||||||
}
|
}
|
||||||
ObjectRef::StringArray(array) => {
|
StringArray(array) => {
|
||||||
return Ok(Utf8(array[index].to_owned()));
|
return Ok(Utf8(array[index].to_owned()));
|
||||||
}
|
}
|
||||||
ObjectRef::Class(_) => {
|
Class(_) => {
|
||||||
panic!("should be array")
|
panic!("should be array")
|
||||||
}
|
}
|
||||||
ObjectRef::Object(_) => {
|
Object(_) => {
|
||||||
panic!("should be array")
|
panic!("should be array")
|
||||||
} //throw error?
|
} //throw error?
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +63,7 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result
|
||||||
if let I32(index) = index {
|
if let I32(index) = index {
|
||||||
if let Ref(mut objectref) = arrayref {
|
if let Ref(mut objectref) = arrayref {
|
||||||
match objectref {
|
match objectref {
|
||||||
ObjectRef::ByteArray(ref mut array) => {
|
ByteArray(ref mut array) => {
|
||||||
if let I32(value) = value {
|
if let I32(value) = value {
|
||||||
// is i32 correct?
|
// is i32 correct?
|
||||||
array[index as usize] = value as i8;
|
array[index as usize] = value as i8;
|
||||||
|
|
@ -71,7 +71,7 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::ShortArray(ref mut array) => {
|
ShortArray(ref mut array) => {
|
||||||
if let I32(value) = value {
|
if let I32(value) = value {
|
||||||
// is i32 correct?
|
// is i32 correct?
|
||||||
array[index as usize] = value as i16;
|
array[index as usize] = value as i16;
|
||||||
|
|
@ -79,63 +79,63 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::IntArray(ref mut array) => {
|
IntArray(ref mut array) => {
|
||||||
if let I32(value) = value {
|
if let I32(value) = value {
|
||||||
array[index as usize] = value;
|
array[index as usize] = value;
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::BooleanArray(ref mut array) => {
|
BooleanArray(ref mut array) => {
|
||||||
if let I32(value) = value {
|
if let I32(value) = value {
|
||||||
array[index as usize] = value > 0;
|
array[index as usize] = value > 0;
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::CharArray(ref mut array) => unsafe {
|
CharArray(ref mut array) => unsafe {
|
||||||
if let I32(value) = value {
|
if let I32(value) = value {
|
||||||
array[index as usize] = char::from_u32_unchecked(value as u32);
|
array[index as usize] = char::from_u32_unchecked(value as u32);
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::LongArray(ref mut array) => {
|
LongArray(ref mut array) => {
|
||||||
if let I64(value) = value {
|
if let I64(value) = value {
|
||||||
array[index as usize] = value;
|
array[index as usize] = value;
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::FloatArray(ref mut array) => {
|
FloatArray(ref mut array) => {
|
||||||
if let F32(value) = value {
|
if let F32(value) = value {
|
||||||
array[index as usize] = value
|
array[index as usize] = value
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::DoubleArray(ref mut array) => {
|
DoubleArray(ref mut array) => {
|
||||||
if let F64(value) = value {
|
if let F64(value) = value {
|
||||||
array[index as usize] = value
|
array[index as usize] = value
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::ObjectArray(_arraytype, ref mut array) => {
|
ObjectArray(_arraytype, ref mut array) => {
|
||||||
if let Ref(ref value) = value {
|
if let Ref(ref value) = value {
|
||||||
array[index as usize] = value.clone();
|
array[index as usize] = value.clone();
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::StringArray(ref mut array) => {
|
StringArray(ref mut array) => {
|
||||||
if let Utf8(ref value) = value {
|
if let Utf8(ref value) = value {
|
||||||
array[index as usize] = value.clone();
|
array[index as usize] = value.clone();
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::Object(_) | ObjectRef::Class(_) => {} //throw error?
|
Object(_) | Class(_) => {} //throw error?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use anyhow::Error;
|
use anyhow::{anyhow, Error};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::class::{ObjectRef, Value};
|
use crate::class::{ObjectRef, Value};
|
||||||
use crate::class::ObjectRef::Object;
|
use crate::class::ObjectRef::Object;
|
||||||
use crate::class::Value::Void;
|
use crate::class::Value::{I32, Void};
|
||||||
use crate::classmanager;
|
use crate::classmanager;
|
||||||
use crate::vm::stack::StackFrame;
|
use crate::vm::stack::StackFrame;
|
||||||
use crate::vm::Vm;
|
use crate::vm::Vm;
|
||||||
|
|
@ -17,19 +17,35 @@ pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec<StackFrame>, class_name:
|
||||||
debug!("native {}.{}", class_name, method_name);
|
debug!("native {}.{}", class_name, method_name);
|
||||||
|
|
||||||
match class_name.as_str() {
|
match class_name.as_str() {
|
||||||
"java/lang/Class" => java_lang_class(vm, method_name),
|
"java/lang/Class" => java_lang_Class(vm, method_name),
|
||||||
|
"java/lang/System" => java_lang_System(vm, method_name),
|
||||||
|
"jdk/internal/misc/Unsafe" => jdk_internal_misc_Unsafe(vm, method_name),
|
||||||
"jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(vm, stackframes, method_name),
|
"jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(vm, stackframes, method_name),
|
||||||
_ => Ok(Void)
|
_ => unimplemented!("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn java_lang_class(_vm: &Vm, method_name: &str) -> Result<Value, Error> {
|
fn java_lang_Class(_vm: &Vm, method_name: &str) -> Result<Value, Error> {
|
||||||
Ok(match method_name {
|
Ok(match method_name {
|
||||||
"desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false),
|
"desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false),
|
||||||
_ => Void
|
_ => Void
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn java_lang_System(_vm: &Vm, method_name: &str) -> Result<Value, Error> {
|
||||||
|
Ok(match method_name {
|
||||||
|
_ => Void
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jdk_internal_misc_Unsafe(_vm: &Vm, 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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn jdk_internal_util_SystemProps_Raw(vm: &mut Vm, stackframes: &mut Vec<StackFrame>, method_name: &str) -> Result<Value, Error> {
|
fn jdk_internal_util_SystemProps_Raw(vm: &mut Vm, stackframes: &mut Vec<StackFrame>, method_name: &str) -> Result<Value, Error> {
|
||||||
match method_name {
|
match method_name {
|
||||||
"platformProperties()[Ljava/lang/String;" => platformProperties(),
|
"platformProperties()[Ljava/lang/String;" => platformProperties(),
|
||||||
|
|
|
||||||
|
|
@ -195,11 +195,13 @@ pub const _FADD: u8 = 98;
|
||||||
// (0x62) Add float
|
// (0x62) Add float
|
||||||
pub const _DADD: u8 = 99; // (0x63) add double
|
pub const _DADD: u8 = 99; // (0x63) add double
|
||||||
|
|
||||||
|
pub const ISUB: u8 = 100;
|
||||||
pub const _DSUB: u8 = 103;
|
pub const _DSUB: u8 = 103;
|
||||||
// (0x67) subtract double
|
// (0x67) subtract double
|
||||||
pub const _FMUL: u8 = 106;
|
pub const _FMUL: u8 = 106;
|
||||||
// (0x6a) Multiply float
|
// (0x6a) Multiply float
|
||||||
pub const _DMUL: u8 = 107; // (0x6b) Multiply double
|
pub const _DMUL: u8 = 107;
|
||||||
|
// (0x6b) Multiply double
|
||||||
pub const IDIV: u8 = 108;
|
pub const IDIV: u8 = 108;
|
||||||
pub const _FDIV: u8 = 110;
|
pub const _FDIV: u8 = 110;
|
||||||
// (0x6e) Divide float
|
// (0x6e) Divide float
|
||||||
|
|
@ -212,7 +214,7 @@ pub const _DREM: u8 = 115;
|
||||||
pub const _FNEG: u8 = 118;
|
pub const _FNEG: u8 = 118;
|
||||||
// (0x76) Negate float
|
// (0x76) Negate float
|
||||||
pub const _DNEG: u8 = 119; // (0x77) Negate double
|
pub const _DNEG: u8 = 119; // (0x77) Negate double
|
||||||
|
pub const ISHL:u8 = 120;
|
||||||
pub const ISHR: u8 = 122;
|
pub const ISHR: u8 = 122;
|
||||||
pub const _F2I: u8 = 139;
|
pub const _F2I: u8 = 139;
|
||||||
// (0x8b) Convert float to int
|
// (0x8b) Convert float to int
|
||||||
|
|
@ -399,6 +401,7 @@ pub const OPCODES:Lazy<Vec<&str>> = Lazy::new(|| {
|
||||||
opcodes[IADD as usize] = "IADD";
|
opcodes[IADD as usize] = "IADD";
|
||||||
opcodes[_FADD as usize] = "_FADD";
|
opcodes[_FADD as usize] = "_FADD";
|
||||||
opcodes[_DADD as usize] = "_DADD";
|
opcodes[_DADD as usize] = "_DADD";
|
||||||
|
opcodes[ISUB as usize] = "ISUB";
|
||||||
opcodes[_DSUB as usize] = "_DSUB";
|
opcodes[_DSUB as usize] = "_DSUB";
|
||||||
opcodes[_FMUL as usize] = "_FMUL";
|
opcodes[_FMUL as usize] = "_FMUL";
|
||||||
opcodes[_DMUL as usize] = "_DMUL";
|
opcodes[_DMUL as usize] = "_DMUL";
|
||||||
|
|
@ -409,6 +412,7 @@ pub const OPCODES:Lazy<Vec<&str>> = Lazy::new(|| {
|
||||||
opcodes[_DREM as usize] = "_DREM";
|
opcodes[_DREM as usize] = "_DREM";
|
||||||
opcodes[_FNEG as usize] = "_FNEG";
|
opcodes[_FNEG as usize] = "_FNEG";
|
||||||
opcodes[_DNEG as usize] = "_DNEG";
|
opcodes[_DNEG as usize] = "_DNEG";
|
||||||
|
opcodes[ISHL as usize] = "ISHL";
|
||||||
opcodes[ISHR as usize] = "ISHR";
|
opcodes[ISHR as usize] = "ISHR";
|
||||||
opcodes[_F2I as usize] = "_F2I";
|
opcodes[_F2I as usize] = "_F2I";
|
||||||
opcodes[_F2L as usize] = "_F2L";
|
opcodes[_F2L as usize] = "_F2L";
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,17 @@
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
use crate::class::{Class, Value};
|
use crate::class::{Class, ObjectRef, Value};
|
||||||
use crate::classloader::classdef::CpEntry;
|
use crate::class::Value::{I32, Ref};
|
||||||
|
use crate::classloader::classdef::{CpEntry, Method};
|
||||||
use crate::classmanager;
|
use crate::classmanager;
|
||||||
use crate::vm::vm::{Invocation, MethodSignature};
|
use crate::vm::stack::StackFrame;
|
||||||
|
use crate::vm::Vm;
|
||||||
|
use crate::vm::vm::{current_frame, Invocation, MethodSignature};
|
||||||
|
|
||||||
/// the place for opcode implementations that are a bit long
|
/// the place for opcode implementations that are a bit long
|
||||||
|
|
||||||
|
|
@ -66,6 +71,52 @@ pub(crate) fn get_signature_for_invoke(cp: &HashMap<u16, CpEntry>, index: u16) -
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// LDC in all varieties (LDC, LDC_W, LDC2_W)
|
||||||
|
pub(crate) fn load_constant(cp_index: &u16, method: &Method, stackframes: &mut Vec<StackFrame>, this_class: &Class){
|
||||||
|
let c = method.constant_pool.get(cp_index).unwrap();
|
||||||
|
match c {
|
||||||
|
CpEntry::Integer(i) => {
|
||||||
|
current_frame(stackframes).push(I32(*i));
|
||||||
|
}
|
||||||
|
CpEntry::Float(f) => {
|
||||||
|
current_frame(stackframes).push(Value::F32(*f));
|
||||||
|
}
|
||||||
|
CpEntry::Double(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 mut stringinstance = Vm::new_instance(stringclass);
|
||||||
|
stringinstance.set(stringclass, "java/lang/String", "value", Value::Ref(ObjectRef::new_byte_array(string)));
|
||||||
|
|
||||||
|
debug!("new string \"{}\"", utf8);
|
||||||
|
|
||||||
|
current_frame(stackframes).push(Ref(ObjectRef::Object(Rc::new(RefCell::new(stringinstance)))));
|
||||||
|
}
|
||||||
|
CpEntry::Long(l) => {
|
||||||
|
current_frame(stackframes).push(Value::I64(*l));
|
||||||
|
}
|
||||||
|
CpEntry::ClassRef(utf8_index) => {
|
||||||
|
let classdef = classmanager::get_classdef(&this_class.id);
|
||||||
|
let class_name = classdef.cp_utf8(utf8_index);
|
||||||
|
classmanager::load_class_by_name(class_name);
|
||||||
|
let klass_id = classmanager::get_classid(class_name);
|
||||||
|
if let Some(class) = classmanager::get_classobject(klass_id) {
|
||||||
|
current_frame(stackframes).push(class.clone());
|
||||||
|
} else {
|
||||||
|
unreachable!("should not be here");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("add variant {:?}", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn get_num_args(signature: &str) -> usize {
|
fn get_num_args(signature: &str) -> usize {
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
|
|
|
||||||
96
src/vm/vm.rs
96
src/vm/vm.rs
|
|
@ -7,7 +7,7 @@ use log::{debug, error};
|
||||||
|
|
||||||
use crate::class::{Class, Object, ObjectRef, Value};
|
use crate::class::{Class, Object, ObjectRef, Value};
|
||||||
use crate::class::Value::{F32, F64, I32, I64, Null, Ref, Utf8, Void};
|
use crate::class::Value::{F32, F64, I32, I64, Null, Ref, Utf8, Void};
|
||||||
use crate::classloader::classdef::{AttributeType, CpEntry, Modifier};
|
use crate::classloader::classdef::{AttributeType, CpEntry, Method, Modifier};
|
||||||
use crate::classloader::io::{read_u16, read_u8};
|
use crate::classloader::io::{read_u16, read_u8};
|
||||||
use crate::classmanager;
|
use crate::classmanager;
|
||||||
use crate::classmanager::get_class_by_id;
|
use crate::classmanager::get_class_by_id;
|
||||||
|
|
@ -15,7 +15,7 @@ use crate::vm::array::{array_load, array_store};
|
||||||
use crate::vm::native::invoke_native;
|
use crate::vm::native::invoke_native;
|
||||||
use crate::vm::opcodes;
|
use crate::vm::opcodes;
|
||||||
use crate::vm::opcodes::*;
|
use crate::vm::opcodes::*;
|
||||||
use crate::vm::operations::{get_signature_for_invoke, get_static};
|
use crate::vm::operations::{get_signature_for_invoke, get_static, load_constant};
|
||||||
use crate::vm::stack::StackFrame;
|
use crate::vm::stack::StackFrame;
|
||||||
|
|
||||||
pub struct Vm {}
|
pub struct Vm {}
|
||||||
|
|
@ -27,6 +27,8 @@ const PATH_SEPARATOR: char = ':';
|
||||||
#[cfg(target_family = "windows")]
|
#[cfg(target_family = "windows")]
|
||||||
const PATH_SEPARATOR: char = ';';
|
const PATH_SEPARATOR: char = ';';
|
||||||
|
|
||||||
|
const MASK_LOWER_5BITS: i32 = 0b00011111;
|
||||||
|
|
||||||
/// The singlethreaded VM (maybe a future Thread)
|
/// The singlethreaded VM (maybe a future Thread)
|
||||||
//TODO goto
|
//TODO goto
|
||||||
//TODO error handling
|
//TODO error handling
|
||||||
|
|
@ -220,83 +222,15 @@ impl Vm {
|
||||||
}
|
}
|
||||||
LDC => {
|
LDC => {
|
||||||
let cp_index = read_u8(&code.opcodes, pc) as u16;
|
let cp_index = read_u8(&code.opcodes, pc) as u16;
|
||||||
let c = method.constant_pool.get(&cp_index).unwrap();
|
load_constant(&cp_index, method, stackframes, this_class);
|
||||||
match c {
|
|
||||||
CpEntry::Integer(i) => {
|
|
||||||
current_frame(stackframes).push(I32(*i));
|
|
||||||
}
|
|
||||||
CpEntry::Float(f) => {
|
|
||||||
current_frame(stackframes).push(Value::F32(*f));
|
|
||||||
}
|
|
||||||
CpEntry::Double(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 mut stringinstance = Vm::new_instance(stringclass);
|
|
||||||
stringinstance.set(stringclass, "java/lang/String", "value", Value::Ref(ObjectRef::new_byte_array(string)));
|
|
||||||
|
|
||||||
debug!("new string \"{}\"", utf8);
|
|
||||||
|
|
||||||
current_frame(stackframes).push(Ref(ObjectRef::Object(Rc::new(RefCell::new(stringinstance)))));
|
|
||||||
}
|
|
||||||
CpEntry::Long(l) => {
|
|
||||||
current_frame(stackframes).push(Value::I64(*l));
|
|
||||||
}
|
|
||||||
CpEntry::ClassRef(utf8) => {
|
|
||||||
let classdef = classmanager::get_classdef(&this_class.id);
|
|
||||||
let class_name = classdef.cp_utf8(utf8);
|
|
||||||
classmanager::load_class_by_name(class_name);
|
|
||||||
let klass_id = classmanager::get_classid(class_name);
|
|
||||||
if let Some(class) = classmanager::get_classobject(klass_id) {
|
|
||||||
current_frame(stackframes).push(class.clone());
|
|
||||||
} else {
|
|
||||||
unreachable!("should not be here");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
panic!("add variant {:?}", c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
LDC_W => {
|
LDC_W => {
|
||||||
let cp_index = read_u16(&code.opcodes, pc);
|
let cp_index = read_u16(&code.opcodes, pc);
|
||||||
let cp_entry = method.constant_pool.get(&cp_index).unwrap();
|
load_constant(&cp_index, method, stackframes, this_class);
|
||||||
match cp_entry {
|
|
||||||
CpEntry::Integer(i) => {
|
|
||||||
current_frame(stackframes).push(I32(*i));
|
|
||||||
}
|
|
||||||
CpEntry::Float(f) => {
|
|
||||||
current_frame(stackframes).push(F32(*f));
|
|
||||||
}
|
|
||||||
CpEntry::StringRef(utf8_index) => {
|
|
||||||
if let CpEntry::Utf8(s) = method.constant_pool.get(utf8_index).unwrap() {
|
|
||||||
current_frame(stackframes).push(Utf8(s.to_owned()));
|
|
||||||
} else {}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
error!("{:?}", cp_entry);
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
LDC2_W => {
|
LDC2_W => {
|
||||||
let cp_index = read_u16(&code.opcodes, pc);
|
let cp_index = read_u16(&code.opcodes, pc);
|
||||||
match method.constant_pool.get(&cp_index).unwrap() {
|
load_constant(&cp_index, method, stackframes, this_class);
|
||||||
CpEntry::Double(d) => {
|
|
||||||
current_frame(stackframes).push(Value::F64(*d));
|
|
||||||
}
|
|
||||||
CpEntry::Long(l) => {
|
|
||||||
current_frame(stackframes).push(Value::I64(*l));
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => {
|
ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => {
|
||||||
// omitting the type checks so far
|
// omitting the type checks so far
|
||||||
|
|
@ -362,16 +296,28 @@ impl Vm {
|
||||||
debug!("{:?}+{:?}", value1, value2);
|
debug!("{:?}+{:?}", value1, value2);
|
||||||
current_frame(stackframes).push(I32(value1.into_i32() + value2.into_i32()));
|
current_frame(stackframes).push(I32(value1.into_i32() + value2.into_i32()));
|
||||||
}
|
}
|
||||||
|
ISUB => {
|
||||||
|
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 => {
|
IDIV => {
|
||||||
let value2 = current_frame(stackframes).pop()?;
|
let value2 = current_frame(stackframes).pop()?;
|
||||||
let value1 = current_frame(stackframes).pop()?;
|
let value1 = current_frame(stackframes).pop()?;
|
||||||
current_frame(stackframes).push(I32(value1.into_i32() / value2.into_i32()));
|
current_frame(stackframes).push(I32(value1.into_i32() / value2.into_i32()));
|
||||||
}
|
}
|
||||||
|
ISHL => {
|
||||||
|
let value2 = current_frame(stackframes).pop()?;
|
||||||
|
let value1 = current_frame(stackframes).pop()?;
|
||||||
|
debug!("{:?} shl {:?}", value1, value2);
|
||||||
|
current_frame(stackframes).push(I32(value1.into_i32() << (value2.into_i32() & MASK_LOWER_5BITS)));
|
||||||
|
}
|
||||||
ISHR => {
|
ISHR => {
|
||||||
let value2 = current_frame(stackframes).pop()?;
|
let value2 = current_frame(stackframes).pop()?;
|
||||||
let value1 = current_frame(stackframes).pop()?;
|
let value1 = current_frame(stackframes).pop()?;
|
||||||
debug!("{:?} shr {:?}", value1, value2);
|
debug!("{:?} shr {:?}", value1, value2);
|
||||||
current_frame(stackframes).push(I32(value1.into_i32() >> (value2.into_i32() & 0b00011111)));
|
current_frame(stackframes).push(I32(value1.into_i32() >> (value2.into_i32() & MASK_LOWER_5BITS)));
|
||||||
}
|
}
|
||||||
IFEQ | IFNE | IFLT | IFGE | IFGT | IFLE => {
|
IFEQ | IFNE | IFLT | IFGE | IFGT | IFLE => {
|
||||||
let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode
|
let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode
|
||||||
|
|
@ -715,7 +661,7 @@ impl MethodSignature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_frame(stackframes: &mut Vec<StackFrame>) -> &mut StackFrame {
|
pub(crate) fn current_frame(stackframes: &mut Vec<StackFrame>) -> &mut StackFrame {
|
||||||
let i = stackframes.len() - 1;
|
let i = stackframes.len() - 1;
|
||||||
stackframes.get_mut(i).unwrap()
|
stackframes.get_mut(i).unwrap()
|
||||||
}
|
}
|
||||||
Loading…
Add table
Reference in a new issue