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**
|
||||
* Hello world domination
|
||||
``
|
||||
|
|
@ -7,6 +7,7 @@ use rand::random;
|
|||
|
||||
use crate::class::ObjectRef::*;
|
||||
|
||||
/// ClassId facilitates loose coupling between classes, classdefs and objects
|
||||
pub type ClassId = usize;
|
||||
|
||||
#[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)]
|
||||
pub struct Class {
|
||||
pub id: ClassId,
|
||||
pub initialized: bool,
|
||||
pub name: String,
|
||||
pub superclass: Option<ClassId>,
|
||||
pub parents: LinkedList<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) 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 {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, LinkedList};
|
||||
use std::rc::Rc;
|
||||
|
||||
use log::debug;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
|
|
@ -12,6 +13,7 @@ use crate::classloader::io::PATH_SEPARATOR;
|
|||
use crate::vm::Vm;
|
||||
|
||||
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() {
|
||||
unsafe {
|
||||
|
|
@ -151,23 +153,64 @@ impl ClassManager {
|
|||
self.classdefs.get(&id).unwrap()
|
||||
}
|
||||
|
||||
/// loads the class if not already there
|
||||
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 {
|
||||
Some(id) => if self.classes.get(id).is_none() {
|
||||
self.add_class(name);
|
||||
self.add_class(&type_name);
|
||||
}
|
||||
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> {
|
||||
let id = self.names.get(name);
|
||||
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 {
|
||||
debug!("add class {}", name);
|
||||
let this_classid = self.load(name);
|
||||
|
|
@ -202,11 +245,11 @@ impl ClassManager {
|
|||
.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.classes.insert(this_classid, Class {
|
||||
id: this_classid,
|
||||
initialized: false,
|
||||
name: name.into(),
|
||||
superclass: superclass_id,
|
||||
parents,
|
||||
|
|
@ -215,6 +258,7 @@ impl ClassManager {
|
|||
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);
|
||||
|
|
@ -223,15 +267,16 @@ impl ClassManager {
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
this_classid
|
||||
}
|
||||
|
||||
/// like described above
|
||||
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,
|
||||
|
|
@ -269,10 +314,7 @@ impl ClassManager {
|
|||
|
||||
/// loads the class and returns it's dependencies
|
||||
fn load_class_and_deps(&mut self, name: &str) -> (ClassId, Vec<String>) {
|
||||
let id = *self.names.entry(name.to_string()).or_insert_with(|| {
|
||||
self.current_id += 1;
|
||||
self.current_id
|
||||
});
|
||||
let id = self.get_or_new_id(name);
|
||||
|
||||
let classdef = self.classdefs
|
||||
.entry(id)
|
||||
|
|
@ -280,6 +322,14 @@ impl ClassManager {
|
|||
(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> {
|
||||
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)]
|
||||
mod test {
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::classloader::classdef::{CpEntry, Field};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
|
@ -372,7 +424,7 @@ mod test {
|
|||
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() });
|
||||
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 {
|
||||
static_class_data: HashMap::new(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::{anyhow, Error};
|
||||
|
||||
use crate::class::ObjectRef;
|
||||
use crate::class::ObjectRef::*;
|
||||
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 {
|
||||
match objectref {
|
||||
ObjectRef::ByteArray(array) => {
|
||||
ByteArray(array) => {
|
||||
return Ok(I32(array[index] as i32));
|
||||
}
|
||||
ObjectRef::ShortArray(array) => {
|
||||
ShortArray(array) => {
|
||||
return Ok(I32(array[index] as i32));
|
||||
}
|
||||
ObjectRef::IntArray(array) => {
|
||||
IntArray(array) => {
|
||||
return Ok(I32(array[index]));
|
||||
}
|
||||
ObjectRef::BooleanArray(array) => {
|
||||
BooleanArray(array) => {
|
||||
return Ok(I32(array[index] as i32));
|
||||
}
|
||||
ObjectRef::CharArray(array) => {
|
||||
CharArray(array) => {
|
||||
return Ok(CHAR(array[index]));
|
||||
}
|
||||
ObjectRef::LongArray(array) => {
|
||||
LongArray(array) => {
|
||||
return Ok(I64(array[index]));
|
||||
}
|
||||
ObjectRef::FloatArray(array) => {
|
||||
FloatArray(array) => {
|
||||
return Ok(F32(array[index]));
|
||||
}
|
||||
ObjectRef::DoubleArray(array) => {
|
||||
DoubleArray(array) => {
|
||||
return Ok(F64(array[index]));
|
||||
}
|
||||
ObjectRef::ObjectArray(_arraytype, data) => {
|
||||
ObjectArray(_arraytype, data) => {
|
||||
return Ok(Ref(data[index].clone()));
|
||||
}
|
||||
ObjectRef::StringArray(array) => {
|
||||
StringArray(array) => {
|
||||
return Ok(Utf8(array[index].to_owned()));
|
||||
}
|
||||
ObjectRef::Class(_) => {
|
||||
Class(_) => {
|
||||
panic!("should be array")
|
||||
}
|
||||
ObjectRef::Object(_) => {
|
||||
Object(_) => {
|
||||
panic!("should be array")
|
||||
} //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 Ref(mut objectref) = arrayref {
|
||||
match objectref {
|
||||
ObjectRef::ByteArray(ref mut array) => {
|
||||
ByteArray(ref mut array) => {
|
||||
if let I32(value) = value {
|
||||
// is i32 correct?
|
||||
array[index as usize] = value as i8;
|
||||
|
|
@ -71,7 +71,7 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result
|
|||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::ShortArray(ref mut array) => {
|
||||
ShortArray(ref mut array) => {
|
||||
if let I32(value) = value {
|
||||
// is i32 correct?
|
||||
array[index as usize] = value as i16;
|
||||
|
|
@ -79,63 +79,63 @@ pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result
|
|||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::IntArray(ref mut array) => {
|
||||
IntArray(ref mut array) => {
|
||||
if let I32(value) = value {
|
||||
array[index as usize] = value;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::BooleanArray(ref mut array) => {
|
||||
BooleanArray(ref mut array) => {
|
||||
if let I32(value) = value {
|
||||
array[index as usize] = value > 0;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::CharArray(ref mut array) => unsafe {
|
||||
CharArray(ref mut array) => unsafe {
|
||||
if let I32(value) = value {
|
||||
array[index as usize] = char::from_u32_unchecked(value as u32);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::LongArray(ref mut array) => {
|
||||
LongArray(ref mut array) => {
|
||||
if let I64(value) = value {
|
||||
array[index as usize] = value;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::FloatArray(ref mut array) => {
|
||||
FloatArray(ref mut array) => {
|
||||
if let F32(value) = value {
|
||||
array[index as usize] = value
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::DoubleArray(ref mut array) => {
|
||||
DoubleArray(ref mut array) => {
|
||||
if let F64(value) = value {
|
||||
array[index as usize] = value
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::ObjectArray(_arraytype, ref mut array) => {
|
||||
ObjectArray(_arraytype, ref mut array) => {
|
||||
if let Ref(ref value) = value {
|
||||
array[index as usize] = value.clone();
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::StringArray(ref mut array) => {
|
||||
StringArray(ref mut array) => {
|
||||
if let Utf8(ref value) = value {
|
||||
array[index as usize] = value.clone();
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::Object(_) | ObjectRef::Class(_) => {} //throw error?
|
||||
Object(_) | Class(_) => {} //throw error?
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use anyhow::Error;
|
||||
use anyhow::{anyhow, Error};
|
||||
use log::debug;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::class::{ObjectRef, Value};
|
||||
use crate::class::ObjectRef::Object;
|
||||
use crate::class::Value::Void;
|
||||
use crate::class::Value::{I32, Void};
|
||||
use crate::classmanager;
|
||||
use crate::vm::stack::StackFrame;
|
||||
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);
|
||||
|
||||
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),
|
||||
_ => 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 {
|
||||
"desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false),
|
||||
_ => 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> {
|
||||
match method_name {
|
||||
"platformProperties()[Ljava/lang/String;" => platformProperties(),
|
||||
|
|
|
|||
|
|
@ -195,11 +195,13 @@ pub const _FADD: u8 = 98;
|
|||
// (0x62) Add float
|
||||
pub const _DADD: u8 = 99; // (0x63) add double
|
||||
|
||||
pub const ISUB: u8 = 100;
|
||||
pub const _DSUB: u8 = 103;
|
||||
// (0x67) subtract double
|
||||
pub const _FMUL: u8 = 106;
|
||||
// (0x6a) Multiply float
|
||||
pub const _DMUL: u8 = 107; // (0x6b) Multiply double
|
||||
pub const _DMUL: u8 = 107;
|
||||
// (0x6b) Multiply double
|
||||
pub const IDIV: u8 = 108;
|
||||
pub const _FDIV: u8 = 110;
|
||||
// (0x6e) Divide float
|
||||
|
|
@ -212,7 +214,7 @@ pub const _DREM: u8 = 115;
|
|||
pub const _FNEG: u8 = 118;
|
||||
// (0x76) Negate float
|
||||
pub const _DNEG: u8 = 119; // (0x77) Negate double
|
||||
|
||||
pub const ISHL:u8 = 120;
|
||||
pub const ISHR: u8 = 122;
|
||||
pub const _F2I: u8 = 139;
|
||||
// (0x8b) Convert float to int
|
||||
|
|
@ -399,6 +401,7 @@ pub const OPCODES:Lazy<Vec<&str>> = Lazy::new(|| {
|
|||
opcodes[IADD as usize] = "IADD";
|
||||
opcodes[_FADD as usize] = "_FADD";
|
||||
opcodes[_DADD as usize] = "_DADD";
|
||||
opcodes[ISUB as usize] = "ISUB";
|
||||
opcodes[_DSUB as usize] = "_DSUB";
|
||||
opcodes[_FMUL as usize] = "_FMUL";
|
||||
opcodes[_DMUL as usize] = "_DMUL";
|
||||
|
|
@ -409,6 +412,7 @@ pub const OPCODES:Lazy<Vec<&str>> = Lazy::new(|| {
|
|||
opcodes[_DREM as usize] = "_DREM";
|
||||
opcodes[_FNEG as usize] = "_FNEG";
|
||||
opcodes[_DNEG as usize] = "_DNEG";
|
||||
opcodes[ISHL as usize] = "ISHL";
|
||||
opcodes[ISHR as usize] = "ISHR";
|
||||
opcodes[_F2I as usize] = "_F2I";
|
||||
opcodes[_F2L as usize] = "_F2L";
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use anyhow::Error;
|
||||
use log::debug;
|
||||
|
||||
use crate::class::{Class, Value};
|
||||
use crate::classloader::classdef::CpEntry;
|
||||
use crate::class::{Class, ObjectRef, Value};
|
||||
use crate::class::Value::{I32, Ref};
|
||||
use crate::classloader::classdef::{CpEntry, Method};
|
||||
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
|
||||
|
||||
|
|
@ -66,6 +71,52 @@ pub(crate) fn get_signature_for_invoke(cp: &HashMap<u16, CpEntry>, index: u16) -
|
|||
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 {
|
||||
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::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::classmanager;
|
||||
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::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;
|
||||
|
||||
pub struct Vm {}
|
||||
|
|
@ -27,6 +27,8 @@ const PATH_SEPARATOR: char = ':';
|
|||
#[cfg(target_family = "windows")]
|
||||
const PATH_SEPARATOR: char = ';';
|
||||
|
||||
const MASK_LOWER_5BITS: i32 = 0b00011111;
|
||||
|
||||
/// The singlethreaded VM (maybe a future Thread)
|
||||
//TODO goto
|
||||
//TODO error handling
|
||||
|
|
@ -220,83 +222,15 @@ impl Vm {
|
|||
}
|
||||
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) => {
|
||||
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)
|
||||
}
|
||||
}
|
||||
load_constant(&cp_index, method, stackframes, this_class);
|
||||
}
|
||||
LDC_W => {
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
let cp_entry = method.constant_pool.get(&cp_index).unwrap();
|
||||
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!()
|
||||
}
|
||||
}
|
||||
load_constant(&cp_index, method, stackframes, this_class);
|
||||
}
|
||||
LDC2_W => {
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
match method.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Double(d) => {
|
||||
current_frame(stackframes).push(Value::F64(*d));
|
||||
}
|
||||
CpEntry::Long(l) => {
|
||||
current_frame(stackframes).push(Value::I64(*l));
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
load_constant(&cp_index, method, stackframes, this_class);
|
||||
}
|
||||
ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => {
|
||||
// omitting the type checks so far
|
||||
|
|
@ -362,16 +296,28 @@ impl Vm {
|
|||
debug!("{:?}+{:?}", value1, value2);
|
||||
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 => {
|
||||
let value2 = current_frame(stackframes).pop()?;
|
||||
let value1 = current_frame(stackframes).pop()?;
|
||||
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 => {
|
||||
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)));
|
||||
current_frame(stackframes).push(I32(value1.into_i32() >> (value2.into_i32() & MASK_LOWER_5BITS)));
|
||||
}
|
||||
IFEQ | IFNE | IFLT | IFGE | IFGT | IFLE => {
|
||||
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;
|
||||
stackframes.get_mut(i).unwrap()
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue