hit a wall

This commit is contained in:
Shautvast 2023-10-29 18:11:12 +01:00
parent 24a6bd0812
commit 76304fa616
6 changed files with 161 additions and 85 deletions

View file

@ -21,6 +21,8 @@ pub static mut CLASSES: Lazy<HashMap<String, Value>> = Lazy::new(|| HashMap::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(crate) fn get_class( pub(crate) fn get_class(
vm: &mut Vm, vm: &mut Vm,
class_name: &str, class_name: &str,
@ -43,6 +45,7 @@ pub(crate) fn get_class(
// not sure why I have to create the clones first // not sure why I have to create the clones first
let clone2 = class.clone(); let clone2 = class.clone();
let clone3 = class.clone(); let clone3 = class.clone();
let clone4 = class.clone();
let mut some_class = class.clone(); let mut some_class = class.clone();
if class_name != "java/lang/Class" { if class_name != "java/lang/Class" {
@ -55,7 +58,7 @@ pub(crate) fn get_class(
// must not enter here twice! // must not enter here twice!
clone2.borrow_mut().inited = true; clone2.borrow_mut().inited = true;
let mut supers = vec![]; let mut supers = vec![];
if class_name != "java/lang/Class" { if class_name != "java/lang/Class" {
loop { loop {
let super_class_name = some_class let super_class_name = some_class
@ -69,7 +72,7 @@ pub(crate) fn get_class(
if let Ok(super_class) = get_class(vm, &super_class_name) { if let Ok(super_class) = get_class(vm, &super_class_name) {
supers.push(super_class.clone()); supers.push(super_class.clone());
some_class = super_class.clone(); some_class = super_class.clone();
clone2.borrow_mut().super_class = Some(super_class); clone4.borrow_mut().super_class = Some(super_class);
} else { } else {
break; break;
} }
@ -79,7 +82,8 @@ pub(crate) fn get_class(
} }
} }
} }
Class::initialize_fields(clone3);
Class::initialize_fields(clone3, supers);
let clinit = clone2.borrow().methods.contains_key("<clinit>()V"); let clinit = clone2.borrow().methods.contains_key("<clinit>()V");
let name = &clone2.borrow().name.to_owned(); let name = &clone2.borrow().name.to_owned();
if clinit { if clinit {
@ -108,11 +112,27 @@ pub struct Class {
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 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) // lookup index and type from the name
pub(crate) static_field_mapping: HashMap<String, HashMap<String, (String, usize)>>, pub(crate) object_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
// first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index) pub(crate) static_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
pub(crate) static_data: Vec<Option<Value>>, // static fields
pub(crate) static_data: Vec<Value>,
}
#[derive(Debug)]
pub(crate) struct TypeIndex {
pub type_name: String,
pub index: usize,
}
impl TypeIndex {
pub(crate) fn new(type_name: String, index: usize) -> Self {
Self {
type_name,
index,
}
}
} }
impl Class { impl Class {
@ -176,7 +196,7 @@ impl Class {
// This way `this.a` can be differentiated from `super.a`. // This way `this.a` can be differentiated from `super.a`.
// //
// this method looks up this and super classes and calls map_fields for each. // this method looks up this and super classes and calls map_fields for each.
pub fn initialize_fields(class: Arc<RefCell<Class>>) { pub fn initialize_fields(class: Arc<RefCell<Class>>, super_classes: Vec<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 object_field_map_index: usize = 0; let mut object_field_map_index: usize = 0;
@ -197,9 +217,13 @@ impl Class {
class.borrow_mut().static_data = static_data; class.borrow_mut().static_data = static_data;
} }
/// for all static and non-static fields on the class compute an index
/// the result of this function is that the class object contains mappings
/// from the field name to the index. This index will be used to store the
/// actual data later in a Vector.
fn add_field_mappings( fn add_field_mappings(
this_field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>, this_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
static_field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>, static_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
class: Arc<RefCell<Class>>, class: Arc<RefCell<Class>>,
object_field_map_index: &mut usize, object_field_map_index: &mut usize,
static_field_map_index: &mut usize, static_field_map_index: &mut usize,
@ -214,11 +238,21 @@ impl Class {
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() { // // same for super class
// if let Some(super_class) = class.borrow().super_class.as_ref() {
// Class::add_field_mappings(
// this_field_mapping,
// static_field_mapping,
// super_class.clone(),
// object_field_map_index,
// static_field_map_index,
// );
// }
for c in &class.borrow().super_classes {
Class::add_field_mappings( Class::add_field_mappings(
this_field_mapping, this_field_mapping,
static_field_mapping, static_field_mapping,
super_class.clone(), c.clone(),
object_field_map_index, object_field_map_index,
static_field_map_index, static_field_map_index,
); );
@ -226,13 +260,14 @@ impl Class {
} }
// part of the initialize procedure // part of the initialize procedure
/// here the actual indices are created
fn map_fields( fn map_fields(
class: Arc<RefCell<Class>>, class: Arc<RefCell<Class>>,
object_field_map_index: &mut usize, object_field_map_index: &mut usize,
static_field_map_index: &mut usize, static_field_map_index: &mut usize,
) -> ( ) -> (
HashMap<String, (String, usize)>, HashMap<String, TypeIndex>,
HashMap<String, (String, usize)>, HashMap<String, TypeIndex>,
) { ) {
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.
@ -241,13 +276,13 @@ 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(), *static_field_map_index), TypeIndex::new(field.type_of().to_owned(), *static_field_map_index),
); );
*static_field_map_index += 1; *static_field_map_index += 1;
} else { } else {
this_fields.insert( this_fields.insert(
name.to_owned(), name.to_owned(),
(field.type_of().to_owned(), *object_field_map_index), TypeIndex::new(field.type_of().to_owned(), *object_field_map_index),
); //name => (type,index) ); //name => (type,index)
*object_field_map_index += 1; *object_field_map_index += 1;
} }
@ -255,14 +290,17 @@ impl Class {
(this_fields, static_fields) (this_fields, static_fields)
} }
/// the bytecode version
pub fn get_version(&self) -> (u16, u16) { pub fn get_version(&self) -> (u16, u16) {
(self.major_version, self.minor_version) (self.major_version, self.minor_version)
} }
/// get a method by signature
pub fn get_method(&self, name: &str) -> Option<&Rc<Method>> { pub fn get_method(&self, name: &str) -> Option<&Rc<Method>> {
self.methods.get(name) self.methods.get(name)
} }
/// get the class name
fn class_name( fn class_name(
super_class_index: u16, super_class_index: u16,
constant_pool: Rc<HashMap<u16, CpEntry>>, constant_pool: Rc<HashMap<u16, CpEntry>>,
@ -281,12 +319,15 @@ impl Class {
} }
} }
pub(crate) fn set_field_data(class: Arc<RefCell<Class>>) -> Vec<Option<Value>> { /// creates default values for every field, ie null for objects, 0 for integers etc
let mut field_data = vec![None; class.borrow().n_static_fields()]; /// this is the step before the constructor/static initializer can be called to set hardcoded
/// or computed values.
pub(crate) fn set_field_data(class: Arc<RefCell<Class>>) -> Vec<Value> {
let mut field_data = vec![Value::Null; class.borrow().n_static_fields()];
for (_, this_class) in &class.borrow().static_field_mapping { for (_, this_class) in &class.borrow().static_field_mapping {
for (_name, (fieldtype, index)) in this_class { for (_name, type_index) in this_class {
let value = match fieldtype.as_str() { let value = match type_index.type_name.as_str() {
"Z" => Value::BOOL(false), "Z" => Value::BOOL(false),
"B" => Value::I32(0), "B" => Value::I32(0),
"S" => Value::I32(0), "S" => Value::I32(0),
@ -297,7 +338,7 @@ impl Class {
_ => Value::Null, _ => Value::Null,
}; };
// println!("{} = {:?}", name, value); // println!("{} = {:?}", name, value);
field_data[*index] = Some(value.into()); field_data[type_index.index] = value.into();
} }
} }
@ -306,51 +347,51 @@ impl Class {
// convienence methods for data from the constantpool // convienence methods for data from the constantpool
pub fn cp_field_ref(&self, index: &u16) -> Option<(&u16, &u16)> { pub fn cp_field_ref(&self, index: &u16) -> (&u16, &u16) {
if let CpEntry::Fieldref(class_index, name_and_type_index) = if let CpEntry::Fieldref(class_index, name_and_type_index) =
self.constant_pool.get(index).unwrap() self.constant_pool.get(index).unwrap()
{ {
Some((class_index, name_and_type_index)) (class_index, name_and_type_index)
} else { } else {
None unreachable!("should be field")
} }
} }
/// both methodRef and InterfaceMethodRef /// both methodRef and InterfaceMethodRef
/// returns (class_index, name_and_type_index) /// returns (class_index, name_and_type_index)
pub fn cp_method_ref(&self, index: &u16) -> Option<(&u16, &u16)> { pub fn cp_method_ref(&self, index: &u16) -> (&u16, &u16) {
if let CpEntry::MethodRef(class_index, name_and_type_index) if let CpEntry::MethodRef(class_index, name_and_type_index)
| CpEntry::InterfaceMethodref(class_index, name_and_type_index) = | CpEntry::InterfaceMethodref(class_index, name_and_type_index) =
self.constant_pool.get(index).unwrap() self.constant_pool.get(index).unwrap()
{ {
Some((class_index, name_and_type_index)) (class_index, name_and_type_index)
} else { } else {
None unreachable!("should be method")
} }
} }
pub fn cp_class_ref(&self, index: &u16) -> Option<&u16> { pub fn cp_class_ref(&self, index: &u16) -> &u16 {
if let CpEntry::ClassRef(name_index) = self.constant_pool.get(index).unwrap() { if let CpEntry::ClassRef(name_index) = self.constant_pool.get(index).unwrap() {
Some(name_index) name_index
} else { } else {
None unreachable!("should be class entry")
} }
} }
pub fn cp_utf8(&self, index: &u16) -> Option<&String> { pub fn cp_utf8(&self, index: &u16) -> &String {
if let CpEntry::Utf8(utf8) = self.constant_pool.get(index).unwrap() { if let CpEntry::Utf8(utf8) = self.constant_pool.get(index).unwrap() {
Some(utf8) utf8
} else { } else {
None unreachable!("should be utf8 entry")
} }
} }
pub fn cp_name_and_type(&self, index: &u16) -> Option<(&u16, &u16)> { pub fn cp_name_and_type(&self, index: &u16) -> (&u16, &u16) {
if let CpEntry::NameAndType(name_index, type_index) = self.constant_pool.get(index).unwrap() if let CpEntry::NameAndType(name_index, type_index) = self.constant_pool.get(index).unwrap()
{ {
Some((name_index, type_index)) (name_index, type_index)
} else { } else {
None unreachable!("should be name_and_type entry")
} }
} }
} }
@ -583,20 +624,42 @@ impl MethodCode {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Value { pub enum Value {
Void,
// variant returned for void methods // variant returned for void methods
Null, Void,
// 'pointer' to nothing // 'pointer' to nothing
Null,
// primitives
I32(i32), I32(i32),
I64(i64), I64(i64),
F32(f32), F32(f32),
F64(f64), F64(f64),
BOOL(bool), BOOL(bool),
CHAR(char), CHAR(char),
// objects and arrays
Ref(UnsafeRef), Ref(UnsafeRef),
// special object
Utf8(String), Utf8(String),
} }
impl Value {
// panics if not correct type
pub fn into_i32(self) -> i32 {
if let Value::I32(v) = self {
v
} else {
panic!();
}
}
pub fn into_object(self) -> UnsafeRef {
if let Value::Ref(v) = self {
v
} else {
panic!();
}
}
}
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 {

View file

@ -113,8 +113,8 @@ impl Object {
let mut field_data = Vec::with_capacity(class.borrow().n_object_fields()); let mut field_data = Vec::with_capacity(class.borrow().n_object_fields());
for (_, fields) in &class.borrow().object_field_mapping { for (_, fields) in &class.borrow().object_field_mapping {
for (_, (fieldtype, _)) in fields { for (_, type_index) in fields {
let value = match fieldtype.as_str() { let value = match type_index.type_name.as_str() {
"Z" => Value::BOOL(false), "Z" => Value::BOOL(false),
"B" => Value::I32(0), "B" => Value::I32(0),
"S" => Value::I32(0), "S" => Value::I32(0),
@ -133,24 +133,24 @@ impl Object {
pub fn set(&mut self, class_name: &String, field_name: &String, value: Value) { pub fn set(&mut self, class_name: &String, field_name: &String, value: Value) {
let borrow = self.class.borrow(); let borrow = self.class.borrow();
let (_type, index) = borrow let type_index = borrow
.object_field_mapping .object_field_mapping
.get(class_name) .get(class_name)
.unwrap() .unwrap()
.get(field_name) .get(field_name)
.unwrap(); .unwrap();
self.data[*index] = value; self.data[type_index.index] = value;
} }
pub fn get(&mut self, class_name: &String, field_name: &String) -> &Value { pub fn get(&mut self, class_name: &String, field_name: &String) -> &Value {
let borrow = self.class.borrow(); let borrow = self.class.borrow();
let (_type, index) = borrow let type_index = borrow
.object_field_mapping .object_field_mapping
.get(class_name) .get(class_name)
.unwrap() .unwrap()
.get(field_name) .get(field_name)
.unwrap(); .unwrap();
&self.data[*index] &self.data[type_index.index]
} }
// fn get_field_name(&self, cp_index: &u16) -> &str { // fn get_field_name(&self, cp_index: &u16) -> &str {

View file

@ -1,6 +1,8 @@
use std::io::Error; use std::io::Error;
use java_rs::vm::Vm; use java_rs::vm::Vm;
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
// TODO cmdline args // TODO cmdline args
// TODO build index for package -> jarfile? // TODO build index for package -> jarfile?

View file

@ -1,43 +1,52 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use log::info; use std::ptr::hash;
use anyhow::Error;
use log::{debug, info};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use crate::class::{unsafe_ref, Value}; use crate::class::{get_class, unsafe_ref, Value};
use crate::class::Value::Void; use crate::class::Value::Void;
use crate::heap::ObjectRef; use crate::heap::ObjectRef;
use crate::heap::ObjectRef::Object;
use crate::vm::Vm;
pub fn invoke_native(class_name: &String, method_name: &String, _args: Vec<Value>) -> Value { pub fn invoke_native(vm: &mut Vm, class_name: &String, method_name: &String, _args: Vec<Value>) -> Result<Value,Error> {
info!("native {}.{}", class_name, method_name); info!("native {}.{}", class_name, method_name);
match class_name.as_str() { match class_name.as_str() {
"java/lang/Class" => java_lang_class(method_name), "java/lang/Class" => java_lang_class(vm, method_name),
"jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(method_name), "jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(vm, method_name),
_ => Void _ => Ok(Void)
} }
} }
fn java_lang_class(method_name: &String) -> Value { fn java_lang_class(_vm: &mut Vm, method_name: &String) -> Result<Value,Error> {
match method_name.as_str() { Ok(match method_name.as_str() {
"desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false), "desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false),
_ => Void _ => Void
} })
} }
fn jdk_internal_util_SystemProps_Raw(method_name: &String) -> Value { fn jdk_internal_util_SystemProps_Raw(vm: &mut Vm,method_name: &String) -> Result<Value,Error> {
match method_name.as_str() { match method_name.as_str() {
"platformProperties()[Ljava/lang/String;" => systemProps(), "platformProperties()[Ljava/lang/String;" => systemProps(),
"cmdProperties()Ljava/util/HashMap;" => cmdProps(), //TODO ability to instantiate classes here "cmdProperties()Ljava/util/HashMap;" => cmdProps(vm), //TODO ability to instantiate classes here
"vmProperties()[Ljava/lang/String;" => cmdProps(), "vmProperties()[Ljava/lang/String;" => cmdProps(vm),
_ => Void _ => Ok(Void)
} }
} }
fn cmdProps() -> Value { fn cmdProps(vm: &mut Vm,) -> Result<Value,Error> {
Value::Null let hashmap_class = get_class(vm, "java/util/HashMap")?;
let hashmap = Vm::new_instance(hashmap_class);
let hashmap = Value::Ref(unsafe_ref(Object(Box::new(hashmap))));
vm.execute_special("java/util/HashMap", "<init>()V", vec![hashmap.clone()]);
unsafe {debug!("hashmap {:?}", *hashmap.into_object().get());}
panic!()
} }
fn systemProps() -> Value { fn systemProps() -> Result<Value,Error> {
unsafe { unsafe {
let props: Lazy<Vec<String>> = Lazy::new(|| { let props: Lazy<Vec<String>> = Lazy::new(|| {
let mut vec: Vec<String> = Vec::new(); let mut vec: Vec<String> = Vec::new();
@ -122,6 +131,6 @@ fn systemProps() -> Value {
vec vec
}); });
Value::Ref(unsafe_ref(ObjectRef::StringArray(props.to_vec()))) Ok(Value::Ref(unsafe_ref(ObjectRef::StringArray(props.to_vec()))))
} }
} }

View file

@ -397,6 +397,7 @@ pub const OPCODES:Lazy<Vec<&str>> = Lazy::new(|| {
opcodes[_DSUB as usize] = "_DSUB" ; opcodes[_DSUB as usize] = "_DSUB" ;
opcodes[_FMUL as usize] = "_FMUL" ; opcodes[_FMUL as usize] = "_FMUL" ;
opcodes[_DMUL as usize] = "_DMUL" ; opcodes[_DMUL as usize] = "_DMUL" ;
opcodes[IDIV as usize] = "IDIV" ;
opcodes[_FDIV as usize] = "_FDIV" ; opcodes[_FDIV as usize] = "_FDIV" ;
opcodes[_DDIV as usize] = "_DDIV" ; opcodes[_DDIV as usize] = "_DDIV" ;
opcodes[_FREM as usize] = "_FREM" ; opcodes[_FREM as usize] = "_FREM" ;

View file

@ -2,36 +2,37 @@ use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use anyhow::{anyhow, Error}; use anyhow::Error;
use Value::I32;
use crate::class::{Class, get_class, Method, Value}; use crate::class::{Class, get_class, Value};
use crate::class::Value::{F32, F64, I64, Ref, Utf8};
use crate::classloader::CpEntry; use crate::classloader::CpEntry;
use crate::heap::ObjectRef;
use crate::vm::Vm; use crate::vm::Vm;
use crate::vm::vm::{Invocation, MethodSignature}; use crate::vm::vm::{Invocation, MethodSignature};
pub(crate) fn get_static(vm: &mut Vm, this_class: Arc<RefCell<Class>>, field_index: u16) -> Value { /// the place for opcode implementations that are a bit long
let borrow = this_class.borrow();
let (class_index, field_name_and_type_index) =
borrow.cp_field_ref(&field_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 that_class_name_index = borrow.cp_class_ref(class_index).unwrap(); // GET_STATIC opcode
let that_class_name = borrow.cp_utf8(that_class_name_index).unwrap(); pub(crate) fn get_static(vm: &mut Vm, this_class: Arc<RefCell<Class>>, field_index: u16) -> Result<Value,Error> {
let that = get_class(vm, that_class_name.as_str()).unwrap(); let this_class = this_class.borrow();
let that_borrow = that.borrow(); let (class_index, field_name_and_type_index) =
let (_, val_index) = that_borrow this_class.cp_field_ref(&field_index); // all these unwraps are safe as long as the class is valid
let (name_index, _) =
this_class.cp_name_and_type(field_name_and_type_index);
let field_name = this_class.cp_utf8(name_index);
let that_class_name_index = this_class.cp_class_ref(class_index);
let that_class_name = this_class.cp_utf8(that_class_name_index);
let that_class = get_class(vm, that_class_name.as_str())?;
let that_class = that_class.borrow();
let type_index = that_class
.static_field_mapping .static_field_mapping
.get(that_class_name) .get(that_class_name)
.unwrap() .unwrap()// safe because class for static field must be there
.get(name) .get(field_name)
.unwrap(); .unwrap(); // safe because field must be there
that_borrow
.static_data Ok(that_class.static_data[type_index.index].clone())
.get(*val_index).unwrap().as_ref().unwrap().clone()
} }
pub(crate) fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<MethodSignature> { pub(crate) fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<MethodSignature> {