WIP create instance on heap
This commit is contained in:
parent
089ba025ea
commit
8dd60c0866
8 changed files with 212 additions and 107 deletions
|
|
@ -2,8 +2,9 @@ use std::collections::HashMap;
|
|||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{CpEntry, opcodes};
|
||||
use crate::io::{read_u8, read_u16};
|
||||
use crate::CpEntry;
|
||||
use crate::heap::Object;
|
||||
use crate::io::read_u16;
|
||||
|
||||
#[derive(Debug)]
|
||||
//TODO create factory function
|
||||
|
|
@ -25,18 +26,20 @@ impl Class {
|
|||
(self.major_version, self.minor_version)
|
||||
}
|
||||
|
||||
pub fn execute(&self, method_name: &str) -> Value {
|
||||
let m = self.methods.get(method_name).unwrap();
|
||||
m.execute().unwrap() //TODO remove unwrap
|
||||
}
|
||||
// pub fn execute(&self, method_name: &str) -> Value {
|
||||
// let m = self.methods.get(method_name).unwrap();
|
||||
// execute(m).unwrap() //TODO
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
pub struct Method {
|
||||
constant_pool: Rc<HashMap<usize, CpEntry>>,
|
||||
pub(crate) constant_pool: Rc<HashMap<usize, CpEntry>>,
|
||||
access_flags: u16,
|
||||
name_index: usize,
|
||||
descriptor_index: usize,
|
||||
attributes: HashMap<String, AttributeType>,
|
||||
pub(crate) attributes: HashMap<String, AttributeType>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Method {
|
||||
|
|
@ -67,78 +70,6 @@ impl Method {
|
|||
|
||||
full_name
|
||||
}
|
||||
|
||||
pub fn execute(&self) -> Option<Value> {
|
||||
if let AttributeType::Code(code) = self.attributes.get("Code").unwrap() {
|
||||
let mut stack = Stack::new();
|
||||
let mut pc: usize = 0;
|
||||
while pc < code.opcodes.len() {
|
||||
let opcode = &code.opcodes[pc];
|
||||
pc += 1;
|
||||
// println!("{}", opcode);
|
||||
match opcode {
|
||||
&opcodes::BIPUSH => {
|
||||
let c = code.opcodes[pc] as i32;
|
||||
stack.push(Value::I32(c));
|
||||
pc += 1;
|
||||
}
|
||||
&opcodes::LDC => {
|
||||
let cp_index = read_u8(&code.opcodes, pc) as usize;
|
||||
match self.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Integer(i) => {
|
||||
stack.push(Value::I32(*i));
|
||||
}
|
||||
CpEntry::Float(f) => {
|
||||
stack.push(Value::F32(*f));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
pc += 1;
|
||||
}
|
||||
&opcodes::LDC_W => {
|
||||
let cp_index = read_u16(&code.opcodes, pc) as usize;
|
||||
match self.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Integer(i) => {
|
||||
stack.push(Value::I32(*i));
|
||||
}
|
||||
CpEntry::Float(f) => {
|
||||
stack.push(Value::F32(*f));
|
||||
}
|
||||
_ => { panic!("unexpected") }
|
||||
}
|
||||
pc += 2;
|
||||
}
|
||||
&opcodes::LDC2_W => {
|
||||
let cp_index = read_u16(&code.opcodes, pc) as usize;
|
||||
match self.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Double(d) => {
|
||||
stack.push(Value::F64(*d));
|
||||
}
|
||||
CpEntry::Long(l) => {
|
||||
stack.push(Value::I64(*l));
|
||||
}
|
||||
_ => { panic!("unexpected") }
|
||||
}
|
||||
|
||||
|
||||
pc += 2;
|
||||
}
|
||||
&opcodes::IRETURN => {
|
||||
return stack.pop();
|
||||
}
|
||||
&opcodes::DRETURN => {
|
||||
return stack.pop();
|
||||
}
|
||||
&opcodes::FRETURN => {
|
||||
return stack.pop();
|
||||
}
|
||||
//TODO implement all opcodes
|
||||
_ => { panic!("opcode not implemented") }
|
||||
}
|
||||
}
|
||||
}
|
||||
None // TODO error situation
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Field {
|
||||
|
|
@ -178,6 +109,13 @@ impl Field {
|
|||
|
||||
full_name
|
||||
}
|
||||
|
||||
pub fn type_of(&self) -> &String {
|
||||
if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.descriptor_index).unwrap() {
|
||||
return s;
|
||||
}
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
const MODIFIERS: [(u16, &str); 12] = [
|
||||
|
|
@ -260,7 +198,7 @@ impl Exception {
|
|||
pub struct MethodCode {
|
||||
max_stack: u16,
|
||||
max_locals: u16,
|
||||
opcodes: Vec<u8>,
|
||||
pub(crate) opcodes: Vec<u8>,
|
||||
exception_table: Vec<Exception>,
|
||||
code_attributes: HashMap<String, AttributeType>,
|
||||
}
|
||||
|
|
@ -274,25 +212,7 @@ impl MethodCode {
|
|||
}
|
||||
}
|
||||
|
||||
struct Stack {
|
||||
data: Vec<Value>,
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
data: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, val: Value) {
|
||||
self.data.push(val);
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> Option<Value> {
|
||||
self.data.pop()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Value {
|
||||
34
src/heap.rs
Normal file
34
src/heap.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
use std::rc::Rc;
|
||||
use crate::class::Class;
|
||||
|
||||
pub(crate) struct Object {
|
||||
// locked: bool,
|
||||
// hashcode: i32,
|
||||
class: Rc<Class>,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Object {
|
||||
pub fn new(class: Rc<Class>, data: Vec<u8>) -> Self {
|
||||
Self {
|
||||
class,
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Heap {
|
||||
objects: Vec<Object>,
|
||||
}
|
||||
|
||||
impl Heap {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
objects: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_object(&mut self, object: Object) {
|
||||
self.objects.push(object);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
pub mod types;
|
||||
pub mod class;
|
||||
pub mod io;
|
||||
pub mod opcodes;
|
||||
pub mod vm;
|
||||
mod heap;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use crate::io::{read_f32, read_f64, read_i32, read_i64, read_u16, read_u32};
|
||||
use crate::types::{AttributeType, Class, MethodCode, Exception, Field, Method};
|
||||
use crate::class::{AttributeType, Class, MethodCode, Exception, Field, Method};
|
||||
|
||||
pub fn get_class(bytecode: Vec<u8>) -> Option<Class> {
|
||||
check_magic(&bytecode);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ pub const LDC2_W: u8 = 20; // (0x14) Push long or double from run-time constant
|
|||
// pub const dload_1:u8 = 39; // (0x27) Load double 1 from local variable
|
||||
// pub const dload_2:u8 = 40; // (0x28) Load double 2 from local variable
|
||||
// pub const dload_3:u8 = 41; // (0x29) Load double 3 from local variable
|
||||
// pub const aload_0:u8 = 42;// (0x2a)
|
||||
pub const ALOAD_0:u8 = 42;// (0x2a)
|
||||
// pub const aload_1:u8 = 43;// (0x2a)
|
||||
// pub const aload_2:u8 = 44;// (0x2b)
|
||||
// pub const aload_3:u8 = 45;// (0x2c)
|
||||
|
|
@ -85,6 +85,7 @@ pub const FRETURN: u8 = 174; // (0xae) Return float from method
|
|||
pub const DRETURN: u8 = 175; // (0xaf) Return double from method
|
||||
// pub const areturn: u8 = 176; //(0xb0) return reference
|
||||
// pub const return_v: u8 = 177; // (0xb1) Return void from method (actually 'return' but that's a keyword)
|
||||
pub const NEW: u8 = 187; // (0xbb) Create new object
|
||||
// pub const invokevirtual: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class
|
||||
//
|
||||
// pub const getstatic: u8 = 178; // (0xb2) Get static field from class
|
||||
|
|
|
|||
127
src/vm.rs
Normal file
127
src/vm.rs
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use crate::{CpEntry, opcodes};
|
||||
use crate::heap::{Heap, Object};
|
||||
use crate::io::*;
|
||||
use crate::class::{AttributeType, Class, Method, Value};
|
||||
|
||||
struct StackFrame {
|
||||
data: Vec<Value>,
|
||||
}
|
||||
|
||||
impl StackFrame {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
data: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, val: Value) {
|
||||
self.data.push(val);
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> Option<Value> {
|
||||
self.data.pop()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Vm {
|
||||
classes: HashMap<String, Class>,
|
||||
heap: Heap,
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
classes: HashMap::new(),
|
||||
heap: Heap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_instance(&self, class: &Class) {
|
||||
for f in class.fields {
|
||||
println!("{}", f.type_of());
|
||||
}
|
||||
// Object::new(Rc::new(class))
|
||||
}
|
||||
|
||||
pub fn execute(&mut self, method: &Method) -> Option<Value> {
|
||||
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
|
||||
let mut stack = StackFrame::new();
|
||||
let mut pc: usize = 0;
|
||||
while pc < code.opcodes.len() {
|
||||
let opcode = &code.opcodes[pc];
|
||||
pc += 1;
|
||||
println!("{}", opcode);
|
||||
match opcode {
|
||||
&opcodes::BIPUSH => {
|
||||
let c = code.opcodes[pc] as i32;
|
||||
stack.push(Value::I32(c));
|
||||
pc += 1;
|
||||
}
|
||||
&opcodes::LDC => {
|
||||
let cp_index = read_u8(&code.opcodes, pc) as usize;
|
||||
match method.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Integer(i) => {
|
||||
stack.push(Value::I32(*i));
|
||||
}
|
||||
CpEntry::Float(f) => {
|
||||
stack.push(Value::F32(*f));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
pc += 1;
|
||||
}
|
||||
&opcodes::LDC_W => {
|
||||
let cp_index = read_u16(&code.opcodes, pc) as usize;
|
||||
match method.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Integer(i) => {
|
||||
stack.push(Value::I32(*i));
|
||||
}
|
||||
CpEntry::Float(f) => {
|
||||
stack.push(Value::F32(*f));
|
||||
}
|
||||
_ => { panic!("unexpected") }
|
||||
}
|
||||
pc += 2;
|
||||
}
|
||||
&opcodes::LDC2_W => {
|
||||
let cp_index = read_u16(&code.opcodes, pc) as usize;
|
||||
match method.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Double(d) => {
|
||||
stack.push(Value::F64(*d));
|
||||
}
|
||||
CpEntry::Long(l) => {
|
||||
stack.push(Value::I64(*l));
|
||||
}
|
||||
_ => { panic!("unexpected") }
|
||||
}
|
||||
|
||||
pc += 2;
|
||||
}
|
||||
&opcodes::ALOAD_0 => {}
|
||||
&opcodes::IRETURN => {
|
||||
return stack.pop();
|
||||
}
|
||||
&opcodes::DRETURN => {
|
||||
return stack.pop();
|
||||
}
|
||||
&opcodes::FRETURN => {
|
||||
return stack.pop();
|
||||
}
|
||||
&opcodes::NEW => {
|
||||
let cp_index = read_u16(&code.opcodes, pc) as usize;
|
||||
if let CpEntry::ClassRef(class_name_index) = method.constant_pool.get(&cp_index).unwrap() {
|
||||
if let CpEntry::Utf8(class) = method.constant_pool.get(class_name_index).unwrap(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO implement all opcodes
|
||||
_ => { panic!("opcode not implemented") }
|
||||
}
|
||||
}
|
||||
}
|
||||
None // TODO error situation
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -2,7 +2,13 @@ public class Float {
|
|||
|
||||
private final static float f =42.0F;
|
||||
|
||||
public static float get() {
|
||||
private float f2;
|
||||
|
||||
public static float getF() {
|
||||
return f;
|
||||
}
|
||||
|
||||
public float getF2(){
|
||||
return f2;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
mod test {
|
||||
use classfile_reader::{get_class, io};
|
||||
use classfile_reader::types::Value;
|
||||
use classfile_reader::class::Value;
|
||||
use classfile_reader::vm::Vm;
|
||||
|
||||
#[test]
|
||||
fn get_constant_int() {
|
||||
let class = get_class(io::read_class_file("tests/Int.class")).unwrap();
|
||||
assert_eq!((55, 0), class.get_version());
|
||||
if let Value::I32(v) = class.methods.get("public static get()I").unwrap().execute().unwrap() {
|
||||
|
||||
|
||||
if let Value::I32(v) = Vm::new().execute(class.methods.get("public static get()I").unwrap()).unwrap() {
|
||||
assert_eq!(v, 42);
|
||||
} else {
|
||||
panic!("fail");
|
||||
|
|
@ -17,7 +20,7 @@ mod test {
|
|||
fn get_constant_double() {
|
||||
let class = get_class(io::read_class_file("tests/Double.class")).unwrap();
|
||||
assert_eq!((55, 0), class.get_version());
|
||||
if let Value::F64(v) = class.methods.get("public static get()D").unwrap().execute().unwrap() {
|
||||
if let Value::F64(v) = Vm::new().execute(class.methods.get("public static get()D").unwrap()).unwrap() {
|
||||
assert_eq!(v, 42.0);
|
||||
} else {
|
||||
panic!("fail");
|
||||
|
|
@ -26,9 +29,21 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn get_constant_foat() {
|
||||
let class = get_class(io::read_class_file("tests/Float.class")).unwrap();
|
||||
Vm::new().new_instance(class);
|
||||
// assert_eq!((55, 0), class.get_version());
|
||||
// if let Value::F32(v) = Vm::new().execute(class.methods.get("public static getF()F").unwrap()).unwrap() {
|
||||
// assert_eq!(v, 42.0);
|
||||
// } else {
|
||||
// panic!("fail");
|
||||
// }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_foat() {
|
||||
let class = get_class(io::read_class_file("tests/Float.class")).unwrap();
|
||||
assert_eq!((55, 0), class.get_version());
|
||||
if let Value::F32(v) = class.methods.get("public static get()F").unwrap().execute().unwrap() {
|
||||
if let Value::F32(v) = Vm::new().execute(class.methods.get("public getF2()F").unwrap()).unwrap() {
|
||||
assert_eq!(v, 42.0);
|
||||
} else {
|
||||
panic!("fail");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue