fixed lot of issues. static initializers are working

This commit is contained in:
Sander Hautvast 2023-10-16 19:29:14 +02:00
parent 24f03f61f6
commit d132502771
8 changed files with 100 additions and 47 deletions

View file

@ -2,6 +2,7 @@ use std::cell::{Ref, RefCell, RefMut, UnsafeCell};
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::os::macos::raw::stat;
use std::rc::Rc;
use std::sync::Arc;
@ -20,9 +21,17 @@ 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, 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
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(|| {
println!("read class {} ", class_name);
let resolved_path = find_class(&vm.classpath, class_name).unwrap();
@ -31,17 +40,24 @@ pub fn get_class(vm: &mut Vm, class_name: &str) -> Result<Arc<RefCell<Class>>, E
let mut class = load_class(bytecode).unwrap();
let super_class_name = class.super_class_name.as_ref();
if let Some(super_class_name) = super_class_name {
if let Ok(super_class) = get_class(vm, &super_class_name) {
if let Ok(super_class) = get_class(vm, Some(class_name), &super_class_name) {
class.super_class = Some(super_class);
}
}
Arc::new(RefCell::new(class))
let class = Arc::new(RefCell::new(class));
Class::initialize_fields(class.clone());
class
});
Class::initialize_fields(new_class.clone());
let exec = new_class.borrow().methods.contains_key("<clinit>()V");
if exec {
// 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>)
if new_class.borrow().methods.contains_key("<clinit>()V") {
vm.execute_class(new_class.clone(), "<clinit>()V", vec![]).unwrap();
}
@ -70,7 +86,7 @@ pub struct Class {
// first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index)
pub(crate) static_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
// first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index)
pub(crate) static_data: Vec<UnsafeValue>,
pub(crate) static_data: Vec<Option<UnsafeValue>>,
}
impl Class {
@ -109,11 +125,11 @@ impl Class {
}
pub(crate) fn n_object_fields(&self) -> usize {
self.object_field_mapping.len()
self.object_field_mapping.iter().map(|(_,v)|v.len()).reduce(|acc, e| acc + e).unwrap()
}
pub(crate) fn n_static_fields(&self) -> usize {
self.object_field_mapping.len()
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.
@ -127,9 +143,10 @@ impl Class {
pub fn initialize_fields(class: Arc<RefCell<Class>>) {
let mut this_field_mapping = HashMap::new();
let mut static_field_mapping = HashMap::new();
let mut field_map_index: usize = 0;
let mut object_field_map_index: usize = 0;
let mut static_field_map_index: usize = 0;
Class::add_field_mappings(&mut this_field_mapping, &mut static_field_mapping, class.clone(), &mut field_map_index);
Class::add_field_mappings(&mut this_field_mapping, &mut static_field_mapping, class.clone(), &mut object_field_map_index, &mut static_field_map_index);
class.borrow_mut().object_field_mapping = this_field_mapping;
class.borrow_mut().static_field_mapping = static_field_mapping;
@ -140,22 +157,25 @@ impl Class {
fn add_field_mappings(this_field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>,
static_field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>,
class: Arc<RefCell<Class>>, field_map_index: &mut usize) {
let (o, s) = Class::map_fields(class.clone(), field_map_index);
class: Arc<RefCell<Class>>,
object_field_map_index: &mut usize,
static_field_map_index: &mut usize) {
let (o, s) = Class::map_fields(class.clone(), object_field_map_index, static_field_map_index);
let borrow = class.borrow();
let name = &borrow.name;
this_field_mapping.insert(name.to_owned(), o);
static_field_mapping.insert(name.to_owned(), s);
if let Some(super_class) = class.borrow().super_class.as_ref() {
Class::add_field_mappings(this_field_mapping, static_field_mapping, super_class.clone(), field_map_index);
Class::add_field_mappings(this_field_mapping, static_field_mapping, super_class.clone(), object_field_map_index, static_field_map_index);
}
}
// part of the initialize procedure
fn map_fields(
class: Arc<RefCell<Class>>,
field_map_index: &mut usize,
object_field_map_index: &mut usize,
static_field_map_index: &mut usize,
) -> (HashMap<String, (String, usize)>, HashMap<String, (String, usize)>) {
let mut this_fields = HashMap::new(); //fields in class are stored per class and every superclass.
let mut static_fields = HashMap::new(); //fields in class are stored per class and every superclass.
@ -164,15 +184,17 @@ impl Class {
if field.is(Modifier::Static) {
static_fields.insert(
name.to_owned(),
(field.type_of().to_owned(), *field_map_index),
(field.type_of().to_owned(), *static_field_map_index),
);
*static_field_map_index += 1;
} else {
this_fields.insert(
name.to_owned(),
(field.type_of().to_owned(), *field_map_index),
(field.type_of().to_owned(), *object_field_map_index),
); //name => (type,index)
*object_field_map_index += 1;
}
*field_map_index += 1;
}
(this_fields, static_fields)
}
@ -205,11 +227,11 @@ impl Class {
}
}
pub(crate) fn set_field_data(class: Arc<RefCell<Class>>) -> Vec<UnsafeValue> {
let mut field_data = Vec::with_capacity(class.borrow().n_object_fields());
pub(crate) fn set_field_data(class: Arc<RefCell<Class>>) -> Vec<Option<UnsafeValue>> {
let mut field_data = vec![None; class.borrow().n_static_fields()];
for (_, fields) in &class.borrow().static_field_mapping {
for (_, (fieldtype, _)) in fields {
for (_, this_class) in &class.borrow().static_field_mapping {
for (name, (fieldtype, index)) in this_class {
let value = match fieldtype.as_str() {
"Z" => Value::BOOL(false),
"B" => Value::I32(0),
@ -218,10 +240,10 @@ impl Class {
"J" => Value::I64(0),
"F" => Value::F32(0.0),
"D" => Value::F64(0.0),
"L" => Value::Null,
_ => Value::Void,
_ => Value::Null,
};
field_data.push(value.into());
println!("{} = {:?}", name, value );
field_data[*index] = Some(value.into());
}
}

View file

@ -226,7 +226,7 @@ fn read_attribute(
*index += attribute_length;
if let CpEntry::Utf8(s) = &constant_pool.get(&attribute_name_index).unwrap() {
// println!("Att [{}]", s);
println!("Att [{}]", s);
return match s.as_str() {
"ConstantValue" => {
assert_eq!(info.len(), 2);
@ -273,6 +273,7 @@ fn read_attribute(
"NestMembers" => Some(("".into(), AttributeType::NestMembers)), //stub
"BootstrapMethods" => Some(("".into(), AttributeType::BootstrapMethods)), //stub
"InnerClasses" => Some(("".into(), AttributeType::InnerClasses)), //stub
"Signature" => Some(("".into(), AttributeType::Signature)), //stub
//TODO more actual attribute implementations
_ => None,
};

View file

@ -56,8 +56,7 @@ impl Object {
"J" => Value::I64(0),
"F" => Value::F32(0.0),
"D" => Value::F64(0.0),
"L" => Value::Null,
_ => Value::Void,
_ => Value::Null,
};
field_data.push(value.into());
}

View file

@ -9,7 +9,7 @@ fn main() -> Result<(), Error> {
// let main_class = "Inheritance";
let main_class = "Main";
vm.execute(main_class, "main([Ljava/lang/String;)V", vec![])
vm.execute(None,main_class, "main([Ljava/lang/String;)V", vec![])
.unwrap();
Ok(())
}

View file

@ -132,7 +132,7 @@ pub const INVOKEVIRTUAL: u8 = 182; // (0xb6) Invoke instance method; dispatch ba
pub const INVOKESPECIAL: u8 = 183; // (0xb7) // nvoke instance method; direct invocation of instance initialization methods and methods of the current class and its supertypes
pub const INVOKESTATIC: u8 = 184; // (0xb8) Invoke a class (static) method
pub const NEW: u8 = 187; // (0xbb) Create new object
pub const anewarray: u8 = 189; // (0xbd)
pub const ANEWARRAY: u8 = 189; // (0xbd)
pub const arraylength: u8 = 190; // (0xbe)
pub const athrow: u8 = 191; // (0xbf)
pub const checkcast: u8 = 192; // (0xc0)

View file

@ -1,5 +1,6 @@
use std::cell::{RefCell, UnsafeCell};
use std::collections::HashMap;
use std::ops::Deref;
use std::rc::Rc;
use std::sync::Arc;
@ -39,6 +40,10 @@ impl StackFrame {
fn pop(&mut self) -> Result<UnsafeValue, Error> {
Ok(self.data.pop().unwrap())
}
fn len(&self) -> usize {
self.data.len()
}
}
@ -84,11 +89,12 @@ impl Vm {
/// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM
pub fn execute(
&mut self,
calling_class_name: Option<&str>,
class_name: &str,
method_name: &str,
args: Vec<UnsafeValue>,
) -> Result<UnsafeValue, Error> {
let class = get_class(self, class_name)?;
let class = get_class(self, calling_class_name, class_name)?;
self.execute_class(class, method_name, args)
}
@ -114,7 +120,7 @@ impl Vm {
let mut pc = &mut 0;
while *pc < code.opcodes.len() {
let opcode = read_u8(&code.opcodes, pc);
println!("opcode {} ", opcode);
println!("stack {} opcode {} ", self.local_stack().len(), opcode);
match opcode {
ACONST_NULL => {
self.local_stack().push(Value::Null);
@ -171,13 +177,25 @@ impl Vm {
}
LDC => {
let cp_index = read_u8(&code.opcodes, pc) as u16;
match method.constant_pool.get(&cp_index).unwrap() {
let c = method.constant_pool.get(&cp_index).unwrap();
println!("{:?}", c);
match c {
CpEntry::Integer(i) => {
self.local_stack().push(Value::I32(*i));
}
CpEntry::Float(f) => {
self.local_stack().push(Value::F32(*f));
}
CpEntry::Double(d) => {
self.local_stack().push(Value::F64(*d));
}
CpEntry::StringRef(utf8) => {
let string = get_class(self, Some(&this_class.borrow().name), "java/lang/String").unwrap();
self.local_stack().push(Value::Ref(Arc::new(UnsafeCell::new(ObjectRef::Object(Box::new(Object::new(string)))))))
}
CpEntry::Long(l) => {
self.local_stack().push(Value::I64(*l));
}
_ => {}
}
}
@ -275,12 +293,14 @@ impl Vm {
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();
let class_name = borrow.cp_utf8(class_name_index).unwrap();
let that = get_class(self, class_name.as_str())?;
let borrow = that.borrow();
let (_, val_index) = borrow.static_field_mapping.get(class_name).unwrap().get(name).unwrap();
self.local_stack().push_arc(this_class.borrow().static_data.get(*val_index).unwrap().clone());
let that_class_name_index = borrow.cp_class_ref(class_index).unwrap();
let that_class_name = borrow.cp_utf8(that_class_name_index).unwrap();
let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?;
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.local_stack().push_arc(borrow.static_data.get(*val_index).unwrap().as_ref().unwrap().clone());
}
PUTSTATIC => {
println!("putstatic");
@ -291,12 +311,21 @@ impl Vm {
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();
let class_name = borrow.cp_utf8(class_name_index).unwrap();
let that = get_class(self, class_name.as_str())?;
let that_borrow = that.borrow();
let (_, val_index) = that_borrow.static_field_mapping.get(class_name).unwrap().get(name).unwrap();
let value = self.local_stack().pop()?;
borrow.static_data[*val_index] = value;
println!("field {}", name);
let that_class_name = borrow.cp_utf8(class_name_index).unwrap();
if &borrow.name == that_class_name {
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.local_stack().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.local_stack().pop()?;
borrow.static_data[*val_index] = Some(value);
}
}
GETFIELD => unsafe {
let borrow = this_class.borrow();
@ -347,6 +376,7 @@ impl Vm {
}
args.insert(0, self.local_stack().pop()?);
let mut return_value = self.execute(
Some(this_class.borrow().name.as_str()),
&invocation.class_name,
&invocation.method.name,
args,
@ -369,6 +399,7 @@ impl Vm {
args.insert(0, self.local_stack().pop()?);
}
let mut returnvalue = self.execute(
Some(this_class.borrow().name.as_str()),
&invocation.class_name,
&invocation.method.name,
args,
@ -386,7 +417,7 @@ impl Vm {
let borrow = this_class.borrow();
let class_name_index = borrow.cp_class_ref(class_index).unwrap();
let class_name = borrow.cp_utf8(class_name_index).unwrap();
let class_to_instantiate = get_class(self, class_name)?;
let class_to_instantiate = get_class(self, Some(&borrow.name), class_name)?;
let object = Arc::new(UnsafeCell::new(ObjectRef::Object(Box::new(
Vm::new_instance(class_to_instantiate),

Binary file not shown.

View file

@ -9,6 +9,6 @@ public class Main {
public static void main(String[] args){
FloatBean f = new FloatBean();
f.setValue(42F);
// System.out.println(f.getValue());
System.out.println(f.getValue());
}
}