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 name: String,
|
||||
pub superclass: Option<ClassId>,
|
||||
pub parents: LinkedList<ClassId>,
|
||||
pub all_superclasses: LinkedList<ClassId>, // all superclasses in a flat list
|
||||
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
|
||||
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> // moved to classmanager
|
||||
}
|
||||
|
||||
impl PartialEq for Class {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Class {
|
||||
/// gets the number of non-static fields on the class
|
||||
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 {
|
||||
let cr = self.cp_class_ref(index);
|
||||
self.cp_utf8(cr)
|
||||
|
|
@ -338,7 +339,7 @@ impl Debug for Method {
|
|||
}
|
||||
|
||||
impl Method {
|
||||
pub(crate) fn new(
|
||||
pub fn new(
|
||||
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
||||
access_flags: u16,
|
||||
name_index: u16,
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ use log::debug;
|
|||
use crate::classloader::classdef::{
|
||||
AttributeType, ClassDef, CpEntry, Exception, Field, Method, MethodCode,
|
||||
};
|
||||
use crate::classloader::code_parser::parse_code;
|
||||
use crate::classloader::io::{
|
||||
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;
|
||||
mod code_parser;
|
||||
pub(crate) mod io;
|
||||
mod opcode_parser;
|
||||
|
||||
pub(crate) fn get_classdef(classpath: &Vec<String>, class_name: &str) -> Result<ClassDef, Error> {
|
||||
debug!("read class {} ", class_name);
|
||||
|
|
@ -250,7 +250,7 @@ fn read_method(
|
|||
}
|
||||
|
||||
let code = if let Some(AttributeType::Code(code)) = attributes.get("Code") {
|
||||
parse_code(&code.opcodes)
|
||||
parse_opcodes(&code.opcodes)
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::classloader::io::{
|
|||
};
|
||||
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 c = 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),
|
||||
IFLE(goto) => IFLE(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
|
||||
_ => opcode,
|
||||
})
|
||||
|
|
@ -138,7 +138,7 @@ impl ClassManager {
|
|||
}
|
||||
|
||||
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);
|
||||
self.classes.get(id.unwrap())
|
||||
}
|
||||
|
|
@ -199,6 +199,9 @@ impl ClassManager {
|
|||
.map(|n| *self.names.get(n.as_str()).unwrap())
|
||||
.collect();
|
||||
|
||||
let mut all_interfaces = Vec::new();
|
||||
self.get_all_interfaces(&interface_ids, &mut all_interfaces);
|
||||
|
||||
// initial values for static fields (before static init)
|
||||
self.static_class_data
|
||||
.insert(this_classid, Self::set_field_data(&static_field_mapping));
|
||||
|
|
@ -210,8 +213,9 @@ impl ClassManager {
|
|||
initialized: false,
|
||||
name: name.into(),
|
||||
superclass: superclass_id,
|
||||
parents,
|
||||
all_superclasses: parents,
|
||||
interfaces: interface_ids,
|
||||
all_interfaces,
|
||||
object_field_mapping,
|
||||
static_field_mapping,
|
||||
},
|
||||
|
|
@ -235,6 +239,16 @@ impl ClassManager {
|
|||
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
|
||||
fn add_fields_for_this_or_parents(
|
||||
object_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
|
||||
|
|
@ -460,8 +474,9 @@ mod test {
|
|||
initialized: false,
|
||||
name: "".into(),
|
||||
superclass: None,
|
||||
parents: LinkedList::new(),
|
||||
all_superclasses: LinkedList::new(),
|
||||
interfaces: vec![],
|
||||
all_interfaces: vec![],
|
||||
object_field_mapping: class_field_mapping,
|
||||
static_field_mapping: HashMap::new(),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -77,10 +77,12 @@ impl Value {
|
|||
}
|
||||
|
||||
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
|
||||
} else {
|
||||
panic!();
|
||||
panic!("{:?}", self);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::cell::RefCell;
|
|||
use std::fmt::{Debug, Formatter, Pointer};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Array<T>
|
||||
where
|
||||
T: Clone,
|
||||
|
|
@ -58,7 +58,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum ObjectRef {
|
||||
ByteArray(Array<i8>),
|
||||
//maybe use arrays?
|
||||
|
|
@ -176,6 +176,12 @@ pub struct Object {
|
|||
pub data: Vec<Value>,
|
||||
}
|
||||
|
||||
impl PartialEq for Object {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
// object, not array
|
||||
impl Object {
|
||||
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::object;
|
||||
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 std::io::Write;
|
||||
|
|
@ -551,7 +551,7 @@ impl Stackframe {
|
|||
class_manager.load_class_by_name(&name);
|
||||
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);
|
||||
if classdef.has_method(method_name) {
|
||||
invoke_class = Some(*parent_id);
|
||||
|
|
@ -712,6 +712,8 @@ impl Stackframe {
|
|||
let object = object.borrow();
|
||||
let value = object.get(runtime_type, &declared_type, &field_name);
|
||||
self.push(value.clone());
|
||||
} else if let ObjectRef::Null = instance {
|
||||
self.push(Null);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
|
@ -907,8 +909,65 @@ impl Stackframe {
|
|||
let value1 = self.pop().into_i64();
|
||||
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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ mod test {
|
|||
0,
|
||||
0,
|
||||
HashMap::new(),
|
||||
vec![],
|
||||
);
|
||||
assert!(m.is(Modifier::Public));
|
||||
assert!(m.is(Modifier::Static));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue