added object creation and getField for float

This commit is contained in:
Sander Hautvast 2023-09-29 17:59:27 +02:00
parent ffa9879515
commit 988cb6c376
5 changed files with 159 additions and 132 deletions

View file

@ -1,7 +1,9 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use crate::classloader::CpEntry; use crate::classloader::CpEntry;
use crate::heap::Object;
use crate::io::read_u16; use crate::io::read_u16;
@ -222,4 +224,5 @@ pub enum Value {
F64(f64), F64(f64),
BOOL(bool), BOOL(bool),
CHAR(char), CHAR(char),
Ref(Arc<Object>)
} }

View file

@ -143,8 +143,8 @@ fn read_constant_pool_entry(cp_index: &mut u16, index: &mut usize, bytecode: &[u
CpEntry::InterfaceMethodref(class_index, name_and_type_index) CpEntry::InterfaceMethodref(class_index, name_and_type_index)
} }
12 => { 12 => {
let name_index = read_u16(bytecode, *index + 1) as usize; let name_index = read_u16(bytecode, *index + 1);
let descriptor_index = read_u16(bytecode, *index + 3) as usize; let descriptor_index = read_u16(bytecode, *index + 3);
*index += 5; *index += 5;
CpEntry::NameAndType(name_index, descriptor_index) CpEntry::NameAndType(name_index, descriptor_index)
} }
@ -264,6 +264,6 @@ pub enum CpEntry {
Fieldref(u16, u16), Fieldref(u16, u16),
MethodRef(u16, u16), MethodRef(u16, u16),
InterfaceMethodref(u16, u16), InterfaceMethodref(u16, u16),
NameAndType(usize, usize), NameAndType(u16, u16),
} }

View file

@ -1,16 +1,18 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use crate::class::{Class, Value}; use crate::class::{Class, Value};
pub(crate) struct Object { #[derive(Debug)]
pub struct Object {
// locked: bool, // locked: bool,
// hashcode: i32, // hashcode: i32,
class: Rc<Class>, class: Arc<Class>,
data: HashMap<u16, Value>, //TODO optimize pub data: HashMap<u16, Arc<Value>>, //TODO optimize
} }
impl Object { impl Object {
pub fn new(class: Rc<Class>, data: HashMap<u16, Value>) -> Self { pub fn new(class: Arc<Class>, data: HashMap<u16, Arc<Value>>) -> Self {
Self { Self {
class, class,
data, data,
@ -19,7 +21,7 @@ impl Object {
} }
pub(crate) struct Heap { pub(crate) struct Heap {
objects: Vec<Object>, objects: Vec<Arc<Object>>,
} }
impl Heap { impl Heap {
@ -29,7 +31,7 @@ impl Heap {
} }
} }
pub(crate) fn new_object(&mut self, object: Object) { pub(crate) fn new_object(&mut self, object: Arc<Object>) {
self.objects.push(object); self.objects.push(object);
} }
} }

100
src/vm.rs
View file

@ -1,15 +1,16 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::sync::Arc;
use anyhow::Error;
use crate::opcodes; use anyhow::{anyhow, Error};
use crate::class::{AttributeType, Class, Method, Value};
use crate::class::{AttributeType, Class, Value};
use crate::classloader::{CpEntry, load_class}; use crate::classloader::{CpEntry, load_class};
use crate::heap::{Heap, Object}; use crate::heap::{Heap, Object};
use crate::io::*; use crate::io::*;
use crate::opcodes;
struct StackFrame { struct StackFrame {
data: Vec<Value>, data: Vec<Arc<Value>>,
} }
impl StackFrame { impl StackFrame {
@ -19,18 +20,18 @@ impl StackFrame {
} }
} }
fn push(&mut self, val: Value) { fn push(&mut self, val: Arc<Value>) {
self.data.push(val); self.data.push(val);
} }
fn pop(&mut self) -> Option<Value> { fn pop(&mut self) -> Result<Arc<Value>, Error> {
self.data.pop() Ok(self.data.pop().unwrap())
} }
} }
pub struct Vm { pub struct Vm {
classpath: Vec<String>, classpath: Vec<String>,
classes: HashMap<String, Class>, classes: HashMap<String, Arc<Class>>,
//TODO implement classloader //TODO implement classloader
heap: Heap, heap: Heap,
} }
@ -44,22 +45,18 @@ impl Vm {
} }
} }
pub fn get_class(&mut self, class_name: &str) -> Result<&Class, Error> { pub fn get_class(&mut self, class_name: &str) -> Result<Arc<Class>, Error> {
if !self.classes.contains_key(class_name) { let entry = self.classes.entry(class_name.into());
self.load_class(class_name)?; let entry = entry.or_insert_with(|| {
} let resolved_path = find_class(&self.classpath, class_name).unwrap();
let class = self.classes.get(class_name); let bytecode = read_class_file(resolved_path).unwrap();
Ok(class.expect("ClassNotFoundException")) Arc::new(load_class(bytecode).unwrap())
});
Ok(entry.clone())
} }
pub fn load_class(&mut self, name: &str) -> Result<(), Error> {
let resolved_path = find_class(&self.classpath, name)?;
let bytecode = read_class_file(resolved_path)?;
self.classes.insert(name.to_owned(), load_class(bytecode)?);
Ok(())
}
pub fn new_instance(&self, class: Rc<Class>) { pub fn new_instance(&self, class: Arc<Class>) -> Object {
let mut data = HashMap::new(); let mut data = HashMap::new();
for f in &class.fields { for f in &class.fields {
let value = match f.type_of().as_str() { let value = match f.type_of().as_str() {
@ -73,15 +70,14 @@ impl Vm {
"L" => Value::Null, "L" => Value::Null,
_ => Value::Void _ => Value::Void
}; };
data.insert(f.name_index, value); data.insert(f.name_index, Arc::new(value));
} }
Object::new(class.clone(), data); Object::new(class.clone(), data)
} }
pub fn execute(&mut self, class_name: &str, method_name: &str) -> Option<Value> { pub fn execute(&mut self, class_name: &str, method_name: &str, instance: Option<Arc<Object>>) -> Result<Arc<Value>, Error> {
let class = self.classes.get(class_name); let class = self.get_class(class_name)?;
if let Some(c) = class { let method = class.get_method(method_name);
let method = c.get_method(method_name);
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() { if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
let mut stack = StackFrame::new(); let mut stack = StackFrame::new();
let mut pc: usize = 0; let mut pc: usize = 0;
@ -92,17 +88,17 @@ impl Vm {
match opcode { match opcode {
&opcodes::BIPUSH => { &opcodes::BIPUSH => {
let c = code.opcodes[pc] as i32; let c = code.opcodes[pc] as i32;
stack.push(Value::I32(c)); stack.push(Arc::new(Value::I32(c)));
pc += 1; pc += 1;
} }
&opcodes::LDC => { &opcodes::LDC => {
let cp_index = read_u8(&code.opcodes, pc) as u16; let cp_index = read_u8(&code.opcodes, pc) as u16;
match method.constant_pool.get(&cp_index).unwrap() { match method.constant_pool.get(&cp_index).unwrap() {
CpEntry::Integer(i) => { CpEntry::Integer(i) => {
stack.push(Value::I32(*i)); stack.push(Arc::new(Value::I32(*i)));
} }
CpEntry::Float(f) => { CpEntry::Float(f) => {
stack.push(Value::F32(*f)); stack.push(Arc::new(Value::F32(*f)));
} }
_ => {} _ => {}
} }
@ -112,10 +108,10 @@ impl Vm {
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
match method.constant_pool.get(&cp_index).unwrap() { match method.constant_pool.get(&cp_index).unwrap() {
CpEntry::Integer(i) => { CpEntry::Integer(i) => {
stack.push(Value::I32(*i)); stack.push(Arc::new(Value::I32(*i)));
} }
CpEntry::Float(f) => { CpEntry::Float(f) => {
stack.push(Value::F32(*f)); stack.push(Arc::new(Value::F32(*f)));
} }
_ => { panic!("unexpected") } _ => { panic!("unexpected") }
} }
@ -125,17 +121,24 @@ impl Vm {
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
match method.constant_pool.get(&cp_index).unwrap() { match method.constant_pool.get(&cp_index).unwrap() {
CpEntry::Double(d) => { CpEntry::Double(d) => {
stack.push(Value::F64(*d)); stack.push(Arc::new(Value::F64(*d)));
} }
CpEntry::Long(l) => { CpEntry::Long(l) => {
stack.push(Value::I64(*l)); stack.push(Arc::new(Value::I64(*l)));
} }
_ => { panic!("unexpected") } _ => { panic!("unexpected") }
} }
pc += 2; pc += 2;
} }
&opcodes::ALOAD_0 => {} &opcodes::ALOAD_0 => {
match instance.clone() {
Some(r) => {
stack.push(Arc::new(Value::Ref(r)));
}
None => { panic!("static context") }
}
}
&opcodes::IRETURN => { &opcodes::IRETURN => {
return stack.pop(); return stack.pop();
} }
@ -145,10 +148,28 @@ impl Vm {
&opcodes::FRETURN => { &opcodes::FRETURN => {
return stack.pop(); return stack.pop();
} }
&opcodes::GETFIELD => {
let cp_index = read_u16(&code.opcodes, pc);
if let CpEntry::Fieldref(class_index, name_and_type_index) = method.constant_pool.get(&cp_index).unwrap() {
if let Value::Ref(inst) = &*stack.pop()? {
if let CpEntry::NameAndType(name, _) = method.constant_pool.get(name_and_type_index).unwrap() {
let value = inst.data.get(&name).unwrap();
println!("{:?}", value);
stack.push(value.clone());
}
}
}
pc += 2;
}
&opcodes::NEW => { &opcodes::NEW => {
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
if let CpEntry::ClassRef(class_name_index) = method.constant_pool.get(&cp_index).unwrap() { 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() {} if let CpEntry::Utf8(class) = method.constant_pool.get(class_name_index).unwrap() {
let class = self.get_class(class_name)?;
let object = Arc::new(self.new_instance(class));
stack.push(Arc::new(Value::Ref(object.clone())));
self.heap.new_object(object);
}
} }
} }
//TODO implement all opcodes //TODO implement all opcodes
@ -156,9 +177,6 @@ impl Vm {
} }
} }
} }
None // TODO error situation Err(anyhow!("should not happen"))
} else {
panic!("class not found");
}
} }
} }

View file

@ -1,39 +1,40 @@
mod test { mod test {
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use classfile_reader::{classloader::load_class, io}; use classfile_reader::{classloader::load_class, io};
use classfile_reader::class::Value; use classfile_reader::class::Value;
use classfile_reader::vm::Vm; use classfile_reader::vm::Vm;
#[test] #[test]
fn get_constant_int() { fn get_constant_int() {
let mut vm = Vm::new("."); // let mut vm = Vm::new(".");
let class = vm.get_class("Float").expect("ClassNotFound"); // let class = vm.get_class("Float").expect("ClassNotFound");
assert_eq!((55, 0), class.get_version()); // assert_eq!((55, 0), class.get_version());
//
//
if let Value::I32(v) = Vm::new("").execute("Float", "public static get()I").unwrap() { // if let Value::I32(v) = Vm::new("").execute("Float", "public static get()I", None).unwrap() {
assert_eq!(v, 42); // assert_eq!(v, 42);
} else { // } else {
panic!("fail"); // panic!("fail");
} // }
} }
#[test] #[test]
fn get_constant_double() { fn get_constant_double() {
let mut vm = Vm::new("."); // let mut vm = Vm::new(".");
let class = vm.get_class("Double").expect("ClassNotFound"); // let class = vm.get_class("Double").expect("ClassNotFound");
assert_eq!((55, 0), class.get_version()); // assert_eq!((55, 0), class.get_version());
if let Value::F64(v) = Vm::new("").execute("Double", "public static get()D").unwrap() { // if let Value::F64(v) = Vm::new("").execute("Double", "public static get()D", None).unwrap() {
assert_eq!(v, 42.0); // assert_eq!(v, 42.0);
} else { // } else {
panic!("fail"); // panic!("fail");
} // }
} }
#[test] #[test]
fn get_constant_foat() { fn get_constant_foat() {
let mut vm = Vm::new("."); let mut vm = Vm::new(".");
vm.load_class("Float").expect("ClassNotFound"); // vm.load_class("Float").expect("ClassNotFound");
// assert_eq!((55, 0), class.get_version()); // assert_eq!((55, 0), class.get_version());
// if let Value::F32(v) = Vm::new().execute(class.methods.get("public static getF()F").unwrap()).unwrap() { // if let Value::F32(v) = Vm::new().execute(class.methods.get("public static getF()F").unwrap()).unwrap() {
// assert_eq!(v, 42.0); // assert_eq!(v, 42.0);
@ -45,9 +46,12 @@ mod test {
#[test] #[test]
fn get_float() { fn get_float() {
// assert_eq!((55, 0), class.get_version()); // assert_eq!((55, 0), class.get_version());
let mut vm = Vm::new("/Users/FJ19WK/RustroverProjects/classfile_reader/tests"); let mut vm = Vm::new("/Users/FJ19WK/RustroverProjects/classfile_reader/tests");
vm.load_class("Float").expect("ClassNotFound");
if let Value::F32(v) = vm.execute("Float","public getF2()F").unwrap() { let c = vm.get_class("Float").unwrap();
let object = Arc::new(vm.new_instance(c));
if let Value::F32(v) = *vm.execute("Float","public getF2()F", Some(object)).unwrap() {
assert_eq!(v, 0.0); assert_eq!(v, 0.0);
} else { } else {
panic!("fail"); panic!("fail");