fixed segv
This commit is contained in:
parent
7219893978
commit
3ce9ce10b4
5 changed files with 106 additions and 40 deletions
23
src/class.rs
23
src/class.rs
|
|
@ -28,7 +28,8 @@ pub fn get_class(vm: &mut Vm, calling_class_name: Option<&str>, class_name: &str
|
|||
// not pretty...sorry
|
||||
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
|
||||
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 Ok(super_class) = get_class(vm, Some(class_name), &super_class_name) {
|
||||
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,
|
||||
// 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>)
|
||||
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();
|
||||
}
|
||||
|
||||
Ok(new_class.clone())
|
||||
Ok(clone)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,11 +133,11 @@ impl Class {
|
|||
}
|
||||
|
||||
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 {
|
||||
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.
|
||||
|
|
@ -194,7 +202,6 @@ impl Class {
|
|||
); //name => (type,index)
|
||||
*object_field_map_index += 1;
|
||||
}
|
||||
|
||||
}
|
||||
(this_fields, static_fields)
|
||||
}
|
||||
|
|
@ -242,7 +249,7 @@ impl Class {
|
|||
"D" => Value::F64(0.0),
|
||||
_ => Value::Null,
|
||||
};
|
||||
println!("{} = {:?}", name, value );
|
||||
println!("{} = {:?}", name, value);
|
||||
field_data[*index] = Some(value.into());
|
||||
}
|
||||
}
|
||||
|
|
@ -540,7 +547,7 @@ pub enum Value {
|
|||
BOOL(bool),
|
||||
CHAR(char),
|
||||
Ref(Arc<UnsafeCell<ObjectRef>>),
|
||||
Utf8(String)
|
||||
Utf8(String),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
|
|
|
|||
19
src/heap.rs
19
src/heap.rs
|
|
@ -1,12 +1,12 @@
|
|||
use std::cell::{RefCell, UnsafeCell};
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::class::{Class, Type, UnsafeValue, Value};
|
||||
use crate::heap::ObjectRef::{IntArray, ObjectArray};
|
||||
|
||||
// can contain object or array
|
||||
#[derive(Debug)]
|
||||
pub enum ObjectRef {
|
||||
ByteArray(Vec<i8>),
|
||||
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
|
||||
pub struct Object {
|
||||
// locked: bool,
|
||||
|
|
|
|||
98
src/vm.rs
98
src/vm.rs
|
|
@ -15,7 +15,7 @@ use crate::native::invoke_native;
|
|||
use crate::opcodes::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct StackFrame {
|
||||
pub(crate) struct StackFrame {
|
||||
at: String,
|
||||
data: Vec<UnsafeValue>,
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ impl StackFrame {
|
|||
pub struct Vm {
|
||||
pub classpath: Vec<String>,
|
||||
heap: Heap,
|
||||
stackframes: Vec<StackFrame>,
|
||||
pub(crate) stackframes: Vec<StackFrame>,
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
|
|
@ -133,6 +133,7 @@ impl Vm {
|
|||
self.current_frame().push(Value::I32(0));
|
||||
}
|
||||
ICONST_1 => {
|
||||
println!("ICONST_1");
|
||||
self.current_frame().push(Value::I32(1));
|
||||
}
|
||||
ICONST_2 => {
|
||||
|
|
@ -218,7 +219,7 @@ impl Vm {
|
|||
self.current_frame().push(Value::F32(*f));
|
||||
}
|
||||
_ => {
|
||||
panic!("unexpected")
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -233,7 +234,7 @@ impl Vm {
|
|||
self.current_frame().push(Value::I64(*l));
|
||||
}
|
||||
_ => {
|
||||
panic!("unexpected")
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -342,6 +343,16 @@ impl Vm {
|
|||
let value = self.current_frame().pop()?;
|
||||
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 {
|
||||
let borrow = this_class.borrow();
|
||||
|
|
@ -359,7 +370,11 @@ impl Vm {
|
|||
if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
|
||||
let value = object.get(class_name, field_name);
|
||||
self.current_frame().push_arc(Arc::clone(value));
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
PUTFIELD => unsafe {
|
||||
|
|
@ -379,6 +394,8 @@ impl Vm {
|
|||
if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
|
||||
object.set(class_name, field_name, value);
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
INVOKEVIRTUAL | INVOKESPECIAL => unsafe {
|
||||
|
|
@ -406,6 +423,8 @@ impl Vm {
|
|||
}
|
||||
}
|
||||
println!("stack {} at {}", self.current_frame().len(), self.current_frame().at)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
INVOKESTATIC => unsafe {
|
||||
|
|
@ -429,6 +448,8 @@ impl Vm {
|
|||
self.current_frame().push_arc(returnvalue.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
NEW => {
|
||||
|
|
@ -445,7 +466,7 @@ impl Vm {
|
|||
self.current_frame().push(Value::Ref(Arc::clone(&object)));
|
||||
self.heap.new_object(object);
|
||||
}
|
||||
ANEWARRAY => unsafe{
|
||||
ANEWARRAY => unsafe {
|
||||
println!("ANEWARRAY");
|
||||
let class_index = &read_u16(&code.opcodes, pc);
|
||||
let borrow = this_class.borrow();
|
||||
|
|
@ -453,17 +474,16 @@ impl Vm {
|
|||
let class_name = borrow.cp_utf8(class_name_index).unwrap();
|
||||
let arraytype = get_class(self, Some(&borrow.name), class_name)?;
|
||||
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 = Arc::new(UnsafeCell::new(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);
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//TODO implement all opcodes
|
||||
|
|
@ -478,43 +498,45 @@ impl Vm {
|
|||
}
|
||||
|
||||
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 arrayref = &*self.current_frame().pop()?.get();
|
||||
if let Value::Null = arrayref {
|
||||
let arrayref = self.current_frame().pop()?;
|
||||
if let Value::Null = &*arrayref.get() {
|
||||
return Err(anyhow!("NullpointerException"));
|
||||
}
|
||||
if let Value::Ref(ref objectref) = arrayref {
|
||||
if let Value::Ref(objectref) = &*arrayref.get() {
|
||||
match &*objectref.get() {
|
||||
ObjectRef::ByteArray(ref array) => {
|
||||
ObjectRef::ByteArray(array) => {
|
||||
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));
|
||||
}
|
||||
ObjectRef::IntArray(ref array) => {
|
||||
ObjectRef::IntArray(array) => {
|
||||
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));
|
||||
}
|
||||
ObjectRef::CharArray(ref array) => {
|
||||
ObjectRef::CharArray(array) => {
|
||||
self.current_frame().push(Value::CHAR(array[index]));
|
||||
}
|
||||
ObjectRef::LongArray(ref array) => {
|
||||
ObjectRef::LongArray(array) => {
|
||||
self.current_frame().push(Value::I64(array[index]));
|
||||
}
|
||||
ObjectRef::FloatArray(ref array) => {
|
||||
ObjectRef::FloatArray(array) => {
|
||||
self.current_frame().push(Value::F32(array[index]));
|
||||
}
|
||||
ObjectRef::DoubleArray(ref array) => {
|
||||
ObjectRef::DoubleArray(array) => {
|
||||
self.current_frame().push(Value::F64(array[index]));
|
||||
}
|
||||
ObjectRef::ObjectArray(_arraytype, ref data) => {
|
||||
ObjectRef::ObjectArray(_arraytype, data) => {
|
||||
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> {
|
||||
let value = self.current_frame().pop()?;
|
||||
let index = &mut *self.current_frame().pop()?.get();
|
||||
let mut arrayref = &mut *self.current_frame().pop()?.get();
|
||||
let index = &*self.current_frame().pop()?;
|
||||
let mut arrayref = &mut self.current_frame().pop()?;
|
||||
|
||||
if let Value::Null = arrayref {
|
||||
if let Value::Null = &*arrayref.get() {
|
||||
return Err(anyhow!("NullpointerException"));
|
||||
}
|
||||
|
||||
if let Value::I32(index) = index {
|
||||
if let Value::Ref(ref mut objectref) = arrayref {
|
||||
if let Value::I32(index) = &*index.get() {
|
||||
if let Value::Ref(ref mut objectref) = &mut *arrayref.get() {
|
||||
match &mut *objectref.get() {
|
||||
ObjectRef::ByteArray(ref mut array) => {
|
||||
if let Value::I32(value) = *value.get() {
|
||||
// is i32 correct?
|
||||
array[*index as usize] = value as i8;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::ShortArray(ref mut array) => {
|
||||
if let Value::I32(value) = *value.get() {
|
||||
// is i32 correct?
|
||||
array[*index as usize] = value as i16;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::IntArray(ref mut array) => {
|
||||
if let Value::I32(value) = *value.get() {
|
||||
array[*index as usize] = value;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::BooleanArray(ref mut array) => {
|
||||
if let Value::I32(value) = *value.get() {
|
||||
array[*index as usize] = value > 0;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::CharArray(ref mut array) => {
|
||||
if let Value::I32(value) = *value.get() {
|
||||
array[*index as usize] = char::from_u32_unchecked(value as u32);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::LongArray(ref mut array) => {
|
||||
if let Value::I64(value) = *value.get() {
|
||||
array[*index as usize] = value;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::FloatArray(ref mut array) => {
|
||||
if let Value::F32(value) = *value.get() {
|
||||
array[*index as usize] = value
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::DoubleArray(ref mut array) => {
|
||||
if let Value::F64(value) = *value.get() {
|
||||
array[*index as usize] = value
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::ObjectArray(arraytype, ref mut array) => {
|
||||
if let Value::Ref(ref value) = *value.get() {
|
||||
array[*index as usize] = value.clone();
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::Object(_) => {} //throw error?
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
BIN
tests/Main.class
BIN
tests/Main.class
Binary file not shown.
|
|
@ -1,14 +1,14 @@
|
|||
public class Main {
|
||||
|
||||
final static int a;
|
||||
final static String a;
|
||||
|
||||
static{
|
||||
a=1;
|
||||
a="";
|
||||
}
|
||||
|
||||
public static void main(String[] args){
|
||||
FloatBean f = new FloatBean();
|
||||
f.setValue(42F);
|
||||
|
||||
System.out.println(a);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue