finally picked it up again, one bytecode at a time
This commit is contained in:
parent
c271881a79
commit
ccf7426086
9 changed files with 109 additions and 17 deletions
|
|
@ -20,14 +20,21 @@ pub struct Class {
|
||||||
pub initialized: bool,
|
pub initialized: bool,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub superclass: Option<ClassId>,
|
pub superclass: Option<ClassId>,
|
||||||
pub parents: LinkedList<ClassId>,
|
pub all_superclasses: LinkedList<ClassId>, // all superclasses in a flat list
|
||||||
pub interfaces: Vec<ClassId>,
|
pub interfaces: Vec<ClassId>,
|
||||||
|
pub all_interfaces: Vec<ClassId>, // all interfaces and their parents in a flat list
|
||||||
// lookup index and type from the name of the declared class and then field
|
// lookup index and type from the name of the declared class and then field
|
||||||
pub(crate) object_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
pub(crate) object_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
||||||
pub(crate) static_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
pub(crate) static_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
||||||
// pub(crate) static_field_data: Vec<Value> // moved to classmanager
|
// pub(crate) static_field_data: Vec<Value> // moved to classmanager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Class {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id == other.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Class {
|
impl Class {
|
||||||
/// gets the number of non-static fields on the class
|
/// gets the number of non-static fields on the class
|
||||||
pub(crate) fn n_object_fields(&self) -> usize {
|
pub(crate) fn n_object_fields(&self) -> usize {
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ impl ClassDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gets the class name if the index is a class ref index
|
||||||
pub fn cp_class_name(&self, index: &u16) -> &String {
|
pub fn cp_class_name(&self, index: &u16) -> &String {
|
||||||
let cr = self.cp_class_ref(index);
|
let cr = self.cp_class_ref(index);
|
||||||
self.cp_utf8(cr)
|
self.cp_utf8(cr)
|
||||||
|
|
@ -338,7 +339,7 @@ impl Debug for Method {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Method {
|
impl Method {
|
||||||
pub(crate) fn new(
|
pub fn new(
|
||||||
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
||||||
access_flags: u16,
|
access_flags: u16,
|
||||||
name_index: u16,
|
name_index: u16,
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ use log::debug;
|
||||||
use crate::classloader::classdef::{
|
use crate::classloader::classdef::{
|
||||||
AttributeType, ClassDef, CpEntry, Exception, Field, Method, MethodCode,
|
AttributeType, ClassDef, CpEntry, Exception, Field, Method, MethodCode,
|
||||||
};
|
};
|
||||||
use crate::classloader::code_parser::parse_code;
|
|
||||||
use crate::classloader::io::{
|
use crate::classloader::io::{
|
||||||
find_class, read_bytes, read_f32, read_f64, read_i32, read_i64, read_u16, read_u32, read_u8,
|
find_class, read_bytes, read_f32, read_f64, read_i32, read_i64, read_u16, read_u32, read_u8,
|
||||||
};
|
};
|
||||||
|
use crate::classloader::opcode_parser::parse_opcodes;
|
||||||
|
|
||||||
pub mod classdef;
|
pub mod classdef;
|
||||||
mod code_parser;
|
|
||||||
pub(crate) mod io;
|
pub(crate) mod io;
|
||||||
|
mod opcode_parser;
|
||||||
|
|
||||||
pub(crate) fn get_classdef(classpath: &Vec<String>, class_name: &str) -> Result<ClassDef, Error> {
|
pub(crate) fn get_classdef(classpath: &Vec<String>, class_name: &str) -> Result<ClassDef, Error> {
|
||||||
debug!("read class {} ", class_name);
|
debug!("read class {} ", class_name);
|
||||||
|
|
@ -250,7 +250,7 @@ fn read_method(
|
||||||
}
|
}
|
||||||
|
|
||||||
let code = if let Some(AttributeType::Code(code)) = attributes.get("Code") {
|
let code = if let Some(AttributeType::Code(code)) = attributes.get("Code") {
|
||||||
parse_code(&code.opcodes)
|
parse_opcodes(&code.opcodes)
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::classloader::io::{
|
||||||
};
|
};
|
||||||
use crate::vm::opcodes::Opcode::{self, *};
|
use crate::vm::opcodes::Opcode::{self, *};
|
||||||
|
|
||||||
pub(crate) fn parse_code(opcodes: &[u8]) -> Vec<Opcode> {
|
pub(crate) fn parse_opcodes(opcodes: &[u8]) -> Vec<Opcode> {
|
||||||
let mut code: BTreeMap<u16, (u16, Opcode)> = BTreeMap::new();
|
let mut code: BTreeMap<u16, (u16, Opcode)> = BTreeMap::new();
|
||||||
let mut c = 0;
|
let mut c = 0;
|
||||||
let mut opcode_index: u16 = 0;
|
let mut opcode_index: u16 = 0;
|
||||||
|
|
@ -39,7 +39,8 @@ pub(crate) fn parse_code(opcodes: &[u8]) -> Vec<Opcode> {
|
||||||
IFLT(goto) => IFLT(code2.get(&goto).unwrap().0),
|
IFLT(goto) => IFLT(code2.get(&goto).unwrap().0),
|
||||||
IFLE(goto) => IFLE(code2.get(&goto).unwrap().0),
|
IFLE(goto) => IFLE(code2.get(&goto).unwrap().0),
|
||||||
GOTO(goto) => GOTO(code2.get(&goto).unwrap().0),
|
GOTO(goto) => GOTO(code2.get(&goto).unwrap().0),
|
||||||
|
IF_ACMPEQ(goto) => GOTO(code2.get(&goto).unwrap().0),
|
||||||
|
IF_ACMPNE(goto) => GOTO(code2.get(&goto).unwrap().0),
|
||||||
//TODO more jump instructions
|
//TODO more jump instructions
|
||||||
_ => opcode,
|
_ => opcode,
|
||||||
})
|
})
|
||||||
|
|
@ -138,7 +138,7 @@ impl ClassManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_class_by_name(&self, name: &str) -> Option<&Class> {
|
pub fn get_class_by_name(&self, name: &str) -> Option<&Class> {
|
||||||
debug!("{}", name);
|
debug!("get class by name {}", name);
|
||||||
let id = self.names.get(name);
|
let id = self.names.get(name);
|
||||||
self.classes.get(id.unwrap())
|
self.classes.get(id.unwrap())
|
||||||
}
|
}
|
||||||
|
|
@ -199,6 +199,9 @@ impl ClassManager {
|
||||||
.map(|n| *self.names.get(n.as_str()).unwrap())
|
.map(|n| *self.names.get(n.as_str()).unwrap())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let mut all_interfaces = Vec::new();
|
||||||
|
self.get_all_interfaces(&interface_ids, &mut all_interfaces);
|
||||||
|
|
||||||
// initial values for static fields (before static init)
|
// initial values for static fields (before static init)
|
||||||
self.static_class_data
|
self.static_class_data
|
||||||
.insert(this_classid, Self::set_field_data(&static_field_mapping));
|
.insert(this_classid, Self::set_field_data(&static_field_mapping));
|
||||||
|
|
@ -210,8 +213,9 @@ impl ClassManager {
|
||||||
initialized: false,
|
initialized: false,
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
superclass: superclass_id,
|
superclass: superclass_id,
|
||||||
parents,
|
all_superclasses: parents,
|
||||||
interfaces: interface_ids,
|
interfaces: interface_ids,
|
||||||
|
all_interfaces,
|
||||||
object_field_mapping,
|
object_field_mapping,
|
||||||
static_field_mapping,
|
static_field_mapping,
|
||||||
},
|
},
|
||||||
|
|
@ -235,6 +239,16 @@ impl ClassManager {
|
||||||
this_classid
|
this_classid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_all_interfaces(&self, ids: &[ClassId], output: &mut Vec<ClassId>) {
|
||||||
|
for id in ids {
|
||||||
|
output.push(*id);
|
||||||
|
let interfaces = self.classes.get(id).map(|c| c.interfaces.to_vec());
|
||||||
|
if let Some(intf) = interfaces {
|
||||||
|
self.get_all_interfaces(&intf, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// like described above
|
/// like described above
|
||||||
fn add_fields_for_this_or_parents(
|
fn add_fields_for_this_or_parents(
|
||||||
object_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
|
object_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
|
||||||
|
|
@ -460,8 +474,9 @@ mod test {
|
||||||
initialized: false,
|
initialized: false,
|
||||||
name: "".into(),
|
name: "".into(),
|
||||||
superclass: None,
|
superclass: None,
|
||||||
parents: LinkedList::new(),
|
all_superclasses: LinkedList::new(),
|
||||||
interfaces: vec![],
|
interfaces: vec![],
|
||||||
|
all_interfaces: vec![],
|
||||||
object_field_mapping: class_field_mapping,
|
object_field_mapping: class_field_mapping,
|
||||||
static_field_mapping: HashMap::new(),
|
static_field_mapping: HashMap::new(),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -77,10 +77,12 @@ impl Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_object(self) -> ObjectRef {
|
pub fn into_object(self) -> ObjectRef {
|
||||||
if let Value::Ref(v) = self {
|
if let Value::Null = self {
|
||||||
|
ObjectRef::Null
|
||||||
|
} else if let Value::Ref(v) = self {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
panic!();
|
panic!("{:?}", self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use std::cell::RefCell;
|
||||||
use std::fmt::{Debug, Formatter, Pointer};
|
use std::fmt::{Debug, Formatter, Pointer};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct Array<T>
|
pub struct Array<T>
|
||||||
where
|
where
|
||||||
T: Clone,
|
T: Clone,
|
||||||
|
|
@ -58,7 +58,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum ObjectRef {
|
pub enum ObjectRef {
|
||||||
ByteArray(Array<i8>),
|
ByteArray(Array<i8>),
|
||||||
//maybe use arrays?
|
//maybe use arrays?
|
||||||
|
|
@ -176,6 +176,12 @@ pub struct Object {
|
||||||
pub data: Vec<Value>,
|
pub data: Vec<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Object {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id == other.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// object, not array
|
// object, not array
|
||||||
impl Object {
|
impl Object {
|
||||||
pub fn new(class: &Class) -> Self {
|
pub fn new(class: &Class) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use crate::vm::array::{array_load, array_store};
|
||||||
use crate::vm::native::invoke_native;
|
use crate::vm::native::invoke_native;
|
||||||
use crate::vm::object;
|
use crate::vm::object;
|
||||||
use crate::vm::object::ObjectRef;
|
use crate::vm::object::ObjectRef;
|
||||||
use crate::vm::object::ObjectRef::Object;
|
use crate::vm::object::ObjectRef::{Class, Object};
|
||||||
use crate::vm::opcodes::Opcode;
|
use crate::vm::opcodes::Opcode;
|
||||||
use crate::vm::opcodes::Opcode::*;
|
use crate::vm::opcodes::Opcode::*;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
@ -551,7 +551,7 @@ impl Stackframe {
|
||||||
class_manager.load_class_by_name(&name);
|
class_manager.load_class_by_name(&name);
|
||||||
let class = class_manager.get_class_by_name(&name).unwrap();
|
let class = class_manager.get_class_by_name(&name).unwrap();
|
||||||
|
|
||||||
for parent_id in &class.parents {
|
for parent_id in &class.all_superclasses {
|
||||||
let classdef = class_manager.get_classdef(parent_id);
|
let classdef = class_manager.get_classdef(parent_id);
|
||||||
if classdef.has_method(method_name) {
|
if classdef.has_method(method_name) {
|
||||||
invoke_class = Some(*parent_id);
|
invoke_class = Some(*parent_id);
|
||||||
|
|
@ -712,6 +712,8 @@ impl Stackframe {
|
||||||
let object = object.borrow();
|
let object = object.borrow();
|
||||||
let value = object.get(runtime_type, &declared_type, &field_name);
|
let value = object.get(runtime_type, &declared_type, &field_name);
|
||||||
self.push(value.clone());
|
self.push(value.clone());
|
||||||
|
} else if let ObjectRef::Null = instance {
|
||||||
|
self.push(Null);
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
@ -907,8 +909,65 @@ impl Stackframe {
|
||||||
let value1 = self.pop().into_i64();
|
let value1 = self.pop().into_i64();
|
||||||
self.push(I64(value1 ^ value2));
|
self.push(I64(value1 ^ value2));
|
||||||
}
|
}
|
||||||
|
CHECKCAST(_) => { //?
|
||||||
|
}
|
||||||
|
IF_ACMPEQ(jmp_to) => {
|
||||||
|
let value2 = self.pop().into_object();
|
||||||
|
let value1 = self.pop().into_object();
|
||||||
|
if value1 == value2 {
|
||||||
|
self.pc = *jmp_to as usize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IF_ACMPNE(jmp_to) => {
|
||||||
|
let value2 = self.pop().into_object();
|
||||||
|
let value1 = self.pop().into_object();
|
||||||
|
if value1 != value2 {
|
||||||
|
self.pc = *jmp_to as usize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
INSTANCEOF(class_index_tca) => {
|
||||||
|
// check object.getClass against class_tca (to check against)
|
||||||
|
// 1. either class == class_tca
|
||||||
|
// 2. or class.one_of_its_interfaces == class_tca // recursive up until there is no super
|
||||||
|
// 3. or class.superclass = class_tca // recursive up until (excluding) object
|
||||||
|
|
||||||
CHECKCAST(_) => {}
|
let object = self.pop().into_object();
|
||||||
|
let class_name = class_manager
|
||||||
|
.get_classdef(&class_id)
|
||||||
|
.cp_class_name(class_index_tca);
|
||||||
|
let classid_tca = class_manager.get_class_by_name(class_name).map(|c| c.id);
|
||||||
|
if let Some(classid_tca) = classid_tca {
|
||||||
|
if let Object(o) = object {
|
||||||
|
let class_id = &o.borrow().class_id;
|
||||||
|
let mut outcome = 0;
|
||||||
|
if let Some(class_to_check) = class_manager.get_class_by_id(class_id) {
|
||||||
|
// 1.
|
||||||
|
if class_to_check.id == classid_tca {
|
||||||
|
outcome = 1;
|
||||||
|
} else {
|
||||||
|
// 2.
|
||||||
|
for intf_id in &class_to_check.all_interfaces {
|
||||||
|
if *intf_id == classid_tca {
|
||||||
|
outcome = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 3.
|
||||||
|
for super_id in &class_to_check.all_superclasses {
|
||||||
|
if *super_id == classid_tca {
|
||||||
|
outcome = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug!("{}", outcome);
|
||||||
|
self.push(I32(outcome));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.push(I32(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("opcode not implemented")
|
panic!("opcode not implemented")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ mod test {
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
|
vec![],
|
||||||
);
|
);
|
||||||
assert!(m.is(Modifier::Public));
|
assert!(m.is(Modifier::Public));
|
||||||
assert!(m.is(Modifier::Static));
|
assert!(m.is(Modifier::Static));
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue