fixed segv

This commit is contained in:
Shautvast 2023-10-17 14:34:34 +02:00
parent 7219893978
commit 3ce9ce10b4
5 changed files with 106 additions and 40 deletions

View file

@ -28,7 +28,8 @@ pub fn get_class(vm: &mut Vm, calling_class_name: Option<&str>, class_name: &str
// not pretty...sorry // not pretty...sorry
if let Some(calling_class_name) = calling_class_name { if let Some(calling_class_name) = calling_class_name {
if class_name == calling_class_name { // works around the situation that static initializer needs a ref to the class it's in if class_name == calling_class_name { // works around the situation that static initializer needs a ref to the class it's in
return Ok(CLASSDEFS.get(class_name.into()).unwrap().clone()); // in that case the class is guaranteed to be here panic!();
// return Ok(CLASSDEFS.get(class_name.into()).unwrap().clone()); // in that case the class is guaranteed to be here
} }
} }
@ -42,6 +43,8 @@ pub fn get_class(vm: &mut Vm, calling_class_name: Option<&str>, class_name: &str
if let Some(super_class_name) = super_class_name { if let Some(super_class_name) = super_class_name {
if let Ok(super_class) = get_class(vm, Some(class_name), &super_class_name) { if let Ok(super_class) = get_class(vm, Some(class_name), &super_class_name) {
class.super_class = Some(super_class); class.super_class = Some(super_class);
} else {
unreachable!()
} }
} }
@ -57,11 +60,16 @@ pub fn get_class(vm: &mut Vm, calling_class_name: Option<&str>, class_name: &str
// the problem is pretty fundamental: method (clinit) should be called before the class is returned, // the problem is pretty fundamental: method (clinit) should be called before the class is returned,
// but the executing code needs a reference to itself. So get_class is called recursively, but clinit must be called exactly once! // but the executing code needs a reference to itself. So get_class is called recursively, but clinit must be called exactly once!
// putting the call to clinit in the closure above is way nicer, but the signature change (wrap it in Arc<RefCell>) // putting the call to clinit in the closure above is way nicer, but the signature change (wrap it in Arc<RefCell>)
if new_class.borrow().methods.contains_key("<clinit>()V") { //update: this is probably not needed anymore because of the check in PUTSTATIC
//somehow this clone needs to be there before clinit is called, even though the newclass ref remains in scope
let clone = new_class.clone();
if new_class.clone().borrow().methods.contains_key("<clinit>()V") {
vm.execute_class(new_class.clone(), "<clinit>()V", vec![]).unwrap(); vm.execute_class(new_class.clone(), "<clinit>()V", vec![]).unwrap();
} }
Ok(new_class.clone()) Ok(clone)
} }
} }
@ -125,11 +133,11 @@ impl Class {
} }
pub(crate) fn n_object_fields(&self) -> usize { pub(crate) fn n_object_fields(&self) -> usize {
self.object_field_mapping.iter().map(|(_,v)|v.len()).reduce(|acc, e| acc + e).unwrap() self.object_field_mapping.iter().map(|(_, v)| v.len()).reduce(|acc, e| acc + e).unwrap()
} }
pub(crate) fn n_static_fields(&self) -> usize { pub(crate) fn n_static_fields(&self) -> usize {
self.static_field_mapping.iter().map(|(_,v)|v.len()).reduce(|acc, e| acc + e).unwrap() self.static_field_mapping.iter().map(|(_, v)| v.len()).reduce(|acc, e| acc + e).unwrap()
} }
// Create a mapping per field(name) to an index in the storage vector that contains the instance data. // Create a mapping per field(name) to an index in the storage vector that contains the instance data.
@ -194,7 +202,6 @@ impl Class {
); //name => (type,index) ); //name => (type,index)
*object_field_map_index += 1; *object_field_map_index += 1;
} }
} }
(this_fields, static_fields) (this_fields, static_fields)
} }
@ -242,7 +249,7 @@ impl Class {
"D" => Value::F64(0.0), "D" => Value::F64(0.0),
_ => Value::Null, _ => Value::Null,
}; };
println!("{} = {:?}", name, value ); println!("{} = {:?}", name, value);
field_data[*index] = Some(value.into()); field_data[*index] = Some(value.into());
} }
} }
@ -540,7 +547,7 @@ pub enum Value {
BOOL(bool), BOOL(bool),
CHAR(char), CHAR(char),
Ref(Arc<UnsafeCell<ObjectRef>>), Ref(Arc<UnsafeCell<ObjectRef>>),
Utf8(String) Utf8(String),
} }
impl Value { impl Value {

View file

@ -1,12 +1,12 @@
use std::cell::{RefCell, UnsafeCell}; use std::cell::{RefCell, UnsafeCell};
use std::fmt; use std::fmt;
use std::fmt::{Debug, Formatter};
use std::sync::Arc; use std::sync::Arc;
use crate::class::{Class, Type, UnsafeValue, Value}; use crate::class::{Class, Type, UnsafeValue, Value};
use crate::heap::ObjectRef::{IntArray, ObjectArray}; use crate::heap::ObjectRef::{IntArray, ObjectArray};
// can contain object or array // can contain object or array
#[derive(Debug)]
pub enum ObjectRef { pub enum ObjectRef {
ByteArray(Vec<i8>), ByteArray(Vec<i8>),
ShortArray(Vec<i16>), ShortArray(Vec<i16>),
@ -30,6 +30,23 @@ impl ObjectRef {
} }
} }
impl Debug for ObjectRef{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
ObjectRef::BooleanArray(d) => write!(f, "[Z;{}]", d.len()),
ObjectRef::ByteArray(d) => write!(f, "[B;{}]", d.len()),
ObjectRef::CharArray(d) => write!(f, "[C;{}]", d.len()),
ObjectRef::DoubleArray(d) => write!(f, "[D;{}]", d.len()),
ObjectRef::FloatArray(d) => write!(f, "[F;{}]", d.len()),
ObjectRef::IntArray(d) => write!(f, "[I;{}]", d.len()),
ObjectRef::LongArray(d) => write!(f, "[J;{}]", d.len()),
ObjectRef::ObjectArray(t, d) => write!(f,"[L{};{}]", t.borrow().name,d.len()),
ObjectRef::ShortArray( d) => write!(f, "[S;{}]", d.len()),
ObjectRef::Object( r) => write!(f,"{}{{ {:?} }}", r.class.borrow().name, r.data),
}
}
}
// trying to implement efficient object instance storage // trying to implement efficient object instance storage
pub struct Object { pub struct Object {
// locked: bool, // locked: bool,

View file

@ -15,7 +15,7 @@ use crate::native::invoke_native;
use crate::opcodes::*; use crate::opcodes::*;
#[derive(Debug)] #[derive(Debug)]
struct StackFrame { pub(crate) struct StackFrame {
at: String, at: String,
data: Vec<UnsafeValue>, data: Vec<UnsafeValue>,
} }
@ -50,7 +50,7 @@ impl StackFrame {
pub struct Vm { pub struct Vm {
pub classpath: Vec<String>, pub classpath: Vec<String>,
heap: Heap, heap: Heap,
stackframes: Vec<StackFrame>, pub(crate) stackframes: Vec<StackFrame>,
} }
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
@ -133,6 +133,7 @@ impl Vm {
self.current_frame().push(Value::I32(0)); self.current_frame().push(Value::I32(0));
} }
ICONST_1 => { ICONST_1 => {
println!("ICONST_1");
self.current_frame().push(Value::I32(1)); self.current_frame().push(Value::I32(1));
} }
ICONST_2 => { ICONST_2 => {
@ -218,7 +219,7 @@ impl Vm {
self.current_frame().push(Value::F32(*f)); self.current_frame().push(Value::F32(*f));
} }
_ => { _ => {
panic!("unexpected") unreachable!()
} }
} }
} }
@ -233,7 +234,7 @@ impl Vm {
self.current_frame().push(Value::I64(*l)); self.current_frame().push(Value::I64(*l));
} }
_ => { _ => {
panic!("unexpected") unreachable!()
} }
} }
} }
@ -342,6 +343,16 @@ impl Vm {
let value = self.current_frame().pop()?; let value = self.current_frame().pop()?;
borrow.static_data[*val_index] = Some(value); borrow.static_data[*val_index] = Some(value);
} }
unsafe {
for v in &borrow.static_data {
let v = &*v.as_ref().unwrap().get();
if let Value::Ref(vv) = v {
println!("{:?}", &*vv.get())
} else {
println!("{:?}", *v);
}
}
}
} }
GETFIELD => unsafe { GETFIELD => unsafe {
let borrow = this_class.borrow(); let borrow = this_class.borrow();
@ -359,7 +370,11 @@ impl Vm {
if let ObjectRef::Object(ref mut object) = &mut *instance.get() { if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
let value = object.get(class_name, field_name); let value = object.get(class_name, field_name);
self.current_frame().push_arc(Arc::clone(value)); self.current_frame().push_arc(Arc::clone(value));
} else {
unreachable!()
} }
} else {
unreachable!()
} }
}, },
PUTFIELD => unsafe { PUTFIELD => unsafe {
@ -379,6 +394,8 @@ impl Vm {
if let ObjectRef::Object(ref mut object) = &mut *instance.get() { if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
object.set(class_name, field_name, value); object.set(class_name, field_name, value);
} }
} else {
unreachable!()
} }
}, },
INVOKEVIRTUAL | INVOKESPECIAL => unsafe { INVOKEVIRTUAL | INVOKESPECIAL => unsafe {
@ -406,6 +423,8 @@ impl Vm {
} }
} }
println!("stack {} at {}", self.current_frame().len(), self.current_frame().at) println!("stack {} at {}", self.current_frame().len(), self.current_frame().at)
} else {
unreachable!()
} }
}, },
INVOKESTATIC => unsafe { INVOKESTATIC => unsafe {
@ -429,6 +448,8 @@ impl Vm {
self.current_frame().push_arc(returnvalue.clone()); self.current_frame().push_arc(returnvalue.clone());
} }
} }
} else {
unreachable!()
} }
}, },
NEW => { NEW => {
@ -445,7 +466,7 @@ impl Vm {
self.current_frame().push(Value::Ref(Arc::clone(&object))); self.current_frame().push(Value::Ref(Arc::clone(&object)));
self.heap.new_object(object); self.heap.new_object(object);
} }
ANEWARRAY => unsafe{ ANEWARRAY => unsafe {
println!("ANEWARRAY"); println!("ANEWARRAY");
let class_index = &read_u16(&code.opcodes, pc); let class_index = &read_u16(&code.opcodes, pc);
let borrow = this_class.borrow(); let borrow = this_class.borrow();
@ -453,17 +474,16 @@ impl Vm {
let class_name = borrow.cp_utf8(class_name_index).unwrap(); let class_name = borrow.cp_utf8(class_name_index).unwrap();
let arraytype = get_class(self, Some(&borrow.name), class_name)?; let arraytype = get_class(self, Some(&borrow.name), class_name)?;
let count = self.current_frame().pop()?; let count = self.current_frame().pop()?;
if let Value::I32(count) = *count.get(){ // why does pop()?.get() give weird results? if let Value::I32(count) = *count.get() { // why does pop()?.get() give weird results?
let array = ObjectRef::new_object_array(arraytype, count as usize); let array = ObjectRef::new_object_array(arraytype, count as usize);
let array = Arc::new(UnsafeCell::new(array)); let array = Arc::new(UnsafeCell::new(array));
self.current_frame().push(Value::Ref(Arc::clone(&array))); self.current_frame().push(Value::Ref(Arc::clone(&array)));
println!("{}",self.current_frame().len()); println!("{}", self.current_frame().len());
self.heap.new_object(array); self.heap.new_object(array);
} else { } else {
panic!(); panic!();
} }
} }
//TODO implement all opcodes //TODO implement all opcodes
@ -478,43 +498,45 @@ impl Vm {
} }
unsafe fn array_load(&mut self) -> Result<(), Error> { unsafe fn array_load(&mut self) -> Result<(), Error> {
if let Value::I32(index) = &*self.current_frame().pop()?.get() { let value = self.current_frame().pop()?;
if let Value::I32(index) = &*value.get() {
let index = *index as usize; let index = *index as usize;
let arrayref = &*self.current_frame().pop()?.get(); let arrayref = self.current_frame().pop()?;
if let Value::Null = arrayref { if let Value::Null = &*arrayref.get() {
return Err(anyhow!("NullpointerException")); return Err(anyhow!("NullpointerException"));
} }
if let Value::Ref(ref objectref) = arrayref { if let Value::Ref(objectref) = &*arrayref.get() {
match &*objectref.get() { match &*objectref.get() {
ObjectRef::ByteArray(ref array) => { ObjectRef::ByteArray(array) => {
self.current_frame().push(Value::I32(array[index] as i32)); self.current_frame().push(Value::I32(array[index] as i32));
} }
ObjectRef::ShortArray(ref array) => { ObjectRef::ShortArray(array) => {
self.current_frame().push(Value::I32(array[index] as i32)); self.current_frame().push(Value::I32(array[index] as i32));
} }
ObjectRef::IntArray(ref array) => { ObjectRef::IntArray(array) => {
self.current_frame().push(Value::I32(array[index])); self.current_frame().push(Value::I32(array[index]));
} }
ObjectRef::BooleanArray(ref array) => { ObjectRef::BooleanArray(array) => {
self.current_frame().push(Value::I32(array[index] as i32)); self.current_frame().push(Value::I32(array[index] as i32));
} }
ObjectRef::CharArray(ref array) => { ObjectRef::CharArray(array) => {
self.current_frame().push(Value::CHAR(array[index])); self.current_frame().push(Value::CHAR(array[index]));
} }
ObjectRef::LongArray(ref array) => { ObjectRef::LongArray(array) => {
self.current_frame().push(Value::I64(array[index])); self.current_frame().push(Value::I64(array[index]));
} }
ObjectRef::FloatArray(ref array) => { ObjectRef::FloatArray(array) => {
self.current_frame().push(Value::F32(array[index])); self.current_frame().push(Value::F32(array[index]));
} }
ObjectRef::DoubleArray(ref array) => { ObjectRef::DoubleArray(array) => {
self.current_frame().push(Value::F64(array[index])); self.current_frame().push(Value::F64(array[index]));
} }
ObjectRef::ObjectArray(_arraytype, ref data) => { ObjectRef::ObjectArray(_arraytype, data) => {
self.current_frame() self.current_frame()
.push(Value::Ref(data[index].clone())); .push(Value::Ref(data[index].clone()));
} }
ObjectRef::Object(_) => {} //throw error? ObjectRef::Object(_) => { panic!("should be array") } //throw error?
} }
} }
} }
@ -523,66 +545,86 @@ impl Vm {
unsafe fn array_store(&mut self) -> Result<(), Error> { unsafe fn array_store(&mut self) -> Result<(), Error> {
let value = self.current_frame().pop()?; let value = self.current_frame().pop()?;
let index = &mut *self.current_frame().pop()?.get(); let index = &*self.current_frame().pop()?;
let mut arrayref = &mut *self.current_frame().pop()?.get(); let mut arrayref = &mut self.current_frame().pop()?;
if let Value::Null = arrayref { if let Value::Null = &*arrayref.get() {
return Err(anyhow!("NullpointerException")); return Err(anyhow!("NullpointerException"));
} }
if let Value::I32(index) = index { if let Value::I32(index) = &*index.get() {
if let Value::Ref(ref mut objectref) = arrayref { if let Value::Ref(ref mut objectref) = &mut *arrayref.get() {
match &mut *objectref.get() { match &mut *objectref.get() {
ObjectRef::ByteArray(ref mut array) => { ObjectRef::ByteArray(ref mut array) => {
if let Value::I32(value) = *value.get() { if let Value::I32(value) = *value.get() {
// is i32 correct? // is i32 correct?
array[*index as usize] = value as i8; array[*index as usize] = value as i8;
} else {
unreachable!()
} }
} }
ObjectRef::ShortArray(ref mut array) => { ObjectRef::ShortArray(ref mut array) => {
if let Value::I32(value) = *value.get() { if let Value::I32(value) = *value.get() {
// is i32 correct? // is i32 correct?
array[*index as usize] = value as i16; array[*index as usize] = value as i16;
} else {
unreachable!()
} }
} }
ObjectRef::IntArray(ref mut array) => { ObjectRef::IntArray(ref mut array) => {
if let Value::I32(value) = *value.get() { if let Value::I32(value) = *value.get() {
array[*index as usize] = value; array[*index as usize] = value;
} else {
unreachable!()
} }
} }
ObjectRef::BooleanArray(ref mut array) => { ObjectRef::BooleanArray(ref mut array) => {
if let Value::I32(value) = *value.get() { if let Value::I32(value) = *value.get() {
array[*index as usize] = value > 0; array[*index as usize] = value > 0;
} else {
unreachable!()
} }
} }
ObjectRef::CharArray(ref mut array) => { ObjectRef::CharArray(ref mut array) => {
if let Value::I32(value) = *value.get() { if let Value::I32(value) = *value.get() {
array[*index as usize] = char::from_u32_unchecked(value as u32); array[*index as usize] = char::from_u32_unchecked(value as u32);
} else {
unreachable!()
} }
} }
ObjectRef::LongArray(ref mut array) => { ObjectRef::LongArray(ref mut array) => {
if let Value::I64(value) = *value.get() { if let Value::I64(value) = *value.get() {
array[*index as usize] = value; array[*index as usize] = value;
} else {
unreachable!()
} }
} }
ObjectRef::FloatArray(ref mut array) => { ObjectRef::FloatArray(ref mut array) => {
if let Value::F32(value) = *value.get() { if let Value::F32(value) = *value.get() {
array[*index as usize] = value array[*index as usize] = value
} else {
unreachable!()
} }
} }
ObjectRef::DoubleArray(ref mut array) => { ObjectRef::DoubleArray(ref mut array) => {
if let Value::F64(value) = *value.get() { if let Value::F64(value) = *value.get() {
array[*index as usize] = value array[*index as usize] = value
} else {
unreachable!()
} }
} }
ObjectRef::ObjectArray(arraytype, ref mut array) => { ObjectRef::ObjectArray(arraytype, ref mut array) => {
if let Value::Ref(ref value) = *value.get() { if let Value::Ref(ref value) = *value.get() {
array[*index as usize] = value.clone(); array[*index as usize] = value.clone();
} else {
unreachable!()
} }
} }
ObjectRef::Object(_) => {} //throw error? ObjectRef::Object(_) => {} //throw error?
} }
} }
} else {
unreachable!()
} }
Ok(()) Ok(())
} }

Binary file not shown.

View file

@ -1,14 +1,14 @@
public class Main { public class Main {
final static int a; final static String a;
static{ static{
a=1; a="";
} }
public static void main(String[] args){ public static void main(String[] args){
FloatBean f = new FloatBean(); FloatBean f = new FloatBean();
f.setValue(42F); f.setValue(42F);
System.out.println(a);
} }
} }