battling stackoverflow and invalid references

This commit is contained in:
Shautvast 2023-11-12 17:25:32 +01:00
parent 712816dc8b
commit f2dc2d2938
4 changed files with 86 additions and 80 deletions

View file

@ -16,6 +16,7 @@ static mut CLASSMANAGER: Lazy<ClassManager> = Lazy::new(|| ClassManager::new());
static PRIMITIVES: Lazy<Vec<&str>> = Lazy::new(|| vec!["B", "S", "I", "J", "F", "D", "Z", "J", "C"]); static PRIMITIVES: Lazy<Vec<&str>> = Lazy::new(|| vec!["B", "S", "I", "J", "F", "D", "Z", "J", "C"]);
pub fn init() { pub fn init() {
debug!("classmanager init");
unsafe { unsafe {
CLASSMANAGER.classes.clear(); CLASSMANAGER.classes.clear();
CLASSMANAGER.names.clear(); CLASSMANAGER.names.clear();
@ -31,9 +32,9 @@ pub fn set_classpath(classpath: &str) {
} }
} }
pub fn get_class_by_id(id: &ClassId) -> Option<&'static Class> { pub fn get_class_by_id(id: ClassId) -> Option<&'static Class> {
unsafe { unsafe {
CLASSMANAGER.get_class_by_id(id) CLASSMANAGER.get_class_by_id(&id)
} }
} }
@ -43,15 +44,15 @@ pub fn classdef_name(id: &ClassId) -> Option<String> {
} }
} }
pub fn get_classid(name: &str) -> &ClassId { pub fn get_classid(name: &str) -> ClassId {
unsafe { unsafe {
CLASSMANAGER.get_classid(name) CLASSMANAGER.get_classid(name).clone()
} }
} }
pub fn get_classdef(id: &ClassId) -> &ClassDef { pub fn get_classdef(id: ClassId) -> &'static ClassDef {
unsafe { unsafe {
CLASSMANAGER.get_classdef(id) CLASSMANAGER.get_classdef(&id)
} }
} }
@ -79,15 +80,15 @@ pub fn get_static(id: &ClassId, index: usize) -> Value {
} }
} }
pub fn set_static(id: &ClassId, index: usize, value: Value) { pub fn set_static(id: ClassId, index: usize, value: Value) {
unsafe { unsafe {
CLASSMANAGER.static_class_data.get_mut(id).unwrap()[index] = value; CLASSMANAGER.static_class_data.get_mut(&id).unwrap()[index] = value;
} }
} }
pub fn get_classobject(id: &ClassId) -> Option<&Value> { pub fn get_classobject(id: ClassId) -> Option<&'static Value> {
unsafe { unsafe {
CLASSMANAGER.class_objects.get(id) CLASSMANAGER.class_objects.get(&id)
} }
} }
@ -198,7 +199,8 @@ impl ClassManager {
/// get optional classid from cache /// get optional classid from cache
fn get_class_by_name(&self, name: &str) -> Option<&Class> { fn get_class_by_name(&self, name: &str) -> Option<&Class> {
let id = self.names.get(name); let id = self.names.get(name);
self.classes.get(id.unwrap()) let t = self.classes.get(id.unwrap());
t
} }
/// adds the class and calculates the 'offset' of it's fields (static and non-static) /// adds the class and calculates the 'offset' of it's fields (static and non-static)

View file

@ -14,10 +14,10 @@ use crate::{class, classmanager};
use crate::vm::stack::StackFrame; use crate::vm::stack::StackFrame;
use crate::vm::Vm; use crate::vm::Vm;
pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec<StackFrame>, class_name: &String, method_name: &str, _args: Vec<Value>) -> Result<Value, Error> { pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec<StackFrame>, class_name: &str, method_name: &str, _args: Vec<Value>) -> Result<Value, Error> {
debug!("native {}.{}", class_name, method_name); debug!("native {}.{}", class_name, method_name);
match class_name.as_str() { match class_name {
"java/lang/Class" => java_lang_Class(vm, method_name), "java/lang/Class" => java_lang_Class(vm, method_name),
"java/lang/System" => java_lang_System(vm, method_name), "java/lang/System" => java_lang_System(vm, method_name),
"jdk/internal/misc/Unsafe" => jdk_internal_misc_Unsafe(vm, method_name), "jdk/internal/misc/Unsafe" => jdk_internal_misc_Unsafe(vm, method_name),

View file

@ -5,20 +5,19 @@ use std::rc::Rc;
use anyhow::Error; use anyhow::Error;
use log::debug; use log::debug;
use crate::class::{Class, ObjectRef, Value}; use crate::{class, classmanager};
use crate::class::{Class, ClassId, ObjectRef, Value};
use crate::class::ObjectRef::Object; use crate::class::ObjectRef::Object;
use crate::class::Value::{I32, Ref}; use crate::class::Value::{I32, Ref};
use crate::classloader::classdef::{CpEntry, Method}; use crate::classloader::classdef::{CpEntry, Method};
use crate::{class, classmanager};
use crate::vm::stack::StackFrame; use crate::vm::stack::StackFrame;
use crate::vm::Vm;
use crate::vm::vm::{current_frame, Invocation, MethodSignature}; use crate::vm::vm::{current_frame, Invocation, MethodSignature};
/// the place for opcode implementations that are a bit long /// the place for opcode implementations that are a bit long
// GET_STATIC opcode // GET_STATIC opcode
pub(crate) fn get_static(this_class: &Class, field_index: u16) -> Result<Value, Error> { pub(crate) fn get_static(this_class: ClassId, field_index: u16) -> Result<Value, Error> {
let classdef = classmanager::get_classdef(&this_class.id); let classdef = classmanager::get_classdef(this_class);
let (class_index, field_name_and_type_index) = let (class_index, field_name_and_type_index) =
classdef.cp_field_ref(&field_index); // all these unwraps are safe as long as the class is valid classdef.cp_field_ref(&field_index); // all these unwraps are safe as long as the class is valid
let (name_index, _) = let (name_index, _) =
@ -73,7 +72,7 @@ pub(crate) fn get_signature_for_invoke(cp: &HashMap<u16, CpEntry>, index: u16) -
} }
/// LDC in all varieties (LDC, LDC_W, LDC2_W) /// LDC in all varieties (LDC, LDC_W, LDC2_W)
pub(crate) fn load_constant(cp_index: &u16, method: &Method, stackframes: &mut Vec<StackFrame>, this_class: &Class){ pub(crate) fn load_constant(cp_index: &u16, method: &Method, stackframes: &mut Vec<StackFrame>, this_class: ClassId){
let c = method.constant_pool.get(cp_index).unwrap(); let c = method.constant_pool.get(cp_index).unwrap();
match c { match c {
CpEntry::Integer(i) => { CpEntry::Integer(i) => {
@ -87,7 +86,7 @@ pub(crate) fn load_constant(cp_index: &u16, method: &Method, stackframes: &mut V
} }
CpEntry::StringRef(utf8) => { CpEntry::StringRef(utf8) => {
//TODO //TODO
let string = classmanager::get_classdef(&this_class.id).cp_utf8(utf8); let string = classmanager::get_classdef(this_class).cp_utf8(utf8);
let string: Vec<u8> = string.as_bytes().into(); let string: Vec<u8> = string.as_bytes().into();
classmanager::load_class_by_name("java/lang/String"); classmanager::load_class_by_name("java/lang/String");
let stringclass = classmanager::get_class_by_name("java/lang/String").unwrap(); let stringclass = classmanager::get_class_by_name("java/lang/String").unwrap();
@ -102,7 +101,7 @@ pub(crate) fn load_constant(cp_index: &u16, method: &Method, stackframes: &mut V
current_frame(stackframes).push(Value::I64(*l)); current_frame(stackframes).push(Value::I64(*l));
} }
CpEntry::ClassRef(utf8_index) => { CpEntry::ClassRef(utf8_index) => {
let classdef = classmanager::get_classdef(&this_class.id); let classdef = classmanager::get_classdef(this_class);
let class_name = classdef.cp_utf8(utf8_index); let class_name = classdef.cp_utf8(utf8_index);
classmanager::load_class_by_name(class_name); classmanager::load_class_by_name(class_name);
let klass_id = classmanager::get_classid(class_name); let klass_id = classmanager::get_classid(class_name);

View file

@ -5,12 +5,12 @@ use std::rc::Rc;
use anyhow::Error; use anyhow::Error;
use log::debug; use log::debug;
use crate::class::{Class, Object, ObjectRef, Value}; use crate::class::{Class, ClassId, Object, ObjectRef, Value};
use crate::class::Value::{F32, F64, I32, I64, Null, Ref, Void}; use crate::class::Value::{F32, F64, I32, I64, Null, Ref, Void};
use crate::classloader::classdef::{AttributeType, Modifier}; use crate::classloader::classdef::{AttributeType, Modifier};
use crate::classloader::io::{read_u16, read_u8}; use crate::classloader::io::{read_u16, read_u8};
use crate::classmanager; use crate::classmanager;
use crate::classmanager::get_class_by_id; use crate::classmanager::{get_class_by_id, get_classid};
use crate::vm::array::{array_load, array_store}; use crate::vm::array::{array_load, array_store};
use crate::vm::native::invoke_native; use crate::vm::native::invoke_native;
use crate::vm::opcodes; use crate::vm::opcodes;
@ -52,6 +52,7 @@ impl Vm {
fn init(vm: &mut Vm, stack: &mut Vec<StackFrame>) { fn init(vm: &mut Vm, stack: &mut Vec<StackFrame>) {
classmanager::load_class_by_name("java/lang/Class"); classmanager::load_class_by_name("java/lang/Class");
classmanager::load_class_by_name("jdk/internal/misc/Unsafe");
vm.execute_static(stack, "java/lang/System", "initPhase1()V", vec![]).expect("cannot create VM"); vm.execute_static(stack, "java/lang/System", "initPhase1()V", vec![]).expect("cannot create VM");
} }
@ -71,12 +72,12 @@ impl Vm {
if let Ref(this) = &args[0] { if let Ref(this) = &args[0] {
if let ObjectRef::Object(this) = this { if let ObjectRef::Object(this) = this {
let thisb= this.borrow(); let thisb= this.borrow();
let cd = classmanager::get_classdef(&thisb.class_id); let cd = classmanager::get_classdef(thisb.class_id);
let method = cd.get_method(method_name); let method = cd.get_method(method_name);
if let Some(method) = method { if let Some(method) = method {
classmanager::load_class_by_name(class_name); classmanager::load_class_by_name(class_name);
let class = classmanager::get_class_by_name(class_name).unwrap(); let class = classmanager::get_class_by_name(class_name).unwrap();
return self.execute_class(stack, class, method.name().as_str(), args.clone()); return self.execute_class(stack, class.id, method.name().as_str(), args.clone());
} else { } else {
let name = classmanager::classdef_name(&this.borrow().class_id); let name = classmanager::classdef_name(&this.borrow().class_id);
if let Some(name) = name { if let Some(name) = name {
@ -84,10 +85,9 @@ impl Vm {
let class = classmanager::get_class_by_name(&name).unwrap(); let class = classmanager::get_class_by_name(&name).unwrap();
for parent_id in &class.parents { for parent_id in &class.parents {
let classdef = classmanager::get_classdef(parent_id); let classdef = classmanager::get_classdef(*parent_id);
if classdef.has_method(method_name) { if classdef.has_method(method_name) {
let class= get_class_by_id(parent_id).unwrap(); return self.execute_class(stack, *parent_id, method_name, args.clone());
return self.execute_class(stack, class, method_name, args.clone());
} }
} }
} else { } else {
@ -96,7 +96,7 @@ impl Vm {
} }
} else if let ObjectRef::Class(_class) = this { // special case for Class ? } else if let ObjectRef::Class(_class) = this { // special case for Class ?
let klazz = classmanager::get_class_by_name("java/lang/Class").unwrap(); let klazz = classmanager::get_class_by_name("java/lang/Class").unwrap();
return self.execute_class(stack, klazz, method_name, args); return self.execute_class(stack, klazz.id, method_name, args);
} }
} }
panic!("Method {} not found in class {}", method_name, class_name); panic!("Method {} not found in class {}", method_name, class_name);
@ -110,8 +110,8 @@ impl Vm {
args: Vec<Value>, args: Vec<Value>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
classmanager::load_class_by_name(class_name); classmanager::load_class_by_name(class_name);
let class = classmanager::get_class_by_name(class_name).unwrap(); let classid = classmanager::get_classid(class_name);
self.execute_class(stack, class, method_name, args) self.execute_class(stack, classid, method_name, args)
} }
pub fn execute_static( pub fn execute_static(
@ -122,28 +122,28 @@ impl Vm {
args: Vec<Value>, args: Vec<Value>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
classmanager::load_class_by_name(class_name); classmanager::load_class_by_name(class_name);
let class = classmanager::get_class_by_name(class_name).unwrap(); self.execute_class(stack, get_classid(class_name), method_name, args)
self.execute_class(stack, class, method_name, args)
} }
pub fn execute_class( pub fn execute_class(
&mut self, &mut self,
stackframes: &mut Vec<StackFrame>, stackframes: &mut Vec<StackFrame>,
this_class: &Class, this_class: ClassId,
method_name: &str, method_name: &str,
args: Vec<Value>, args: Vec<Value>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
debug!("execute {}.{}", this_class.name, method_name); let this_class_name = &get_class_by_id(this_class).unwrap().name;
debug!("execute {}.{}", this_class_name, method_name);
//TODO implement dynamic dispatch -> get method from instance //TODO implement dynamic dispatch -> get method from instance
let method = classmanager::get_classdef(&this_class.id).get_method(method_name).unwrap(); let method = classmanager::get_classdef(this_class).get_method(method_name).unwrap();
let mut local_params: Vec<Option<Value>> = let mut local_params: Vec<Option<Value>> =
args.clone().iter().map(|e| Some(e.clone())).collect(); args.clone().iter().map(|e| Some(e.clone())).collect();
if method.is(Modifier::Native) { if method.is(Modifier::Native) {
return invoke_native(self, stackframes, &this_class.name, method_name, args); return invoke_native(self, stackframes, this_class_name, method_name, args);
} }
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() { if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
let stackframe = StackFrame::new(&this_class.name, method_name); let stackframe = StackFrame::new(&this_class_name, method_name);
stackframes.push(stackframe); stackframes.push(stackframe);
let pc = &mut 0; let pc = &mut 0;
@ -151,6 +151,7 @@ impl Vm {
let opcode = read_u8(&code.opcodes, pc); let opcode = read_u8(&code.opcodes, pc);
let cur_frame = current_frame(stackframes); let cur_frame = current_frame(stackframes);
debug!("\t{} #{} {} - {:?}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.data); debug!("\t{} #{} {} - {:?}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.data);
debug!("id {}", this_class);
match opcode { match opcode {
ACONST_NULL => { ACONST_NULL => {
current_frame(stackframes).push(Value::Null); current_frame(stackframes).push(Value::Null);
@ -337,7 +338,7 @@ impl Vm {
current_frame(stackframes).push(field_value); current_frame(stackframes).push(field_value);
} }
PUTSTATIC => { PUTSTATIC => {
let classdef = classmanager::get_classdef(&this_class.id); let classdef = classmanager::get_classdef(this_class);
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
let (class_index, field_name_and_type_index) = let (class_index, field_name_and_type_index) =
classdef.cp_field_ref(&cp_index); // all these unwraps are safe as long as the class is valid classdef.cp_field_ref(&cp_index); // all these unwraps are safe as long as the class is valid
@ -354,10 +355,10 @@ impl Vm {
.unwrap() .unwrap()
.index; .index;
let value = current_frame(stackframes).pop()?; let value = current_frame(stackframes).pop()?;
classmanager::set_static(&this_class.id, val_index, value); classmanager::set_static(this_class, val_index, value);
} }
GETFIELD => { GETFIELD => {
let classdef = classmanager::get_classdef(&this_class.id); let classdef = classmanager::get_classdef(this_class);
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
let (class_index, field_name_and_type_index) = let (class_index, field_name_and_type_index) =
classdef.cp_field_ref(&cp_index); classdef.cp_field_ref(&cp_index);
@ -371,7 +372,7 @@ impl Vm {
let objectref = current_frame(stackframes).pop()?; let objectref = current_frame(stackframes).pop()?;
if let Ref(instance) = objectref { if let Ref(instance) = objectref {
if let ObjectRef::Object(object) = instance { if let ObjectRef::Object(object) = instance {
let runtime_type = classmanager::get_class_by_id(&object.borrow().class_id).unwrap(); let runtime_type = classmanager::get_class_by_id(object.borrow().class_id).unwrap();
let object = object.borrow(); let object = object.borrow();
let value = object.get(runtime_type, declared_type, field_name); let value = object.get(runtime_type, declared_type, field_name);
current_frame(stackframes).push(value.clone()); current_frame(stackframes).push(value.clone());
@ -383,7 +384,7 @@ impl Vm {
} }
} }
PUTFIELD => { PUTFIELD => {
let classdef = classmanager::get_classdef(&this_class.id); let classdef = classmanager::get_classdef(this_class);
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
let (class_index, field_name_and_type_index) = let (class_index, field_name_and_type_index) =
classdef.cp_field_ref(&cp_index); classdef.cp_field_ref(&cp_index);
@ -397,47 +398,13 @@ impl Vm {
let objectref = current_frame(stackframes).pop()?; let objectref = current_frame(stackframes).pop()?;
if let Ref(instance) = objectref { if let Ref(instance) = objectref {
if let ObjectRef::Object(object) = instance { if let ObjectRef::Object(object) = instance {
let runtime_type = classmanager::get_class_by_id(&object.borrow().class_id).unwrap(); let runtime_type = classmanager::get_class_by_id(object.borrow().class_id).unwrap();
object.borrow_mut().set(runtime_type, declared_type, field_name, value); object.borrow_mut().set(runtime_type, declared_type, field_name, value);
} }
} else { } else {
unreachable!() unreachable!()
} }
} }
INVOKESPECIAL => {
// TODO differentiate these opcodes
let cp_index = read_u16(&code.opcodes, pc);
if let Some(invocation) =
get_signature_for_invoke(&method.constant_pool, cp_index)
{
debug!("invoke {:?}", invocation);
let mut args = Vec::with_capacity(invocation.method.num_args);
for _ in 0..invocation.method.num_args {
args.insert(0, current_frame(stackframes).pop()?.clone());
}
args.insert(0, current_frame(stackframes).pop()?);
let return_value = self.execute_special(stackframes,
&invocation.class_name,
&invocation.method.name,
args,
)?;
if let Ref(objectref) = &return_value {
if let ObjectRef::Object(object) = objectref {
debug!("return {:?}", object);
}
} else {
debug!("return {:?}", return_value);
}
match return_value {
Void => {}
_ => {
current_frame(stackframes).push(return_value.clone());
}
}
} else {
unreachable!()
}
}
INVOKEVIRTUAL => { INVOKEVIRTUAL => {
// TODO differentiate these opcodes // TODO differentiate these opcodes
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
@ -473,6 +440,44 @@ impl Vm {
unreachable!() unreachable!()
} }
} }
INVOKESPECIAL => {
// TODO differentiate these opcodes
let cp_index = read_u16(&code.opcodes, pc);
if let Some(invocation) =
get_signature_for_invoke(&method.constant_pool, cp_index)
{
debug!("id before new {}", this_class);
let mut args = Vec::with_capacity(invocation.method.num_args);
for _ in 0..invocation.method.num_args {
args.insert(0, current_frame(stackframes).pop()?.clone());
}
args.insert(0, current_frame(stackframes).pop()?);
debug!("invoke special{:?}", invocation);
let return_value = self.execute_special(stackframes,
&invocation.class_name,
&invocation.method.name,
args,
)?;
// let return_value = Null;
debug!("id after new {}", this_class);
if let Ref(objectref) = &return_value {
if let ObjectRef::Object(object) = objectref {
debug!("return {:?}", object);
}
} else {
debug!("return {:?}", return_value);
}
match return_value {
Void => {}
_ => {
current_frame(stackframes).push(return_value.clone());
}
}
} else {
unreachable!()
}
}
INVOKESTATIC => { INVOKESTATIC => {
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
if let Some(invocation) = if let Some(invocation) =
@ -505,7 +510,7 @@ impl Vm {
} }
} }
NEW => { NEW => {
let classdef = classmanager::get_classdef(&this_class.id); let classdef = classmanager::get_classdef(this_class);
let class_index = &read_u16(&code.opcodes, pc); let class_index = &read_u16(&code.opcodes, pc);
let class_name_index = classdef.cp_class_ref(class_index); let class_name_index = classdef.cp_class_ref(class_index);
let class_name = classdef.cp_utf8(class_name_index); let class_name = classdef.cp_utf8(class_name_index);
@ -524,7 +529,7 @@ impl Vm {
current_frame(stackframes).push(Ref(array)); current_frame(stackframes).push(Ref(array));
} }
ANEWARRAY => { ANEWARRAY => {
let classdef = classmanager::get_classdef(&this_class.id); let classdef = classmanager::get_classdef(this_class);
let class_index = &read_u16(&code.opcodes, pc); let class_index = &read_u16(&code.opcodes, pc);
let class_name_index = classdef.cp_class_ref(class_index); let class_name_index = classdef.cp_class_ref(class_index);
let class_name = classdef.cp_utf8(class_name_index); let class_name = classdef.cp_utf8(class_name_index);