invalid pointer
This commit is contained in:
parent
656b6aa66a
commit
050c1821c2
3 changed files with 73 additions and 82 deletions
66
src/class.rs
66
src/class.rs
|
|
@ -1,7 +1,6 @@
|
|||
use std::cell::{RefCell, UnsafeCell};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
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,
|
||||
// then parses the binary data into a Class struct
|
||||
// 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);
|
||||
|
||||
unsafe {
|
||||
// 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
|
||||
panic!();
|
||||
// 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
|
||||
}
|
||||
}
|
||||
// }
|
||||
// }
|
||||
|
||||
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);
|
||||
let resolved_path = find_class(&vm.classpath, class_name).unwrap();
|
||||
// println!("full path {}", resolved_path);
|
||||
let bytecode = read_bytecode(resolved_path).unwrap();
|
||||
let mut class = load_class(bytecode).unwrap();
|
||||
let super_class_name = class.super_class_name.as_ref();
|
||||
let class = load_class(bytecode).unwrap();
|
||||
Arc::new(RefCell::new(class))
|
||||
});
|
||||
|
||||
let clone = class.clone();
|
||||
let clone2 = class.clone();
|
||||
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.super_class = Some(super_class);
|
||||
class.borrow_mut().super_class = Some(super_class);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
let class = Arc::new(RefCell::new(class));
|
||||
Class::initialize_fields(class.clone());
|
||||
class
|
||||
});
|
||||
|
||||
|
||||
// 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(clone)
|
||||
Class::initialize_fields(class.clone());
|
||||
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;
|
||||
}
|
||||
Ok(clone2)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,6 +82,7 @@ pub struct Class {
|
|||
pub fields: HashMap<String, Field>,
|
||||
pub methods: HashMap<String, Rc<Method>>,
|
||||
pub attributes: HashMap<String, AttributeType>,
|
||||
pub inited: bool,
|
||||
pub(crate) object_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
|
||||
// first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index)
|
||||
pub(crate) static_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
|
||||
|
|
@ -125,6 +119,7 @@ impl Class {
|
|||
fields,
|
||||
methods,
|
||||
attributes,
|
||||
inited: false,
|
||||
object_field_mapping: HashMap::new(),
|
||||
static_field_mapping: HashMap::new(),
|
||||
static_data: vec![],
|
||||
|
|
@ -566,16 +561,17 @@ pub type UnsafeValue = Arc<UnsafeCell<Value>>;
|
|||
pub type UnsafeRef = Arc<UnsafeCell<ObjectRef>>;
|
||||
|
||||
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 {
|
||||
return Arc::new(UnsafeCell::new(val))
|
||||
return Arc::new(UnsafeCell::new(val));
|
||||
}
|
||||
|
||||
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>>;
|
||||
|
||||
unsafe impl Send for Value {}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ use std::io::Read;
|
|||
/// * [jar/zip]#[package_path]/[class].class
|
||||
/// * [dir]/[package_path]/[class].class
|
||||
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();
|
||||
path.push_str(class_name);
|
||||
path.push_str(".class");
|
||||
|
|
|
|||
56
src/vm.rs
56
src/vm.rs
|
|
@ -321,42 +321,32 @@ impl Vm {
|
|||
let that_borrow = that.borrow();
|
||||
let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
|
||||
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 => {
|
||||
println!("PUTSTATIC");
|
||||
let mut borrow = this_class.borrow_mut();
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
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
|
||||
let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap();
|
||||
let (name) = borrow.cp_utf8(name_index).unwrap();
|
||||
let class_name_index = borrow.cp_class_ref(class_index).unwrap();
|
||||
println!("field {}", name);
|
||||
let that_class_name = borrow.cp_utf8(class_name_index).unwrap();
|
||||
// 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
|
||||
// let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap();
|
||||
// let (name) = borrow.cp_utf8(name_index).unwrap();
|
||||
// let class_name_index = borrow.cp_class_ref(class_index).unwrap();
|
||||
// println!("field {}", name);
|
||||
// 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
|
||||
let (_, val_index) = borrow.static_field_mapping.get(that_class_name).unwrap().get(name).as_ref().unwrap();
|
||||
let val_index = *val_index;
|
||||
let value = self.current_frame().pop()?;
|
||||
borrow.static_data[val_index] = Some(value);
|
||||
} else {
|
||||
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 (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 = *val_index;
|
||||
// let value = self.current_frame().pop()?;
|
||||
// borrow.static_data[val_index] = Some(value);
|
||||
// } else {
|
||||
// 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 (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
|
||||
// let value = self.current_frame().pop()?;
|
||||
// borrow.static_data[*val_index] = Some(value);
|
||||
// }
|
||||
}
|
||||
GETFIELD => unsafe {
|
||||
let borrow = this_class.borrow();
|
||||
|
|
@ -414,7 +404,7 @@ impl Vm {
|
|||
args.insert(0, copy(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()),
|
||||
&invocation.class_name,
|
||||
&invocation.method.name,
|
||||
|
|
@ -432,6 +422,7 @@ impl Vm {
|
|||
}
|
||||
},
|
||||
INVOKESTATIC => unsafe {
|
||||
println!("INVOKESTATIC");
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
if let Some(invocation) =
|
||||
get_signature_for_invoke(&method.constant_pool, cp_index)
|
||||
|
|
@ -440,7 +431,7 @@ impl Vm {
|
|||
for _ in 0..invocation.method.num_args {
|
||||
args.insert(0, copy(self.current_frame().pop()?));
|
||||
}
|
||||
let mut returnvalue = self.execute(
|
||||
let returnvalue = self.execute(
|
||||
Some(this_class.borrow().name.as_str()),
|
||||
&invocation.class_name,
|
||||
&invocation.method.name,
|
||||
|
|
@ -719,6 +710,7 @@ fn get_hum_args(signature: &str) -> usize {
|
|||
while chars[i] != ';' {
|
||||
i += 1;
|
||||
}
|
||||
i += 1;
|
||||
num += 1;
|
||||
} else if chars[i] == ')' {
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue