invalid pointer
This commit is contained in:
parent
656b6aa66a
commit
050c1821c2
3 changed files with 73 additions and 82 deletions
78
src/class.rs
78
src/class.rs
|
|
@ -1,7 +1,6 @@
|
||||||
use std::cell::{RefCell, UnsafeCell};
|
use std::cell::{RefCell, UnsafeCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::Hash;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|
@ -20,55 +19,49 @@ static mut CLASSDEFS: Lazy<HashMap<String, Arc<RefCell<Class>>>> = Lazy::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(vm: &mut Vm, calling_class_name: Option<&str>, class_name: &str) -> Result<Arc<RefCell<Class>>, Error> {
|
pub fn get_class(vm: &mut Vm, _calling_class_name: Option<&str>, class_name: &str) -> Result<Arc<RefCell<Class>>, Error> {
|
||||||
println!("get_class {}", class_name);
|
println!("get_class {}", class_name);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// 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
|
||||||
panic!();
|
// return Ok(CLASSDEFS.get(class_name.into()).unwrap().clone()); // in that case the class is guaranteed to be here
|
||||||
// return Ok(CLASSDEFS.get(class_name.into()).unwrap().clone()); // in that case the class is guaranteed to be here
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
let new_class = CLASSDEFS.entry(class_name.into()).or_insert_with(|| {
|
let class = CLASSDEFS.entry(class_name.into()).or_insert_with(|| {
|
||||||
println!("read class {} ", class_name);
|
println!("read class {} ", class_name);
|
||||||
let resolved_path = find_class(&vm.classpath, class_name).unwrap();
|
let resolved_path = find_class(&vm.classpath, class_name).unwrap();
|
||||||
// println!("full path {}", resolved_path);
|
// println!("full path {}", resolved_path);
|
||||||
let bytecode = read_bytecode(resolved_path).unwrap();
|
let bytecode = read_bytecode(resolved_path).unwrap();
|
||||||
let mut class = load_class(bytecode).unwrap();
|
let class = load_class(bytecode).unwrap();
|
||||||
let super_class_name = class.super_class_name.as_ref();
|
Arc::new(RefCell::new(class))
|
||||||
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);
|
let clone = class.clone();
|
||||||
} else {
|
let clone2 = class.clone();
|
||||||
unreachable!()
|
if !class.borrow().inited {
|
||||||
|
let super_class_name = class.borrow().super_class_name.as_ref().map(|n| n.to_owned());
|
||||||
|
{
|
||||||
|
if let Some(super_class_name) = super_class_name {
|
||||||
|
if let Ok(super_class) = get_class(vm, Some(class_name), &super_class_name) {
|
||||||
|
class.borrow_mut().super_class = Some(super_class);
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let class = Arc::new(RefCell::new(class));
|
|
||||||
Class::initialize_fields(class.clone());
|
Class::initialize_fields(class.clone());
|
||||||
class
|
let clinit = clone.borrow().methods.contains_key("<clinit>()V");
|
||||||
});
|
if clinit{
|
||||||
|
vm.execute_class(class.clone(), "<clinit>()V", vec![]).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
clone.borrow_mut().inited = true;
|
||||||
// calling clinit before the end of this function has been a PITA
|
|
||||||
// 1. infinite recursion
|
|
||||||
// panic after second borrow.
|
|
||||||
// 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>)
|
|
||||||
//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(clone2)
|
||||||
Ok(clone)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,6 +82,7 @@ pub struct Class {
|
||||||
pub fields: HashMap<String, Field>,
|
pub fields: HashMap<String, Field>,
|
||||||
pub methods: HashMap<String, Rc<Method>>,
|
pub methods: HashMap<String, Rc<Method>>,
|
||||||
pub attributes: HashMap<String, AttributeType>,
|
pub attributes: HashMap<String, AttributeType>,
|
||||||
|
pub inited: bool,
|
||||||
pub(crate) object_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
|
pub(crate) object_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
|
||||||
// first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index)
|
// first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index)
|
||||||
pub(crate) static_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
|
pub(crate) static_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
|
||||||
|
|
@ -125,6 +119,7 @@ impl Class {
|
||||||
fields,
|
fields,
|
||||||
methods,
|
methods,
|
||||||
attributes,
|
attributes,
|
||||||
|
inited: false,
|
||||||
object_field_mapping: HashMap::new(),
|
object_field_mapping: HashMap::new(),
|
||||||
static_field_mapping: HashMap::new(),
|
static_field_mapping: HashMap::new(),
|
||||||
static_data: vec![],
|
static_data: vec![],
|
||||||
|
|
@ -565,17 +560,18 @@ pub type UnsafeValue = Arc<UnsafeCell<Value>>;
|
||||||
|
|
||||||
pub type UnsafeRef = Arc<UnsafeCell<ObjectRef>>;
|
pub type UnsafeRef = Arc<UnsafeCell<ObjectRef>>;
|
||||||
|
|
||||||
pub fn unsafe_ref(object: ObjectRef) -> UnsafeRef{
|
pub fn unsafe_ref(object: ObjectRef) -> UnsafeRef {
|
||||||
return Arc::new(UnsafeCell::new(object))
|
return Arc::new(UnsafeCell::new(object));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unsafe_val(val: Value) -> UnsafeValue{
|
pub fn unsafe_val(val: Value) -> UnsafeValue {
|
||||||
return Arc::new(UnsafeCell::new(val))
|
return Arc::new(UnsafeCell::new(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_ref(class: Class) -> Type{
|
pub fn type_ref(class: Class) -> Type {
|
||||||
return Arc::new(RefCell::new(class))
|
return Arc::new(RefCell::new(class));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Type = Arc<RefCell<Class>>;
|
pub type Type = Arc<RefCell<Class>>;
|
||||||
|
|
||||||
unsafe impl Send for Value {}
|
unsafe impl Send for Value {}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,10 @@ use std::io::Read;
|
||||||
/// * [jar/zip]#[package_path]/[class].class
|
/// * [jar/zip]#[package_path]/[class].class
|
||||||
/// * [dir]/[package_path]/[class].class
|
/// * [dir]/[package_path]/[class].class
|
||||||
pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, Error> {
|
pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, Error> {
|
||||||
if class_name.starts_with("java/") {
|
if class_name.starts_with("java")
|
||||||
|
|| class_name.starts_with("sun/")
|
||||||
|
|| class_name.starts_with("com/sun/")
|
||||||
|
|| class_name.starts_with("jdk/") {
|
||||||
let mut path: String = "jmods/java.base.jmod#classes/".into();
|
let mut path: String = "jmods/java.base.jmod#classes/".into();
|
||||||
path.push_str(class_name);
|
path.push_str(class_name);
|
||||||
path.push_str(".class");
|
path.push_str(".class");
|
||||||
|
|
|
||||||
72
src/vm.rs
72
src/vm.rs
|
|
@ -321,42 +321,32 @@ impl Vm {
|
||||||
let that_borrow = that.borrow();
|
let that_borrow = that.borrow();
|
||||||
let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
|
let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
|
||||||
println!("get static field {}", name);
|
println!("get static field {}", name);
|
||||||
self.current_frame().push_ref(borrow.static_data.get(*val_index).unwrap().as_ref().unwrap().clone());
|
self.current_frame().push_ref(that_borrow.static_data.get(*val_index).unwrap().as_ref().unwrap().clone());
|
||||||
}
|
}
|
||||||
PUTSTATIC => {
|
PUTSTATIC => {
|
||||||
println!("PUTSTATIC");
|
println!("PUTSTATIC");
|
||||||
let mut borrow = this_class.borrow_mut();
|
let mut borrow = this_class.borrow_mut();
|
||||||
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) =
|
||||||
borrow.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid
|
// 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_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap();
|
||||||
let (name) = borrow.cp_utf8(name_index).unwrap();
|
// let (name) = borrow.cp_utf8(name_index).unwrap();
|
||||||
let class_name_index = borrow.cp_class_ref(class_index).unwrap();
|
// let class_name_index = borrow.cp_class_ref(class_index).unwrap();
|
||||||
println!("field {}", name);
|
// println!("field {}", name);
|
||||||
let that_class_name = borrow.cp_utf8(class_name_index).unwrap();
|
// let that_class_name = borrow.cp_utf8(class_name_index).unwrap();
|
||||||
|
|
||||||
if &borrow.name == that_class_name {// may have to apply this in GETSTATIC too
|
// if &borrow.name == that_class_name {// may have to apply this in GETSTATIC too
|
||||||
let (_, val_index) = borrow.static_field_mapping.get(that_class_name).unwrap().get(name).as_ref().unwrap();
|
// let (_, val_index) = borrow.static_field_mapping.get(that_class_name).unwrap().get(name).as_ref().unwrap();
|
||||||
let val_index = *val_index;
|
// let val_index = *val_index;
|
||||||
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);
|
||||||
} else {
|
// } else {
|
||||||
let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?;
|
// let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?;
|
||||||
let that_borrow = that.borrow(); // if already borrowed, then that_class == this_class
|
// let that_borrow = that.borrow(); // if already borrowed, then that_class == this_class
|
||||||
let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
|
// let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
|
||||||
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();
|
||||||
|
|
@ -414,7 +404,7 @@ impl Vm {
|
||||||
args.insert(0, copy(self.current_frame().pop()?));
|
args.insert(0, copy(self.current_frame().pop()?));
|
||||||
}
|
}
|
||||||
args.insert(0, self.current_frame().pop()?);
|
args.insert(0, self.current_frame().pop()?);
|
||||||
let mut return_value = self.execute(
|
let return_value = self.execute(
|
||||||
Some(this_class.borrow().name.as_str()),
|
Some(this_class.borrow().name.as_str()),
|
||||||
&invocation.class_name,
|
&invocation.class_name,
|
||||||
&invocation.method.name,
|
&invocation.method.name,
|
||||||
|
|
@ -432,6 +422,7 @@ impl Vm {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
INVOKESTATIC => unsafe {
|
INVOKESTATIC => unsafe {
|
||||||
|
println!("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) =
|
||||||
get_signature_for_invoke(&method.constant_pool, cp_index)
|
get_signature_for_invoke(&method.constant_pool, cp_index)
|
||||||
|
|
@ -440,7 +431,7 @@ impl Vm {
|
||||||
for _ in 0..invocation.method.num_args {
|
for _ in 0..invocation.method.num_args {
|
||||||
args.insert(0, copy(self.current_frame().pop()?));
|
args.insert(0, copy(self.current_frame().pop()?));
|
||||||
}
|
}
|
||||||
let mut returnvalue = self.execute(
|
let returnvalue = self.execute(
|
||||||
Some(this_class.borrow().name.as_str()),
|
Some(this_class.borrow().name.as_str()),
|
||||||
&invocation.class_name,
|
&invocation.class_name,
|
||||||
&invocation.method.name,
|
&invocation.method.name,
|
||||||
|
|
@ -680,14 +671,14 @@ unsafe fn copy(value: UnsafeValue) -> UnsafeValue {
|
||||||
unsafe_val(match (&*value.get()) {
|
unsafe_val(match (&*value.get()) {
|
||||||
Void => Void,
|
Void => Void,
|
||||||
Null => Null,
|
Null => Null,
|
||||||
BOOL(b)=> BOOL(*b),
|
BOOL(b) => BOOL(*b),
|
||||||
CHAR(c)=> CHAR(*c),
|
CHAR(c) => CHAR(*c),
|
||||||
I32(i)=> I32(*i),
|
I32(i) => I32(*i),
|
||||||
I64(l)=> I64(*l),
|
I64(l) => I64(*l),
|
||||||
F32(f)=> F32(*f),
|
F32(f) => F32(*f),
|
||||||
F64(d)=> F64(*d),
|
F64(d) => F64(*d),
|
||||||
Ref(r)=> Ref(r.clone()),
|
Ref(r) => Ref(r.clone()),
|
||||||
Utf8(s)=> Utf8(s.to_owned()),
|
Utf8(s) => Utf8(s.to_owned()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -719,6 +710,7 @@ fn get_hum_args(signature: &str) -> usize {
|
||||||
while chars[i] != ';' {
|
while chars[i] != ';' {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
i += 1;
|
||||||
num += 1;
|
num += 1;
|
||||||
} else if chars[i] == ')' {
|
} else if chars[i] == ')' {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue