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::collections::HashMap;
use std::fmt; use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use std::os::macos::raw::stat;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; 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, // 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, 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
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 new_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();
@ -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 mut class = load_class(bytecode).unwrap();
let super_class_name = class.super_class_name.as_ref(); let super_class_name = class.super_class_name.as_ref();
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, &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);
} }
} }
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"); // calling clinit before the end of this function has been a PITA
if exec { // 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(); 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) // 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)>>,
// 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_data: Vec<UnsafeValue>, pub(crate) static_data: Vec<Option<UnsafeValue>>,
} }
impl Class { impl Class {
@ -109,11 +125,11 @@ impl Class {
} }
pub(crate) fn n_object_fields(&self) -> usize { 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 { 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. // 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>>) { pub fn initialize_fields(class: Arc<RefCell<Class>>) {
let mut this_field_mapping = HashMap::new(); let mut this_field_mapping = HashMap::new();
let mut static_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().object_field_mapping = this_field_mapping;
class.borrow_mut().static_field_mapping = static_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)>>, fn add_field_mappings(this_field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>,
static_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) { class: Arc<RefCell<Class>>,
let (o, s) = Class::map_fields(class.clone(), field_map_index); 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 borrow = class.borrow();
let name = &borrow.name; let name = &borrow.name;
this_field_mapping.insert(name.to_owned(), o); this_field_mapping.insert(name.to_owned(), o);
static_field_mapping.insert(name.to_owned(), s); static_field_mapping.insert(name.to_owned(), s);
if let Some(super_class) = class.borrow().super_class.as_ref() { 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 // part of the initialize procedure
fn map_fields( fn map_fields(
class: Arc<RefCell<Class>>, 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)>) { ) -> (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 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. 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) { if field.is(Modifier::Static) {
static_fields.insert( static_fields.insert(
name.to_owned(), 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 { } else {
this_fields.insert( this_fields.insert(
name.to_owned(), name.to_owned(),
(field.type_of().to_owned(), *field_map_index), (field.type_of().to_owned(), *object_field_map_index),
); //name => (type,index) ); //name => (type,index)
*object_field_map_index += 1;
} }
*field_map_index += 1;
} }
(this_fields, static_fields) (this_fields, static_fields)
} }
@ -205,11 +227,11 @@ impl Class {
} }
} }
pub(crate) fn set_field_data(class: Arc<RefCell<Class>>) -> Vec<UnsafeValue> { pub(crate) fn set_field_data(class: Arc<RefCell<Class>>) -> Vec<Option<UnsafeValue>> {
let mut field_data = Vec::with_capacity(class.borrow().n_object_fields()); let mut field_data = vec![None; class.borrow().n_static_fields()];
for (_, fields) in &class.borrow().static_field_mapping { for (_, this_class) in &class.borrow().static_field_mapping {
for (_, (fieldtype, _)) in fields { for (name, (fieldtype, index)) in this_class {
let value = match fieldtype.as_str() { let value = match fieldtype.as_str() {
"Z" => Value::BOOL(false), "Z" => Value::BOOL(false),
"B" => Value::I32(0), "B" => Value::I32(0),
@ -218,10 +240,10 @@ impl Class {
"J" => Value::I64(0), "J" => Value::I64(0),
"F" => Value::F32(0.0), "F" => Value::F32(0.0),
"D" => Value::F64(0.0), "D" => Value::F64(0.0),
"L" => Value::Null, _ => Value::Null,
_ => Value::Void,
}; };
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; *index += attribute_length;
if let CpEntry::Utf8(s) = &constant_pool.get(&attribute_name_index).unwrap() { if let CpEntry::Utf8(s) = &constant_pool.get(&attribute_name_index).unwrap() {
// println!("Att [{}]", s); println!("Att [{}]", s);
return match s.as_str() { return match s.as_str() {
"ConstantValue" => { "ConstantValue" => {
assert_eq!(info.len(), 2); assert_eq!(info.len(), 2);
@ -273,6 +273,7 @@ fn read_attribute(
"NestMembers" => Some(("".into(), AttributeType::NestMembers)), //stub "NestMembers" => Some(("".into(), AttributeType::NestMembers)), //stub
"BootstrapMethods" => Some(("".into(), AttributeType::BootstrapMethods)), //stub "BootstrapMethods" => Some(("".into(), AttributeType::BootstrapMethods)), //stub
"InnerClasses" => Some(("".into(), AttributeType::InnerClasses)), //stub "InnerClasses" => Some(("".into(), AttributeType::InnerClasses)), //stub
"Signature" => Some(("".into(), AttributeType::Signature)), //stub
//TODO more actual attribute implementations //TODO more actual attribute implementations
_ => None, _ => None,
}; };

View file

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

View file

@ -9,7 +9,7 @@ fn main() -> Result<(), Error> {
// let main_class = "Inheritance"; // let main_class = "Inheritance";
let main_class = "Main"; 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(); .unwrap();
Ok(()) 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 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 INVOKESTATIC: u8 = 184; // (0xb8) Invoke a class (static) method
pub const NEW: u8 = 187; // (0xbb) Create new object 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 arraylength: u8 = 190; // (0xbe)
pub const athrow: u8 = 191; // (0xbf) pub const athrow: u8 = 191; // (0xbf)
pub const checkcast: u8 = 192; // (0xc0) pub const checkcast: u8 = 192; // (0xc0)

View file

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