some new opcodes

This commit is contained in:
Shautvast 2023-11-11 12:22:52 +01:00
parent 66983b0783
commit 40a7c6cd1e
8 changed files with 354 additions and 286 deletions

View file

@ -21,3 +21,4 @@ actually:
**Ultimate goal**
* Hello world domination
``

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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