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::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::{CpEntry, opcodes};
|
use crate::CpEntry;
|
||||||
use crate::io::{read_u8, read_u16};
|
use crate::heap::Object;
|
||||||
|
use crate::io::read_u16;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
//TODO create factory function
|
//TODO create factory function
|
||||||
|
|
@ -25,18 +26,20 @@ impl Class {
|
||||||
(self.major_version, self.minor_version)
|
(self.major_version, self.minor_version)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(&self, method_name: &str) -> Value {
|
// pub fn execute(&self, method_name: &str) -> Value {
|
||||||
let m = self.methods.get(method_name).unwrap();
|
// let m = self.methods.get(method_name).unwrap();
|
||||||
m.execute().unwrap() //TODO remove unwrap
|
// execute(m).unwrap() //TODO
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Method {
|
pub struct Method {
|
||||||
constant_pool: Rc<HashMap<usize, CpEntry>>,
|
pub(crate) constant_pool: Rc<HashMap<usize, CpEntry>>,
|
||||||
access_flags: u16,
|
access_flags: u16,
|
||||||
name_index: usize,
|
name_index: usize,
|
||||||
descriptor_index: usize,
|
descriptor_index: usize,
|
||||||
attributes: HashMap<String, AttributeType>,
|
pub(crate) attributes: HashMap<String, AttributeType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Method {
|
impl fmt::Debug for Method {
|
||||||
|
|
@ -67,78 +70,6 @@ impl Method {
|
||||||
|
|
||||||
full_name
|
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 {
|
pub struct Field {
|
||||||
|
|
@ -178,6 +109,13 @@ impl Field {
|
||||||
|
|
||||||
full_name
|
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] = [
|
const MODIFIERS: [(u16, &str); 12] = [
|
||||||
|
|
@ -260,7 +198,7 @@ impl Exception {
|
||||||
pub struct MethodCode {
|
pub struct MethodCode {
|
||||||
max_stack: u16,
|
max_stack: u16,
|
||||||
max_locals: u16,
|
max_locals: u16,
|
||||||
opcodes: Vec<u8>,
|
pub(crate) opcodes: Vec<u8>,
|
||||||
exception_table: Vec<Exception>,
|
exception_table: Vec<Exception>,
|
||||||
code_attributes: HashMap<String, AttributeType>,
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum Value {
|
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 io;
|
||||||
pub mod opcodes;
|
pub mod opcodes;
|
||||||
|
pub mod vm;
|
||||||
|
mod heap;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use crate::io::{read_f32, read_f64, read_i32, read_i64, read_u16, read_u32};
|
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> {
|
pub fn get_class(bytecode: Vec<u8>) -> Option<Class> {
|
||||||
check_magic(&bytecode);
|
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_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_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 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_1:u8 = 43;// (0x2a)
|
||||||
// pub const aload_2:u8 = 44;// (0x2b)
|
// pub const aload_2:u8 = 44;// (0x2b)
|
||||||
// pub const aload_3:u8 = 45;// (0x2c)
|
// 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 DRETURN: u8 = 175; // (0xaf) Return double from method
|
||||||
// pub const areturn: u8 = 176; //(0xb0) return reference
|
// 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 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 invokevirtual: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class
|
||||||
//
|
//
|
||||||
// pub const getstatic: u8 = 178; // (0xb2) Get static field from 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;
|
private final static float f =42.0F;
|
||||||
|
|
||||||
public static float get() {
|
private float f2;
|
||||||
|
|
||||||
|
public static float getF() {
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getF2(){
|
||||||
|
return f2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
mod test {
|
mod test {
|
||||||
use classfile_reader::{get_class, io};
|
use classfile_reader::{get_class, io};
|
||||||
use classfile_reader::types::Value;
|
use classfile_reader::class::Value;
|
||||||
|
use classfile_reader::vm::Vm;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_constant_int() {
|
fn get_constant_int() {
|
||||||
let class = get_class(io::read_class_file("tests/Int.class")).unwrap();
|
let class = get_class(io::read_class_file("tests/Int.class")).unwrap();
|
||||||
assert_eq!((55, 0), class.get_version());
|
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);
|
assert_eq!(v, 42);
|
||||||
} else {
|
} else {
|
||||||
panic!("fail");
|
panic!("fail");
|
||||||
|
|
@ -17,7 +20,7 @@ mod test {
|
||||||
fn get_constant_double() {
|
fn get_constant_double() {
|
||||||
let class = get_class(io::read_class_file("tests/Double.class")).unwrap();
|
let class = get_class(io::read_class_file("tests/Double.class")).unwrap();
|
||||||
assert_eq!((55, 0), class.get_version());
|
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);
|
assert_eq!(v, 42.0);
|
||||||
} else {
|
} else {
|
||||||
panic!("fail");
|
panic!("fail");
|
||||||
|
|
@ -26,9 +29,21 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_constant_foat() {
|
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();
|
let class = get_class(io::read_class_file("tests/Float.class")).unwrap();
|
||||||
assert_eq!((55, 0), class.get_version());
|
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);
|
assert_eq!(v, 42.0);
|
||||||
} else {
|
} else {
|
||||||
panic!("fail");
|
panic!("fail");
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue