refactoring

This commit is contained in:
Shautvast 2023-10-28 17:24:00 +02:00
parent 90361c4a35
commit 24a6bd0812
8 changed files with 304 additions and 279 deletions

View file

@ -21,7 +21,7 @@ pub static mut CLASSES: Lazy<HashMap<String, Value>> = Lazy::new(|| HashMap::new
// gets the Class from cache, or reads it from classpath, // gets the Class from cache, or reads it from classpath,
// then parses the binary data into a Class struct // then parses the binary data into a Class struct
// Vm keeps ownership of the class and hands out Arc references to it // Vm keeps ownership of the class and hands out Arc references to it
pub fn get_class( pub(crate) fn get_class(
vm: &mut Vm, vm: &mut Vm,
class_name: &str, class_name: &str,
) -> Result<Arc<RefCell<Class>>, Error> { ) -> Result<Arc<RefCell<Class>>, Error> {

View file

@ -1,5 +1,5 @@
use java_rs::vm::Vm;
use std::io::Error; use std::io::Error;
use java_rs::vm::Vm;
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
// TODO cmdline args // TODO cmdline args

143
src/vm/array.rs Normal file
View file

@ -0,0 +1,143 @@
use anyhow::{anyhow, Error};
use crate::class::Value::{self,*};
use crate::heap::ObjectRef;
pub(crate) unsafe fn array_load(index: Value, arrayref: Value) -> Result<Value, Error> {
if let I32(index) = &index {
let index = *index as usize;
if let Null = arrayref {
return Err(anyhow!("NullpointerException"));
}
if let Ref(objectref) = arrayref {
match &*objectref.get() {
ObjectRef::ByteArray(array) => {
return Ok(I32(array[index] as i32));
}
ObjectRef::ShortArray(array) => {
return Ok(I32(array[index] as i32));
}
ObjectRef::IntArray(array) => {
return Ok(I32(array[index]));
}
ObjectRef::BooleanArray(array) => {
return Ok(I32(array[index] as i32));
}
ObjectRef::CharArray(array) => {
return Ok(CHAR(array[index]));
}
ObjectRef::LongArray(array) => {
return Ok(I64(array[index]));
}
ObjectRef::FloatArray(array) => {
return Ok(F32(array[index]));
}
ObjectRef::DoubleArray(array) => {
return Ok(F64(array[index]));
}
ObjectRef::ObjectArray(_arraytype, data) => {
return Ok(Ref(data[index].clone()));
}
ObjectRef::StringArray(array) => {
return Ok(Utf8(array[index].to_owned()));
}
ObjectRef::Class(_) => {
panic!("should be array")
}
ObjectRef::Object(_) => {
panic!("should be array")
} //throw error?
}
}
}
panic!()
}
pub(crate) unsafe fn array_store(value: Value, index: Value, arrayref: &mut Value) -> Result<(), Error> {
if let Null = &*arrayref {
return Err(anyhow!("NullpointerException"));
}
if let I32(index) = index {
if let Ref(ref mut objectref) = arrayref {
match &mut *objectref.get() {
ObjectRef::ByteArray(ref mut array) => {
if let I32(value) = value {
// is i32 correct?
array[index as usize] = value as i8;
} else {
unreachable!()
}
}
ObjectRef::ShortArray(ref mut array) => {
if let I32(value) = value {
// is i32 correct?
array[index as usize] = value as i16;
} else {
unreachable!()
}
}
ObjectRef::IntArray(ref mut array) => {
if let I32(value) = value {
array[index as usize] = value;
} else {
unreachable!()
}
}
ObjectRef::BooleanArray(ref mut array) => {
if let I32(value) = value {
array[index as usize] = value > 0;
} else {
unreachable!()
}
}
ObjectRef::CharArray(ref mut array) => {
if let I32(value) = value {
array[index as usize] = char::from_u32_unchecked(value as u32);
} else {
unreachable!()
}
}
ObjectRef::LongArray(ref mut array) => {
if let I64(value) = value {
array[index as usize] = value;
} else {
unreachable!()
}
}
ObjectRef::FloatArray(ref mut array) => {
if let F32(value) = value {
array[index as usize] = value
} else {
unreachable!()
}
}
ObjectRef::DoubleArray(ref mut array) => {
if let F64(value) = value {
array[index as usize] = value
} else {
unreachable!()
}
}
ObjectRef::ObjectArray(_arraytype, ref mut array) => {
if let Ref(ref value) = value {
array[index as usize] = value.clone();
} else {
unreachable!()
}
}
ObjectRef::StringArray(ref mut array) => {
if let Utf8(ref value) = value {
array[index as usize] = value.clone();
} else {
unreachable!()
}
}
ObjectRef::Object(_) | ObjectRef::Class(_) => {} //throw error?
}
}
} else {
unreachable!()
}
Ok(())
}

5
src/vm/mod.rs Normal file
View file

@ -0,0 +1,5 @@
mod vm;
pub use vm::Vm;
mod operations;
mod stack;
mod array;

90
src/vm/operations.rs Normal file
View file

@ -0,0 +1,90 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;
use anyhow::{anyhow, Error};
use Value::I32;
use crate::class::{Class, get_class, Method, Value};
use crate::class::Value::{F32, F64, I64, Ref, Utf8};
use crate::classloader::CpEntry;
use crate::heap::ObjectRef;
use crate::vm::Vm;
use crate::vm::vm::{Invocation, MethodSignature};
pub(crate) fn get_static(vm: &mut Vm, this_class: Arc<RefCell<Class>>, field_index: u16) -> Value {
let borrow = this_class.borrow();
let (class_index, field_name_and_type_index) =
borrow.cp_field_ref(&field_index).unwrap(); // all these unwraps are safe as long as the class is valid
let (name_index, _) =
borrow.cp_name_and_type(field_name_and_type_index).unwrap();
let name = borrow.cp_utf8(name_index).unwrap();
let that_class_name_index = borrow.cp_class_ref(class_index).unwrap();
let that_class_name = borrow.cp_utf8(that_class_name_index).unwrap();
let that = get_class(vm, that_class_name.as_str()).unwrap();
let that_borrow = that.borrow();
let (_, val_index) = that_borrow
.static_field_mapping
.get(that_class_name)
.unwrap()
.get(name)
.unwrap();
that_borrow
.static_data
.get(*val_index).unwrap().as_ref().unwrap().clone()
}
pub(crate) fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<MethodSignature> {
if let CpEntry::NameAndType(method_name_index, signature_index) = cp.get(&index).unwrap() {
if let CpEntry::Utf8(method_name) = cp.get(method_name_index).unwrap() {
if let CpEntry::Utf8(signature) = cp.get(signature_index).unwrap() {
let mut method_signature: String = method_name.into();
let num_args = get_num_args(signature);
method_signature.push_str(signature);
return Some(MethodSignature::new(method_signature, num_args));
}
}
}
None
}
pub(crate) fn get_signature_for_invoke(cp: &Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<Invocation> {
if let CpEntry::MethodRef(class_index, name_and_type_index)
| CpEntry::InterfaceMethodref(class_index, name_and_type_index) = cp.get(&index).unwrap()
{
if let Some(method_signature) = get_name_and_type(Rc::clone(&cp), *name_and_type_index) {
if let CpEntry::ClassRef(class_name_index) = cp.get(class_index).unwrap() {
if let CpEntry::Utf8(class_name) = cp.get(class_name_index).unwrap() {
return Some(Invocation::new(
class_name.into(),
method_signature)
);
}
}
}
}
None
}
fn get_num_args(signature: &str) -> usize {
let mut num = 0;
let mut i = 1;
let chars: Vec<char> = signature.chars().collect();
while i < chars.len() {
if chars[i] == 'L' {
i += 1;
while chars[i] != ';' {
i += 1;
}
i += 1;
num += 1;
} else if chars[i] == ')' {
break;
} else {
i += 1;
num += 1;
}
}
num
}

29
src/vm/stack.rs Normal file
View file

@ -0,0 +1,29 @@
use anyhow::Error;
use crate::class::Value;
#[derive(Debug)]
pub(crate) struct StackFrame {
pub(crate) at: String,
pub(crate) data: Vec<Value>,
}
// maybe just call frame
impl StackFrame {
pub(crate) fn new(at_class: &str, at_method: &str) -> Self {
let mut at: String = at_class.into();
at.push('.');
at.push_str(at_method);
Self { at, data: vec![] }
}
pub(crate) fn push(&mut self, val: Value) {
self.data.push(val);
}
pub(crate) fn len(&self) -> usize {
self.data.len()
}
pub(crate) fn pop(&mut self) -> Result<Value, Error> {
Ok(self.data.pop().unwrap())
}
}

View file

@ -1,48 +1,25 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Write;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::io::Write;
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use log::{debug, info}; use log::{debug, info};
use Value::*; use Value::*;
use crate::class::{AttributeType, Class, CLASSES, get_class, Method, Modifier, unsafe_ref, Value};
use crate::class::Value::{Null, Void}; use crate::class::Value::{Null, Void};
use crate::class::{get_class, unsafe_ref, AttributeType, Class, Modifier, Value, Method, CLASSES};
use crate::classloader::CpEntry; use crate::classloader::CpEntry;
use crate::heap::{Heap, Object, ObjectRef}; use crate::heap::{Heap, Object, ObjectRef};
use crate::io::*; use crate::io::*;
use crate::native::invoke_native; use crate::native::invoke_native;
use crate::opcodes; use crate::opcodes;
use crate::opcodes::*; use crate::opcodes::*;
use crate::vm::array::{array_load, array_store};
#[derive(Debug)] use crate::vm::operations::{get_name_and_type, get_signature_for_invoke, get_static};
pub(crate) struct StackFrame { use crate::vm::stack::StackFrame;
at: String,
data: Vec<Value>,
}
// maybe just call frame
impl StackFrame {
fn new(at_class: &str, at_method: &str) -> Self {
let mut at: String = at_class.into();
at.push('.');
at.push_str(at_method);
Self { at, data: vec![] }
}
fn push(&mut self, val: Value) {
self.data.push(val);
}
fn len(&self) -> usize {
self.data.len()
}
fn pop(&mut self) -> Result<Value, Error> {
Ok(self.data.pop().unwrap())
}
}
pub struct Vm { pub struct Vm {
pub classpath: Vec<String>, pub classpath: Vec<String>,
@ -324,7 +301,9 @@ impl Vm {
} }
CpEntry::StringRef(utf8_index) => { CpEntry::StringRef(utf8_index) => {
if let CpEntry::Utf8(s) = method.constant_pool.get(utf8_index).unwrap() { if let CpEntry::Utf8(s) = method.constant_pool.get(utf8_index).unwrap() {
self.current_frame().push(Value::Utf8(s.to_owned())); self.current_frame().push(Utf8(s.to_owned()));
} else {
} }
} }
_ => { _ => {
@ -370,7 +349,9 @@ impl Vm {
.push(local_params[3].as_ref().unwrap().clone()); .push(local_params[3].as_ref().unwrap().clone());
} }
IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => unsafe { IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => unsafe {
self.array_load()?; let index = self.current_frame().pop()?;
let arrayref = self.current_frame().pop()?;
self.current_frame().push(array_load(index, arrayref)?);
}, },
ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => { ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => {
let index = read_u8(&code.opcodes, pc) as usize; let index = read_u8(&code.opcodes, pc) as usize;
@ -390,7 +371,10 @@ impl Vm {
} }
BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE
| AASTORE => unsafe { | AASTORE => unsafe {
self.array_store()? let value = self.current_frame().pop()?;
let index = self.current_frame().pop()?;
let arrayref = &mut self.current_frame().pop()?;
array_store(value, index, arrayref)?
}, },
POP => { POP => {
self.current_frame().pop()?; self.current_frame().pop()?;
@ -430,33 +414,9 @@ impl Vm {
return Ok(Void); return Ok(Void);
} }
GETSTATIC => { GETSTATIC => {
let borrow = this_class.borrow(); let field_index = read_u16(&code.opcodes, pc);
let cp_index = read_u16(&code.opcodes, pc); let field_value = get_static(self, this_class.clone(), field_index);
let (class_index, field_name_and_type_index) = self.current_frame().push(field_value);
borrow.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid
let (name_index, _) =
borrow.cp_name_and_type(field_name_and_type_index).unwrap();
let name = borrow.cp_utf8(name_index).unwrap();
let that_class_name_index = borrow.cp_class_ref(class_index).unwrap();
let that_class_name = borrow.cp_utf8(that_class_name_index).unwrap();
let that = get_class(self, that_class_name.as_str())?;
let that_borrow = that.borrow();
let (_, val_index) = that_borrow
.static_field_mapping
.get(that_class_name)
.unwrap()
.get(name)
.unwrap();
self.current_frame().push(
that_borrow
.static_data
.get(*val_index)
.unwrap()
.as_ref()
.unwrap()
.clone(),
);
} }
PUTSTATIC => { PUTSTATIC => {
let mut borrow = this_class.borrow_mut(); let mut borrow = this_class.borrow_mut();
@ -733,152 +693,6 @@ impl Vm {
} }
} }
unsafe fn array_load(&mut self) -> Result<(), Error> {
let value = self.current_frame().pop()?;
if let I32(index) = &value {
let index = *index as usize;
let arrayref = self.current_frame().pop()?;
if let Null = arrayref {
return Err(anyhow!("NullpointerException"));
}
if let Ref(objectref) = arrayref {
match &*objectref.get() {
ObjectRef::ByteArray(array) => {
self.current_frame().push(I32(array[index] as i32));
}
ObjectRef::ShortArray(array) => {
self.current_frame().push(I32(array[index] as i32));
}
ObjectRef::IntArray(array) => {
self.current_frame().push(I32(array[index]));
}
ObjectRef::BooleanArray(array) => {
self.current_frame().push(I32(array[index] as i32));
}
ObjectRef::CharArray(array) => {
self.current_frame().push(CHAR(array[index]));
}
ObjectRef::LongArray(array) => {
self.current_frame().push(I64(array[index]));
}
ObjectRef::FloatArray(array) => {
self.current_frame().push(F32(array[index]));
}
ObjectRef::DoubleArray(array) => {
self.current_frame().push(F64(array[index]));
}
ObjectRef::ObjectArray(_arraytype, data) => {
self.current_frame().push(Ref(data[index].clone()));
}
ObjectRef::StringArray(array) => {
self.current_frame().push(Utf8(array[index].to_owned()));
}
ObjectRef::Class(_) => {
panic!("should be array")
}
ObjectRef::Object(_) => {
panic!("should be array")
} //throw error?
}
}
}
Ok(())
}
unsafe fn array_store(&mut self) -> Result<(), Error> {
let value = self.current_frame().pop()?;
let index = self.current_frame().pop()?;
let arrayref = &mut self.current_frame().pop()?;
if let Value::Null = &*arrayref {
return Err(anyhow!("NullpointerException"));
}
if let I32(index) = index {
if let Ref(ref mut objectref) = arrayref {
match &mut *objectref.get() {
ObjectRef::ByteArray(ref mut array) => {
if let I32(value) = value {
// is i32 correct?
array[index as usize] = value as i8;
} else {
unreachable!()
}
}
ObjectRef::ShortArray(ref mut array) => {
if let I32(value) = value {
// is i32 correct?
array[index as usize] = value as i16;
} else {
unreachable!()
}
}
ObjectRef::IntArray(ref mut array) => {
if let I32(value) = value{
array[index as usize] = value;
} else {
unreachable!()
}
}
ObjectRef::BooleanArray(ref mut array) => {
if let I32(value) = value {
array[index as usize] = value > 0;
} else {
unreachable!()
}
}
ObjectRef::CharArray(ref mut array) => {
if let I32(value) = value {
array[index as usize] = char::from_u32_unchecked(value as u32);
} else {
unreachable!()
}
}
ObjectRef::LongArray(ref mut array) => {
if let I64(value) = value {
array[index as usize] = value;
} else {
unreachable!()
}
}
ObjectRef::FloatArray(ref mut array) => {
if let F32(value) = value {
array[index as usize] = value
} else {
unreachable!()
}
}
ObjectRef::DoubleArray(ref mut array) => {
if let F64(value) = value {
array[index as usize] = value
} else {
unreachable!()
}
}
ObjectRef::ObjectArray(_arraytype, ref mut array) => {
if let Ref(ref value) = value {
array[index as usize] = value.clone();
} else {
unreachable!()
}
}
ObjectRef::StringArray(ref mut array) => {
if let Utf8(ref value) = value {
array[index as usize] = value.clone();
} else {
unreachable!()
}
}
ObjectRef::Object(_) | ObjectRef::Class(_) => {} //throw error?
}
}
} else {
unreachable!()
}
Ok(())
}
fn store( fn store(
&mut self, &mut self,
local_params: &mut Vec<Option<Value>>, local_params: &mut Vec<Option<Value>>,
@ -893,86 +707,30 @@ impl Vm {
} }
} }
struct Invocation { pub(crate) struct Invocation {
class_name: String, class_name: String,
method: MethodSignature, method: MethodSignature,
} }
struct MethodSignature { impl Invocation {
pub fn new(class_name: String, method: MethodSignature) -> Self{
Self{
class_name, method
}
}
}
pub(crate) struct MethodSignature {
name: String, name: String,
num_args: usize, num_args: usize,
} }
// TODO can be simplified now, using cp_ methods in Class impl MethodSignature {
fn get_signature_for_invoke(cp: &Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<Invocation> { pub(crate) fn new(name: String, num_args: usize) -> Self {
if let CpEntry::MethodRef(class_index, name_and_type_index) MethodSignature {
| CpEntry::InterfaceMethodref(class_index, name_and_type_index) = cp.get(&index).unwrap() name,
{ num_args,
if let Some(method_signature) = get_name_and_type(Rc::clone(&cp), *name_and_type_index) {
if let CpEntry::ClassRef(class_name_index) = cp.get(class_index).unwrap() {
if let CpEntry::Utf8(class_name) = cp.get(class_name_index).unwrap() {
return Some(Invocation {
class_name: class_name.into(),
method: method_signature,
});
}
}
} }
} }
None
} }
// unsafe fn copy(value: Value) -> Value {
// match value {
// Void => Void,
// Null => Null,
// BOOL(b) => BOOL(b),
// CHAR(c) => CHAR(c),
// I32(i) => I32(i),
// I64(l) => I64(l),
// F32(f) => F32(f),
// F64(d) => F64(d),
// Ref(r) => Ref(r.clone()),
// Utf8(s) => Utf8(s.to_owned()),
// }
// }
fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<MethodSignature> {
if let CpEntry::NameAndType(method_name_index, signature_index) = cp.get(&index).unwrap() {
if let CpEntry::Utf8(method_name) = cp.get(method_name_index).unwrap() {
if let CpEntry::Utf8(signature) = cp.get(signature_index).unwrap() {
let mut method_signature: String = method_name.into();
let num_args = get_hum_args(signature);
method_signature.push_str(signature);
return Some(MethodSignature {
name: method_signature,
num_args,
});
}
}
}
None
}
fn get_hum_args(signature: &str) -> usize {
let mut num = 0;
let mut i = 1;
let chars: Vec<char> = signature.chars().collect();
while i < chars.len() {
if chars[i] == 'L' {
i += 1;
while chars[i] != ';' {
i += 1;
}
i += 1;
num += 1;
} else if chars[i] == ')' {
break;
} else {
i += 1;
num += 1;
}
}
num
}

View file

@ -1,7 +1,7 @@
mod test { mod test {
use java_rs::class::Value; use java_rs::class::Value;
use java_rs::heap::ObjectRef; use java_rs::heap::ObjectRef;
use java_rs::vm::Vm; use java_rs::vm1::Vm;
#[test] #[test]
fn if_cmp() { fn if_cmp() {