WIP create instance on heap

This commit is contained in:
Sander Hautvast 2023-09-27 13:56:26 +02:00
parent 089ba025ea
commit 8dd60c0866
8 changed files with 212 additions and 107 deletions

View file

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

View file

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

View file

@ -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
View 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.

View file

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

View file

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