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);
|
||||
match id {
|
||||
Some(id) => if self.classes.get(id).is_none() {
|
||||
self.add_class(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;
|
||||
}
|
||||
None => {
|
||||
self.add_class(name);
|
||||
}
|
||||
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(&type_name);
|
||||
}
|
||||
None => {
|
||||
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(),
|
||||
|
|
|
|||
|
|
@ -190,17 +190,19 @@ pub const _DUP2_X1: u8 = 93;
|
|||
//(0x5d) Duplicate the top one or two operand stack values and insert two or three values down
|
||||
pub const _DUP2_X2: u8 = 94; // (0x5e) Duplicate the top one or two operand stack values and insert two, three, or four values down
|
||||
|
||||
pub const IADD:u8 = 96;
|
||||
pub const IADD: u8 = 96;
|
||||
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 IDIV:u8 = 108;
|
||||
pub const _DMUL: u8 = 107;
|
||||
// (0x6b) Multiply double
|
||||
pub const IDIV: u8 = 108;
|
||||
pub const _FDIV: u8 = 110;
|
||||
// (0x6e) Divide float
|
||||
pub const _DDIV: u8 = 111;
|
||||
|
|
@ -212,8 +214,8 @@ pub const _DREM: u8 = 115;
|
|||
pub const _FNEG: u8 = 118;
|
||||
// (0x76) Negate float
|
||||
pub const _DNEG: u8 = 119; // (0x77) Negate double
|
||||
|
||||
pub const ISHR:u8 = 122;
|
||||
pub const ISHL:u8 = 120;
|
||||
pub const ISHR: u8 = 122;
|
||||
pub const _F2I: u8 = 139;
|
||||
// (0x8b) Convert float to int
|
||||
pub const _F2L: u8 = 140;
|
||||
|
|
@ -286,7 +288,7 @@ pub const INVOKESTATIC: u8 = 184;
|
|||
// (0xb8) Invoke a class (static) method
|
||||
pub const NEW: u8 = 187;
|
||||
// (0xbb) Create new object
|
||||
pub const NEWARRAY:u8 = 188;
|
||||
pub const NEWARRAY: u8 = 188;
|
||||
pub const ANEWARRAY: u8 = 189;
|
||||
// (0xbd)
|
||||
pub const ARRAYLENGTH: u8 = 190;
|
||||
|
|
@ -300,160 +302,162 @@ pub const MONITOREXIT: u8 = 195;
|
|||
pub const IFNULL: u8 = 198;
|
||||
pub const IFNONNULL: u8 = 199;
|
||||
|
||||
pub const OPCODES:Lazy<Vec<&str>> = Lazy::new(|| {
|
||||
let mut opcodes = vec!["";256];
|
||||
opcodes[NOP as usize] = "NOP" ;
|
||||
opcodes[ACONST_NULL as usize] = "ACONST_NULL" ;
|
||||
opcodes[ICONST_M1 as usize] = "ICONST_M1" ;
|
||||
opcodes[ICONST_0 as usize] = "ICONST_0" ;
|
||||
opcodes[ICONST_1 as usize] = "ICONST_1" ;
|
||||
opcodes[ICONST_2 as usize] = "ICONST_2" ;
|
||||
opcodes[ICONST_3 as usize] = "ICONST_3" ;
|
||||
opcodes[ICONST_4 as usize] = "ICONST_4" ;
|
||||
opcodes[ICONST_5 as usize] = "ICONST_5" ;
|
||||
opcodes[LCONST_0 as usize] = "LCONST_0" ;
|
||||
opcodes[LCONST_1 as usize] = "LCONST_1" ;
|
||||
opcodes[FCONST_0 as usize] = "FCONST_0" ;
|
||||
opcodes[FCONST_1 as usize] = "FCONST_1" ;
|
||||
opcodes[FCONST_2 as usize] = "FCONST_2" ;
|
||||
opcodes[DCONST_0 as usize] = "DCONST_0" ;
|
||||
opcodes[DCONST_1 as usize] = "DCONST_1" ;
|
||||
opcodes[BIPUSH as usize] = "BIPUSH" ;
|
||||
opcodes[SIPUSH as usize] = "SIPUSH" ;
|
||||
opcodes[LDC as usize] = "LDC" ;
|
||||
opcodes[LDC_W as usize] = "LDC_W" ;
|
||||
opcodes[LDC2_W as usize] = "LDC2_W" ;
|
||||
opcodes[ILOAD as usize] = "ILOAD" ;
|
||||
opcodes[LLOAD as usize] = "LLOAD" ;
|
||||
opcodes[FLOAD as usize] = "FLOAD" ;
|
||||
opcodes[DLOAD as usize] = "DLOAD" ;
|
||||
opcodes[ALOAD as usize] = "ALOAD" ;
|
||||
opcodes[ILOAD_0 as usize] = "ILOAD_0" ;
|
||||
opcodes[ILOAD_1 as usize] = "ILOAD_1" ;
|
||||
opcodes[ILOAD_2 as usize] = "ILOAD_2" ;
|
||||
opcodes[ILOAD_3 as usize] = "ILOAD_3" ;
|
||||
opcodes[LLOAD_0 as usize] = "LLOAD_0" ;
|
||||
opcodes[LLOAD_1 as usize] = "LLOAD_1" ;
|
||||
opcodes[LLOAD_2 as usize] = "LLOAD_2" ;
|
||||
opcodes[LLOAD_3 as usize] = "LLOAD_3" ;
|
||||
opcodes[FLOAD_0 as usize] = "FLOAD_0" ;
|
||||
opcodes[FLOAD_1 as usize] = "FLOAD_1" ;
|
||||
opcodes[FLOAD_2 as usize] = "FLOAD_2" ;
|
||||
opcodes[FLOAD_3 as usize] = "FLOAD_3" ;
|
||||
opcodes[DLOAD_0 as usize] = "DLOAD_0" ;
|
||||
opcodes[DLOAD_1 as usize] = "DLOAD_1" ;
|
||||
opcodes[DLOAD_2 as usize] = "DLOAD_2" ;
|
||||
opcodes[DLOAD_3 as usize] = "DLOAD_3" ;
|
||||
opcodes[ALOAD_0 as usize] = "ALOAD_0" ;
|
||||
opcodes[ALOAD_1 as usize] = "ALOAD_1" ;
|
||||
opcodes[ALOAD_2 as usize] = "ALOAD_2" ;
|
||||
opcodes[ALOAD_3 as usize] = "ALOAD_3" ;
|
||||
opcodes[IALOAD as usize] = "IALOAD" ;
|
||||
opcodes[LALOAD as usize] = "LALOAD" ;
|
||||
opcodes[FALOAD as usize] = "FALOAD" ;
|
||||
opcodes[DALOAD as usize] = "DALOAD" ;
|
||||
opcodes[AALOAD as usize] = "AALOAD" ;
|
||||
opcodes[BALOAD as usize] = "BALOAD" ;
|
||||
opcodes[CALOAD as usize] = "CALOAD" ;
|
||||
opcodes[SALOAD as usize] = "SALOAD" ;
|
||||
opcodes[ISTORE as usize] = "ISTORE" ;
|
||||
opcodes[LSTORE as usize] = "LSTORE" ;
|
||||
opcodes[FSTORE as usize] = "FSTORE" ;
|
||||
opcodes[DSTORE as usize] = "DSTORE" ;
|
||||
opcodes[ASTORE as usize] = "ASTORE" ;
|
||||
opcodes[ISTORE_0 as usize] = "ISTORE_0" ;
|
||||
opcodes[ISTORE_1 as usize] = "ISTORE_1" ;
|
||||
opcodes[ISTORE_2 as usize] = "ISTORE_2" ;
|
||||
opcodes[ISTORE_3 as usize] = "ISTORE_3" ;
|
||||
opcodes[LSTORE_0 as usize] = "LSTORE_0" ;
|
||||
opcodes[LSTORE_1 as usize] = "LSTORE_1" ;
|
||||
opcodes[LSTORE_2 as usize] = "LSTORE_2" ;
|
||||
opcodes[LSTORE_3 as usize] = "LSTORE_3" ;
|
||||
opcodes[FSTORE_0 as usize] = "FSTORE_0" ;
|
||||
opcodes[FSTORE_1 as usize] = "FSTORE_1" ;
|
||||
opcodes[FSTORE_2 as usize] = "FSTORE_2" ;
|
||||
opcodes[FSTORE_3 as usize] = "FSTORE_3" ;
|
||||
opcodes[DSTORE_0 as usize] = "DSTORE_0" ;
|
||||
opcodes[DSTORE_1 as usize] = "DSTORE_1" ;
|
||||
opcodes[DSTORE_2 as usize] = "DSTORE_2" ;
|
||||
opcodes[DSTORE_3 as usize] = "DSTORE_3" ;
|
||||
opcodes[ASTORE_0 as usize] = "ASTORE_0" ;
|
||||
opcodes[ASTORE_1 as usize] = "ASTORE_1" ;
|
||||
opcodes[ASTORE_2 as usize] = "ASTORE_2" ;
|
||||
opcodes[ASTORE_3 as usize] = "ASTORE_3" ;
|
||||
opcodes[IASTORE as usize] = "IASTORE" ;
|
||||
opcodes[LASTORE as usize] = "LASTORE" ;
|
||||
opcodes[FASTORE as usize] = "FASTORE" ;
|
||||
opcodes[DASTORE as usize] = "DASTORE" ;
|
||||
opcodes[AASTORE as usize] = "AASTORE" ;
|
||||
opcodes[BASTORE as usize] = "BASTORE" ;
|
||||
opcodes[CASTORE as usize] = "CASTORE" ;
|
||||
opcodes[SASTORE as usize] = "SASTORE" ;
|
||||
opcodes[POP as usize] = "POP" ;
|
||||
opcodes[DUP as usize] = "DUP" ;
|
||||
opcodes[_DUP_X1 as usize] = "_DUP_X1" ;
|
||||
opcodes[_DUP_X2 as usize] = "_DUP_X2" ;
|
||||
opcodes[_DUP2 as usize] = "_DUP2" ;
|
||||
opcodes[_DUP2_X1 as usize] = "_DUP2_X1" ;
|
||||
opcodes[_DUP2_X2 as usize] = "_DUP2_X2" ;
|
||||
pub const OPCODES: Lazy<Vec<&str>> = Lazy::new(|| {
|
||||
let mut opcodes = vec![""; 256];
|
||||
opcodes[NOP as usize] = "NOP";
|
||||
opcodes[ACONST_NULL as usize] = "ACONST_NULL";
|
||||
opcodes[ICONST_M1 as usize] = "ICONST_M1";
|
||||
opcodes[ICONST_0 as usize] = "ICONST_0";
|
||||
opcodes[ICONST_1 as usize] = "ICONST_1";
|
||||
opcodes[ICONST_2 as usize] = "ICONST_2";
|
||||
opcodes[ICONST_3 as usize] = "ICONST_3";
|
||||
opcodes[ICONST_4 as usize] = "ICONST_4";
|
||||
opcodes[ICONST_5 as usize] = "ICONST_5";
|
||||
opcodes[LCONST_0 as usize] = "LCONST_0";
|
||||
opcodes[LCONST_1 as usize] = "LCONST_1";
|
||||
opcodes[FCONST_0 as usize] = "FCONST_0";
|
||||
opcodes[FCONST_1 as usize] = "FCONST_1";
|
||||
opcodes[FCONST_2 as usize] = "FCONST_2";
|
||||
opcodes[DCONST_0 as usize] = "DCONST_0";
|
||||
opcodes[DCONST_1 as usize] = "DCONST_1";
|
||||
opcodes[BIPUSH as usize] = "BIPUSH";
|
||||
opcodes[SIPUSH as usize] = "SIPUSH";
|
||||
opcodes[LDC as usize] = "LDC";
|
||||
opcodes[LDC_W as usize] = "LDC_W";
|
||||
opcodes[LDC2_W as usize] = "LDC2_W";
|
||||
opcodes[ILOAD as usize] = "ILOAD";
|
||||
opcodes[LLOAD as usize] = "LLOAD";
|
||||
opcodes[FLOAD as usize] = "FLOAD";
|
||||
opcodes[DLOAD as usize] = "DLOAD";
|
||||
opcodes[ALOAD as usize] = "ALOAD";
|
||||
opcodes[ILOAD_0 as usize] = "ILOAD_0";
|
||||
opcodes[ILOAD_1 as usize] = "ILOAD_1";
|
||||
opcodes[ILOAD_2 as usize] = "ILOAD_2";
|
||||
opcodes[ILOAD_3 as usize] = "ILOAD_3";
|
||||
opcodes[LLOAD_0 as usize] = "LLOAD_0";
|
||||
opcodes[LLOAD_1 as usize] = "LLOAD_1";
|
||||
opcodes[LLOAD_2 as usize] = "LLOAD_2";
|
||||
opcodes[LLOAD_3 as usize] = "LLOAD_3";
|
||||
opcodes[FLOAD_0 as usize] = "FLOAD_0";
|
||||
opcodes[FLOAD_1 as usize] = "FLOAD_1";
|
||||
opcodes[FLOAD_2 as usize] = "FLOAD_2";
|
||||
opcodes[FLOAD_3 as usize] = "FLOAD_3";
|
||||
opcodes[DLOAD_0 as usize] = "DLOAD_0";
|
||||
opcodes[DLOAD_1 as usize] = "DLOAD_1";
|
||||
opcodes[DLOAD_2 as usize] = "DLOAD_2";
|
||||
opcodes[DLOAD_3 as usize] = "DLOAD_3";
|
||||
opcodes[ALOAD_0 as usize] = "ALOAD_0";
|
||||
opcodes[ALOAD_1 as usize] = "ALOAD_1";
|
||||
opcodes[ALOAD_2 as usize] = "ALOAD_2";
|
||||
opcodes[ALOAD_3 as usize] = "ALOAD_3";
|
||||
opcodes[IALOAD as usize] = "IALOAD";
|
||||
opcodes[LALOAD as usize] = "LALOAD";
|
||||
opcodes[FALOAD as usize] = "FALOAD";
|
||||
opcodes[DALOAD as usize] = "DALOAD";
|
||||
opcodes[AALOAD as usize] = "AALOAD";
|
||||
opcodes[BALOAD as usize] = "BALOAD";
|
||||
opcodes[CALOAD as usize] = "CALOAD";
|
||||
opcodes[SALOAD as usize] = "SALOAD";
|
||||
opcodes[ISTORE as usize] = "ISTORE";
|
||||
opcodes[LSTORE as usize] = "LSTORE";
|
||||
opcodes[FSTORE as usize] = "FSTORE";
|
||||
opcodes[DSTORE as usize] = "DSTORE";
|
||||
opcodes[ASTORE as usize] = "ASTORE";
|
||||
opcodes[ISTORE_0 as usize] = "ISTORE_0";
|
||||
opcodes[ISTORE_1 as usize] = "ISTORE_1";
|
||||
opcodes[ISTORE_2 as usize] = "ISTORE_2";
|
||||
opcodes[ISTORE_3 as usize] = "ISTORE_3";
|
||||
opcodes[LSTORE_0 as usize] = "LSTORE_0";
|
||||
opcodes[LSTORE_1 as usize] = "LSTORE_1";
|
||||
opcodes[LSTORE_2 as usize] = "LSTORE_2";
|
||||
opcodes[LSTORE_3 as usize] = "LSTORE_3";
|
||||
opcodes[FSTORE_0 as usize] = "FSTORE_0";
|
||||
opcodes[FSTORE_1 as usize] = "FSTORE_1";
|
||||
opcodes[FSTORE_2 as usize] = "FSTORE_2";
|
||||
opcodes[FSTORE_3 as usize] = "FSTORE_3";
|
||||
opcodes[DSTORE_0 as usize] = "DSTORE_0";
|
||||
opcodes[DSTORE_1 as usize] = "DSTORE_1";
|
||||
opcodes[DSTORE_2 as usize] = "DSTORE_2";
|
||||
opcodes[DSTORE_3 as usize] = "DSTORE_3";
|
||||
opcodes[ASTORE_0 as usize] = "ASTORE_0";
|
||||
opcodes[ASTORE_1 as usize] = "ASTORE_1";
|
||||
opcodes[ASTORE_2 as usize] = "ASTORE_2";
|
||||
opcodes[ASTORE_3 as usize] = "ASTORE_3";
|
||||
opcodes[IASTORE as usize] = "IASTORE";
|
||||
opcodes[LASTORE as usize] = "LASTORE";
|
||||
opcodes[FASTORE as usize] = "FASTORE";
|
||||
opcodes[DASTORE as usize] = "DASTORE";
|
||||
opcodes[AASTORE as usize] = "AASTORE";
|
||||
opcodes[BASTORE as usize] = "BASTORE";
|
||||
opcodes[CASTORE as usize] = "CASTORE";
|
||||
opcodes[SASTORE as usize] = "SASTORE";
|
||||
opcodes[POP as usize] = "POP";
|
||||
opcodes[DUP as usize] = "DUP";
|
||||
opcodes[_DUP_X1 as usize] = "_DUP_X1";
|
||||
opcodes[_DUP_X2 as usize] = "_DUP_X2";
|
||||
opcodes[_DUP2 as usize] = "_DUP2";
|
||||
opcodes[_DUP2_X1 as usize] = "_DUP2_X1";
|
||||
opcodes[_DUP2_X2 as usize] = "_DUP2_X2";
|
||||
opcodes[IADD as usize] = "IADD";
|
||||
opcodes[_FADD as usize] = "_FADD" ;
|
||||
opcodes[_DADD as usize] = "_DADD" ;
|
||||
opcodes[_DSUB as usize] = "_DSUB" ;
|
||||
opcodes[_FMUL as usize] = "_FMUL" ;
|
||||
opcodes[_DMUL as usize] = "_DMUL" ;
|
||||
opcodes[IDIV as usize] = "IDIV" ;
|
||||
opcodes[_FDIV as usize] = "_FDIV" ;
|
||||
opcodes[_DDIV as usize] = "_DDIV" ;
|
||||
opcodes[_FREM as usize] = "_FREM" ;
|
||||
opcodes[_DREM as usize] = "_DREM" ;
|
||||
opcodes[_FNEG as usize] = "_FNEG" ;
|
||||
opcodes[_DNEG as usize] = "_DNEG" ;
|
||||
opcodes[ISHR as usize] = "ISHR" ;
|
||||
opcodes[_F2I as usize] = "_F2I" ;
|
||||
opcodes[_F2L as usize] = "_F2L" ;
|
||||
opcodes[_F2D as usize] = "_F2D" ;
|
||||
opcodes[_D2I as usize] = "_D2I" ;
|
||||
opcodes[_D2L as usize] = "_D2L" ;
|
||||
opcodes[_D2F as usize] = "_D2F" ;
|
||||
opcodes[_FCMPL as usize] = "_FCMPL" ;
|
||||
opcodes[_FCMPG as usize] = "_FCMPG" ;
|
||||
opcodes[_DCMPL as usize] = "_DCMPL" ;
|
||||
opcodes[_DCMPG as usize] = "_DCMPG" ;
|
||||
opcodes[IFEQ as usize] = "IFEQ" ;
|
||||
opcodes[IFNE as usize] = "IFNE" ;
|
||||
opcodes[IFLT as usize] = "IFLT" ;
|
||||
opcodes[IFGE as usize] = "IFGE" ;
|
||||
opcodes[IFGT as usize] = "IFGT" ;
|
||||
opcodes[IFLE as usize] = "IFLE" ;
|
||||
opcodes[IF_ICMPEQ as usize] = "IF_ICMPEQ" ;
|
||||
opcodes[IF_ICMPNE as usize] = "IF_ICMPNE" ;
|
||||
opcodes[IF_ICMPLT as usize] = "IF_ICMPLT" ;
|
||||
opcodes[IF_ICMPGE as usize] = "IF_ICMPGE" ;
|
||||
opcodes[IF_ICMPGT as usize] = "IF_ICMPGT" ;
|
||||
opcodes[IF_ICMPLE as usize] = "IF_ICMPLE" ;
|
||||
opcodes[GOTO as usize] = "GOTO" ;
|
||||
opcodes[IRETURN as usize] = "IRETURN" ;
|
||||
opcodes[FRETURN as usize] = "FRETURN" ;
|
||||
opcodes[DRETURN as usize] = "DRETURN" ;
|
||||
opcodes[ARETURN as usize] = "ARETURN" ;
|
||||
opcodes[RETURN_VOID as usize] = "RETURN_VOID" ;
|
||||
opcodes[GETSTATIC as usize] = "GETSTATIC" ;
|
||||
opcodes[PUTSTATIC as usize] = "PUTSTATIC" ;
|
||||
opcodes[GETFIELD as usize] = "GETFIELD" ;
|
||||
opcodes[PUTFIELD as usize] = "PUTFIELD" ;
|
||||
opcodes[INVOKEVIRTUAL as usize] = "INVOKEVIRTUAL" ;
|
||||
opcodes[INVOKESPECIAL as usize] = "INVOKESPECIAL" ;
|
||||
opcodes[INVOKESTATIC as usize] = "INVOKESTATIC" ;
|
||||
opcodes[NEW as usize] = "NEW" ;
|
||||
opcodes[NEWARRAY as usize] = "NEWARRAY" ;
|
||||
opcodes[ANEWARRAY as usize] = "ANEWARRAY" ;
|
||||
opcodes[ARRAYLENGTH as usize] = "ARRAYLENGTH" ;
|
||||
opcodes[_ATHROW as usize] = "_ATHROW" ;
|
||||
opcodes[_CHECKCAST as usize] = "_CHECKCAST" ;
|
||||
opcodes[MONITORENTER as usize] = "MONITORENTER" ;
|
||||
opcodes[MONITOREXIT as usize] = "MONITOREXIT" ;
|
||||
opcodes[IFNULL as usize] = "IFNULL" ;
|
||||
opcodes[IFNONNULL as usize] = "IFNONNULL" ;
|
||||
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";
|
||||
opcodes[IDIV as usize] = "IDIV";
|
||||
opcodes[_FDIV as usize] = "_FDIV";
|
||||
opcodes[_DDIV as usize] = "_DDIV";
|
||||
opcodes[_FREM as usize] = "_FREM";
|
||||
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";
|
||||
opcodes[_F2D as usize] = "_F2D";
|
||||
opcodes[_D2I as usize] = "_D2I";
|
||||
opcodes[_D2L as usize] = "_D2L";
|
||||
opcodes[_D2F as usize] = "_D2F";
|
||||
opcodes[_FCMPL as usize] = "_FCMPL";
|
||||
opcodes[_FCMPG as usize] = "_FCMPG";
|
||||
opcodes[_DCMPL as usize] = "_DCMPL";
|
||||
opcodes[_DCMPG as usize] = "_DCMPG";
|
||||
opcodes[IFEQ as usize] = "IFEQ";
|
||||
opcodes[IFNE as usize] = "IFNE";
|
||||
opcodes[IFLT as usize] = "IFLT";
|
||||
opcodes[IFGE as usize] = "IFGE";
|
||||
opcodes[IFGT as usize] = "IFGT";
|
||||
opcodes[IFLE as usize] = "IFLE";
|
||||
opcodes[IF_ICMPEQ as usize] = "IF_ICMPEQ";
|
||||
opcodes[IF_ICMPNE as usize] = "IF_ICMPNE";
|
||||
opcodes[IF_ICMPLT as usize] = "IF_ICMPLT";
|
||||
opcodes[IF_ICMPGE as usize] = "IF_ICMPGE";
|
||||
opcodes[IF_ICMPGT as usize] = "IF_ICMPGT";
|
||||
opcodes[IF_ICMPLE as usize] = "IF_ICMPLE";
|
||||
opcodes[GOTO as usize] = "GOTO";
|
||||
opcodes[IRETURN as usize] = "IRETURN";
|
||||
opcodes[FRETURN as usize] = "FRETURN";
|
||||
opcodes[DRETURN as usize] = "DRETURN";
|
||||
opcodes[ARETURN as usize] = "ARETURN";
|
||||
opcodes[RETURN_VOID as usize] = "RETURN_VOID";
|
||||
opcodes[GETSTATIC as usize] = "GETSTATIC";
|
||||
opcodes[PUTSTATIC as usize] = "PUTSTATIC";
|
||||
opcodes[GETFIELD as usize] = "GETFIELD";
|
||||
opcodes[PUTFIELD as usize] = "PUTFIELD";
|
||||
opcodes[INVOKEVIRTUAL as usize] = "INVOKEVIRTUAL";
|
||||
opcodes[INVOKESPECIAL as usize] = "INVOKESPECIAL";
|
||||
opcodes[INVOKESTATIC as usize] = "INVOKESTATIC";
|
||||
opcodes[NEW as usize] = "NEW";
|
||||
opcodes[NEWARRAY as usize] = "NEWARRAY";
|
||||
opcodes[ANEWARRAY as usize] = "ANEWARRAY";
|
||||
opcodes[ARRAYLENGTH as usize] = "ARRAYLENGTH";
|
||||
opcodes[_ATHROW as usize] = "_ATHROW";
|
||||
opcodes[_CHECKCAST as usize] = "_CHECKCAST";
|
||||
opcodes[MONITORENTER as usize] = "MONITORENTER";
|
||||
opcodes[MONITOREXIT as usize] = "MONITOREXIT";
|
||||
opcodes[IFNULL as usize] = "IFNULL";
|
||||
opcodes[IFNONNULL as usize] = "IFNONNULL";
|
||||
opcodes
|
||||
});
|
||||
|
|
@ -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