proper implementation for non-statics

This commit is contained in:
Sander Hautvast 2023-10-13 17:00:44 +02:00
parent 7313d24777
commit 6cf0365dd0
10 changed files with 353 additions and 115 deletions

7
Cargo.lock generated
View file

@ -196,6 +196,7 @@ name = "java_rs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"once_cell",
"zip", "zip",
] ]
@ -223,6 +224,12 @@ dependencies = [
"adler", "adler",
] ]
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]] [[package]]
name = "password-hash" name = "password-hash"
version = "0.4.2" version = "0.4.2"

View file

@ -5,4 +5,5 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = { version = "1.0", features = ["default"] } anyhow = { version = "1.0", features = ["default"] }
once_cell = { version = "1.18.0", features = [] }
zip = { version = "0.6", features = ["zstd"] } zip = { version = "0.6", features = ["zstd"] }

View file

@ -4,27 +4,97 @@ use crate::heap::{Object, ObjectRef};
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
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;
use crate::io::read_u16; use crate::io::read_u16;
// the class definition as read from the class file + derived values
#[derive(Debug)] #[derive(Debug)]
//TODO create factory function
pub struct Class { pub struct Class {
pub minor_version: u16, pub minor_version: u16,
pub major_version: u16, pub major_version: u16,
pub constant_pool: Rc<HashMap<u16, CpEntry>>, pub constant_pool: Rc<HashMap<u16, CpEntry>>,
pub access_flags: u16, pub access_flags: u16,
pub this_class: u16, pub name: String,
pub super_class: u16, pub super_class_name: Option<String>,
pub interfaces: Vec<u16>, pub super_class: Option<Rc<Class>>,
pub fields: Vec<Field>, pub interface_indices: Vec<u16>,
pub interfaces: Vec<Class>,
pub fields: HashMap<String, Field>,
pub methods: HashMap<String, Method>, pub methods: HashMap<String, Method>,
pub attributes: HashMap<String, AttributeType>, pub attributes: HashMap<String, AttributeType>,
pub(crate) field_mapping: Option<HashMap<String, HashMap<String, (String, usize)>>>, // first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index)
} }
impl Class { impl Class {
pub fn new(minor_version: u16,
major_version: u16,
constant_pool: Rc<HashMap<u16, CpEntry>>,
access_flags: u16,
this_class: u16,
super_class_index: u16,
interface_indices: Vec<u16>,
fields: HashMap<String, Field>,
methods: HashMap<String, Method>,
attributes: HashMap<String, AttributeType>) -> Self {
let name = Class::class_name(this_class, constant_pool.clone()).unwrap();
let super_class_name = Class::class_name(super_class_index, constant_pool.clone());
Self {
major_version,
minor_version,
constant_pool,
access_flags,
name,
super_class_name,
super_class: None, // has to be instantiated later, because it involves classloading. maybe not store it here
interface_indices,
interfaces: vec![], // same
fields,
methods,
attributes,
field_mapping: None,
}
}
pub(crate) fn n_fields(&self) -> usize {
self.field_mapping.as_ref().map_or(0, |m| m.len())
}
// Create a mapping per field(name) to an index in the storage vector that contains the instance data.
// When a field is stored, first the index will be looked up, using the qualified name (from the FieldRef)
// The qualified name is the combination of class name and field name.
// The class name is needed as part of the key to separate class from superclass fields
// (duplicates in the singular field name are allowed).
// This way `this.a` can be differentiated from `super.a`.
//
// this method looks up this and super classes and calls map_fields for each.
pub fn initialize(&mut self) {
let mut field_mapping = HashMap::new();
let mut field_map_index: usize = 0;
Class::map_fields(&mut field_mapping, self, &mut field_map_index);
let mut sooper = &self.super_class;
while let Some(super_class) = sooper {
Class::map_fields(&mut field_mapping, super_class, &mut field_map_index);
sooper = &super_class.super_class;
}
self.field_mapping = Some(field_mapping);
}
// part of the initialize procedure
fn map_fields(field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>, class: &Class, field_map_index: &mut usize) {
let mut this_fields = HashMap::new(); //fields in class are stored per class and every superclass.
for field in &class.fields {
this_fields.insert(field.0.to_owned(), (field.1.type_of().to_owned(), *field_map_index)); //name => (type,index)
*field_map_index += 1;
}
let this_name = class.name.to_owned();
field_mapping.insert(this_name, this_fields);
}
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)
} }
@ -35,16 +105,58 @@ impl Class {
.ok_or(anyhow!("Method {} not found", name)) .ok_or(anyhow!("Method {} not found", name))
} }
pub fn get_name(&self) -> &str { fn class_name(super_class_index: u16, constant_pool: Rc<HashMap<u16, CpEntry>>) -> Option<String> {
if let CpEntry::ClassRef(name_index ) = self.constant_pool.get(&self.this_class).unwrap(){ if super_class_index == 0 {
if let CpEntry::Utf8(name) = self.constant_pool.get(name_index).unwrap(){ None
return name; } else if let CpEntry::ClassRef(name_index) = constant_pool.get(&super_class_index).unwrap() {
if let CpEntry::Utf8(name) = constant_pool.get(name_index).unwrap() {
Some(name.to_owned())
} else {
None
} }
} else {
None
} }
panic!();
} }
// convienence methods for data from the constantpool
pub fn get_field_ref(&self, index: &u16) -> Option<(&u16, &u16)> {
if let CpEntry::Fieldref(class_index, name_and_type_index) = self.constant_pool.get(index).unwrap() {
Some((class_index, name_and_type_index))
} else {
None
}
}
pub fn get_class_ref(&self, index: &u16) -> Option<&u16> {
if let CpEntry::ClassRef(name_index) = self.constant_pool.get(index).unwrap() {
Some(name_index)
} else {
None
}
}
pub fn get_utf8(&self, index: &u16) -> Option<&String> {
if let CpEntry::Utf8(utf8) = self.constant_pool.get(index).unwrap() {
Some(utf8)
} else {
None
}
}
pub fn get_name_and_type(&self, index: &u16) -> Option<(&u16, &u16)> {
if let CpEntry::NameAndType(name_index, type_index) = self.constant_pool.get(index).unwrap(){
Some((name_index, type_index))
} else {
None
}
}
} }
unsafe impl Send for Class {} unsafe impl Send for Class {}
unsafe impl Sync for Class {} unsafe impl Sync for Class {}
pub struct Method { pub struct Method {
@ -101,6 +213,7 @@ pub struct Field {
pub(crate) name_index: u16, pub(crate) name_index: u16,
descriptor_index: u16, descriptor_index: u16,
attributes: HashMap<String, AttributeType>, attributes: HashMap<String, AttributeType>,
index: u16,
} }
impl fmt::Debug for Field { impl fmt::Debug for Field {
@ -120,6 +233,7 @@ impl Field {
name_index: u16, name_index: u16,
descriptor_index: u16, descriptor_index: u16,
attributes: HashMap<String, AttributeType>, attributes: HashMap<String, AttributeType>,
field_index: u16,
) -> Self { ) -> Self {
Field { Field {
constant_pool, constant_pool,
@ -127,18 +241,15 @@ impl Field {
name_index, name_index,
descriptor_index, descriptor_index,
attributes, attributes,
index: field_index,
} }
} }
pub fn name(&self) -> String { pub fn name(&self) -> &String {
let mut name = String::new(); if let CpEntry::Utf8(utf8) = &self.constant_pool.get(&self.name_index).unwrap() {
return utf8;
name.push(' ');
if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.name_index).unwrap() {
name.push_str(s);
} }
unreachable!()
name
} }
pub fn type_of(&self) -> &String { pub fn type_of(&self) -> &String {
@ -174,10 +285,11 @@ pub fn get_modifier(modifier: u16) -> String {
output output
} }
//TODO implement more types
#[derive(Debug)] #[derive(Debug)]
pub enum AttributeType { pub enum AttributeType {
ConstantValue(u16), ConstantValue(u16),
Code(MethodCode), Code(Box<MethodCode>),
StackMapTable, StackMapTable,
BootstrapMethods, BootstrapMethods,
NestHost, NestHost,
@ -256,8 +368,10 @@ impl MethodCode {
#[derive(Debug)] #[derive(Debug)]
pub enum Value { pub enum Value {
Void, // variant returned for void methods Void,
Null, // 'pointer' to nothing // variant returned for void methods
Null,
// 'pointer' to nothing
I32(i32), I32(i32),
I64(i64), I64(i64),
F32(f32), F32(f32),
@ -268,4 +382,5 @@ pub enum Value {
} }
unsafe impl Send for Value {} unsafe impl Send for Value {}
unsafe impl Sync for Value {} unsafe impl Sync for Value {}

View file

@ -4,6 +4,8 @@ use anyhow::Error;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
// The native classoader
pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> { pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
let pos = &mut 0; let pos = &mut 0;
check_magic(&bytecode, pos); check_magic(&bytecode, pos);
@ -37,9 +39,10 @@ pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
} }
let fields_count = read_u16(&bytecode, pos); let fields_count = read_u16(&bytecode, pos);
let mut fields = vec![]; let mut fields = HashMap::new();
for _ in 0..fields_count { for i in 0..fields_count {
fields.push(read_field(constant_pool.clone(), pos, &bytecode)); let field = read_field(constant_pool.clone(), pos, &bytecode, i);
fields.insert(field.name().to_owned(), field);
} }
let methods_count = read_u16(&bytecode, pos); let methods_count = read_u16(&bytecode, pos);
@ -56,11 +59,11 @@ pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
if let Some(att) = some { if let Some(att) = some {
attributes.insert(att.0, att.1); attributes.insert(att.0, att.1);
} else { } else {
panic!(); // bug/not-implemented panic!("attribute not found"); // bug/not-implemented
} }
} }
Ok(Class { Ok(Class::new(
minor_version, minor_version,
major_version, major_version,
constant_pool, constant_pool,
@ -71,7 +74,7 @@ pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
fields, fields,
methods, methods,
attributes, attributes,
}) ))
} }
fn check_magic(bytecode: &[u8], pos: &mut usize) { fn check_magic(bytecode: &[u8], pos: &mut usize) {
@ -83,6 +86,7 @@ fn check_magic(bytecode: &[u8], pos: &mut usize) {
fn read_constant_pool_entry(cp_index: &mut u16, index: &mut usize, bytecode: &[u8]) -> CpEntry { fn read_constant_pool_entry(cp_index: &mut u16, index: &mut usize, bytecode: &[u8]) -> CpEntry {
let tag = read_u8(bytecode, index); let tag = read_u8(bytecode, index);
// println!("tag {}", tag);
match tag { match tag {
1 => { 1 => {
let len = read_u16(bytecode, index) as usize; let len = read_u16(bytecode, index) as usize;
@ -137,10 +141,21 @@ fn read_constant_pool_entry(cp_index: &mut u16, index: &mut usize, bytecode: &[u
let descriptor_index = read_u16(bytecode, index); let descriptor_index = read_u16(bytecode, index);
CpEntry::NameAndType(name_index, descriptor_index) CpEntry::NameAndType(name_index, descriptor_index)
} }
// 15 MethodHandle, 15 =>{
// 16 MethodType, let reference_kind = read_u8(bytecode, index);
let reference_index = read_u16(bytecode, index);
CpEntry::MethodHandle(reference_kind, reference_index)
}
16 => {
let descriptor_index = read_u16(bytecode, index);
CpEntry::MethodType(descriptor_index)
}
// 17 Dynamic, // 17 Dynamic,
// 18 InvokeDynamic, 18 => {
let bootstrap_method_attr_index = read_u16(bytecode, index);
let name_and_type_index = read_u16(bytecode, index);
CpEntry::InvokeDynamic(bootstrap_method_attr_index, name_and_type_index)
}
// 19 Module, // 19 Module,
// 20 Package, // 20 Package,
_ => panic!("cp entry type not recognized"), _ => panic!("cp entry type not recognized"),
@ -151,6 +166,7 @@ fn read_field(
constant_pool: Rc<HashMap<u16, CpEntry>>, constant_pool: Rc<HashMap<u16, CpEntry>>,
index: &mut usize, index: &mut usize,
bytecode: &[u8], bytecode: &[u8],
field_index: u16,
) -> Field { ) -> Field {
let access_flags = read_u16(bytecode, index); let access_flags = read_u16(bytecode, index);
let name_index = read_u16(bytecode, index); let name_index = read_u16(bytecode, index);
@ -170,6 +186,7 @@ fn read_field(
name_index, name_index,
descriptor_index, descriptor_index,
attributes, attributes,
field_index,
) )
} }
@ -210,7 +227,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);
@ -241,17 +258,22 @@ fn read_attribute(
} }
Some(( Some((
"Code".into(), "Code".into(),
AttributeType::Code(MethodCode::new( AttributeType::Code(Box::new(MethodCode::new(
max_stack, max_stack,
max_locals, max_locals,
code, code,
exception_table, exception_table,
code_attributes, code_attributes,
)), ))),
)) ))
} }
"SourceFile" => Some(("SourceFile".into(), AttributeType::SourceFile)), "SourceFile" => Some(("SourceFile".into(), AttributeType::SourceFile)),
"LineNumberTable" => Some(("SourceFile".into(), AttributeType::LineNumberTable)), "LineNumberTable" => Some(("SourceFile".into(), AttributeType::LineNumberTable)),
"RuntimeVisibleAnnotations" => Some(("".into(), AttributeType::RuntimeInvisibleAnnotations)), //stub
"NestMembers" => Some(("".into(), AttributeType::NestMembers)),//stub
"BootstrapMethods" => Some(("".into(), AttributeType::BootstrapMethods)),//stub
"InnerClasses" => Some(("".into(), AttributeType::InnerClasses)),//stub
//TODO more actual attribute implementations
_ => None, _ => None,
}; };
} }
@ -271,4 +293,7 @@ pub enum CpEntry {
MethodRef(u16, u16), MethodRef(u16, u16),
InterfaceMethodref(u16, u16), InterfaceMethodref(u16, u16),
NameAndType(u16, u16), NameAndType(u16, u16),
MethodHandle(u8, u16),
MethodType(u16),
InvokeDynamic(u16, u16),
} }

View file

@ -7,15 +7,17 @@ use std::sync::Arc;
use crate::class::{Class, Value}; use crate::class::{Class, Value};
use crate::classloader::CpEntry; use crate::classloader::CpEntry;
// trying to implement efficient object instance storage
pub struct Object { pub struct Object {
// locked: bool, // locked: bool,
// hashcode: i32, // hashcode: i32,
pub class: Rc<Class>, pub class: Rc<Class>,
pub data: HashMap<u16, Arc<UnsafeCell<Value>>>, //TODO optimize pub data: Option<Vec<Arc<UnsafeCell<Value>>>>,
}//arrays }//arrays
// can contain object or array
#[derive(Debug)] #[derive(Debug)]
pub enum ObjectRef{ pub enum ObjectRef {
ByteArray(Vec<i8>), ByteArray(Vec<i8>),
ShortArray(Vec<i16>), ShortArray(Vec<i16>),
IntArray(Vec<i32>), IntArray(Vec<i32>),
@ -28,45 +30,78 @@ pub enum ObjectRef{
Object(Box<Object>), Object(Box<Object>),
} }
unsafe impl Send for Object {} unsafe impl Send for Object {}
unsafe impl Sync for Object {} unsafe impl Sync for Object {}
// object, not array
impl Object { impl Object {
pub fn new(class: Rc<Class>, data: HashMap<u16, Arc<UnsafeCell<Value>>>) -> Self { pub fn new(class: Rc<Class>) -> Self {
Self { class, data } Self { class, data: None }
} }
fn get_field(&self, cp_index: &u16) -> &str { // initializes all non-static fields to their default values
pub(crate) fn init_fields(&mut self) {
let mut field_data = Vec::with_capacity(self.class.n_fields());
for (_, fields) in self.class.field_mapping.as_ref().unwrap() {
for (_, (fieldtype, _)) in fields {
let value = match fieldtype.as_str() {
"Z" => Value::BOOL(false),
"B" => Value::I32(0),
"S" => Value::I32(0),
"I" => Value::I32(0),
"J" => Value::I64(0),
"F" => Value::F32(0.0),
"D" => Value::F64(0.0),
"L" => Value::Null,
_ => Value::Void,
};
field_data.push(Arc::new(UnsafeCell::new(value)));
}
}
self.data = Some(field_data);
}
pub fn set(&mut self, class_name: &String, field_name: &String, value: Arc<UnsafeCell<Value>>) {
let p = self.class.field_mapping.as_ref().unwrap();
let p2 = p.get(class_name).unwrap();
let (_type, index) = p2.get(field_name).unwrap();
self.data.as_mut().unwrap()[*index] = value;
}
pub fn get(&mut self, class_name: &String, field_name: &String) -> &Arc<UnsafeCell<Value>> {
let (_type, index) = &self.class.field_mapping.as_ref().unwrap().get(class_name).unwrap().get(field_name).unwrap(); // (index, type)
&self.data.as_ref().unwrap()[*index]
}
fn get_field_name(&self, cp_index: &u16) -> &str {
if let CpEntry::Utf8(name) = self.class.constant_pool.get(cp_index).unwrap() { if let CpEntry::Utf8(name) = self.class.constant_pool.get(cp_index).unwrap() {
return name; return name;
} }
panic!() panic!()
} }
unsafe fn get_mut<T>(ptr: &UnsafeCell<T>) -> &mut T {
unsafe { &mut *ptr.get() }
}
} }
impl fmt::Debug for Object { impl fmt::Debug for Object {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let fields: Vec<String> = self.data.iter().map(|(k, v)| { // let fields: Vec<String> = self.data.unwrap().iter().map(|(k)| {
let mut r: String = self.get_field(k).into(); // // let mut r: String = self.get_field_name(k).into();
r.push(':'); // // r.push(':');
r.push_str(format!("{:?}", v).as_str()); // // r.push_str(format!("{:?}").as_str());
r // // r
} // }
).collect(); // ).collect();
write!( write!(
f, f,
"{} {{ {:?} }}", "{}",
self.class.get_name(), fields self.class.name
) )
} }
} }
// will using Arc's enable a GC-less heap????
pub(crate) struct Heap { pub(crate) struct Heap {
objects: Vec<Arc<UnsafeCell<ObjectRef>>>, objects: Vec<Arc<UnsafeCell<ObjectRef>>>,
} }

View file

@ -121,7 +121,7 @@ pub const FRETURN: u8 = 174; // (0xae) Return float from method
pub const DRETURN: u8 = 175; // (0xaf) Return double from method pub const DRETURN: u8 = 175; // (0xaf) Return double from method
// pub const areturn: u8 = 176; //(0xb0) return reference // pub const areturn: u8 = 176; //(0xb0) return reference
pub const RETURN_VOID: u8 = 177; // (0xb1) Return void from method (actually 'return' but that's a keyword) pub const RETURN_VOID: u8 = 177; // (0xb1) Return void from method (actually 'return' but that's a keyword)
// pub const getstatic: u8 = 178; // (0xb2) Get static field from class pub const GETSTATIC: u8 = 178; // (0xb2) Get static field from class
pub const GETFIELD: u8 = 180; // (0xb4) Fetch field from object3 pub const GETFIELD: u8 = 180; // (0xb4) Fetch field from object3
pub const PUTFIELD: u8 = 181; // (0xb5) Set field in object pub const PUTFIELD: u8 = 181; // (0xb5) Set field in object
pub const INVOKEVIRTUAL: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class pub const INVOKEVIRTUAL: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class

133
src/vm.rs
View file

@ -4,6 +4,7 @@ use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use once_cell::unsync::Lazy;
use crate::class::{AttributeType, Class, Value}; use crate::class::{AttributeType, Class, Value};
use crate::class::Value::Void; use crate::class::Value::Void;
@ -18,6 +19,7 @@ struct StackFrame {
data: Vec<Arc<UnsafeCell<Value>>>, data: Vec<Arc<UnsafeCell<Value>>>,
} }
// maybe just call frame
impl StackFrame { impl StackFrame {
fn new(at_class: &str, at_method: &str) -> Self { fn new(at_class: &str, at_method: &str) -> Self {
let mut at: String = at_class.into(); let mut at: String = at_class.into();
@ -39,9 +41,11 @@ impl StackFrame {
} }
} }
//trying to be ready for multithreaded as much as possible, using Arc's and all, but it will still require (a lot of) extra work
static mut CLASSDEFS: Lazy<HashMap<String, Rc<Class>>> = Lazy::new(|| HashMap::new()); //TODO add mutex...and Arc most likely
pub struct Vm { pub struct Vm {
classpath: Vec<String>, classpath: Vec<String>,
classes: HashMap<String, Rc<Class>>,
heap: Heap, heap: Heap,
stack: Vec<StackFrame>, stack: Vec<StackFrame>,
} }
@ -52,7 +56,7 @@ const PATH_SEPARATOR: char = ':';
#[cfg(target_family = "windows")] #[cfg(target_family = "windows")]
const PATH_SEPARATOR: char = ';'; const PATH_SEPARATOR: char = ';';
// The singlethreaded VM (maybe a future Thread)
impl Vm { impl Vm {
fn local_stack(&mut self) -> &mut StackFrame { fn local_stack(&mut self) -> &mut StackFrame {
let i = self.stack.len() - 1; let i = self.stack.len() - 1;
@ -62,49 +66,51 @@ impl Vm {
pub fn new(classpath: &'static str) -> Self { pub fn new(classpath: &'static str) -> Self {
Self { Self {
classpath: classpath.split(PATH_SEPARATOR).map(|s| s.to_owned()).collect(), classpath: classpath.split(PATH_SEPARATOR).map(|s| s.to_owned()).collect(),
classes: HashMap::new(),
heap: Heap::new(), heap: Heap::new(),
stack: vec![], stack: vec![],
} }
} }
/// parse the binary data into a Class struct // parse the binary data into a Class struct
/// gets the file from cache, or reads it from classpath // gets the file from cache, or reads it from classpath
/// 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(&mut self, class_name: &str) -> Result<Rc<Class>, Error> { pub fn get_class(&self, class_name: &str) -> Result<Rc<Class>, Error> {
println!("get_class {}", class_name); println!("get_class {}", class_name);
let entry = self.classes.entry(class_name.into()); unsafe {
let entry = entry.or_insert_with(|| { let entry = CLASSDEFS.entry(class_name.into());
// print!("read class {} ", class_name); let entry = entry.or_insert_with(|| {
let resolved_path = find_class(&self.classpath, class_name).expect("Class not found"); // print!("read class {} ", class_name);
// println!("full path {}", resolved_path); let resolved_path = find_class(&self.classpath, class_name).unwrap();
let bytecode = read_bytecode(resolved_path).unwrap(); // println!("full path {}", resolved_path);
Rc::new(load_class(bytecode).unwrap()) let bytecode = read_bytecode(resolved_path).unwrap();
}); let mut class = load_class(bytecode).unwrap();
Ok(entry.clone()) let super_class_name = class.super_class_name.as_ref();
if let Some(super_class_name) = super_class_name {
if let Ok(super_class) = self.get_class(&super_class_name) {
class.super_class = Some(super_class.clone());
}
}
class.initialize();
Rc::new(class)
});
Ok(entry.clone())
}
} }
pub fn new_instance(&self, class: Rc<Class>) -> Object { pub fn new_instance(class: Rc<Class>) -> Object {
//TODO add fields from superclasses let mut class = class;
let mut data = HashMap::new(); // let mut outer = HashMap::new();
for f in &class.fields { //TODO
let value = match f.type_of().as_str() {
"Z" => Value::BOOL(false), let mut instance = Object::new(class.clone());
"B" => Value::I32(0), instance.init_fields();
"S" => Value::I32(0), instance
"I" => Value::I32(0),
"J" => Value::I64(0),
"F" => Value::F32(0.0),
"D" => Value::F64(0.0),
"L" => Value::Null,
_ => Value::Void,
};
data.insert(f.name_index, Arc::new(UnsafeCell::new(value)));
}
Object::new(class.clone(), data)
} }
/// execute the bytecode /// execute the bytecode
/// 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,
class_name: &str, class_name: &str,
@ -269,41 +275,45 @@ impl Vm {
self.stack.pop(); // Void is also returned as a value self.stack.pop(); // Void is also returned as a value
return Ok(Arc::new(UnsafeCell::new(Void))); return Ok(Arc::new(UnsafeCell::new(Void)));
} }
GETSTATIC => {
let cp_index = read_u16(&code.opcodes, pc);
let (class_index, _field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap();
let class_name_index = class.get_class_ref(class_index).unwrap();
let class_name = class.get_utf8(class_name_index).unwrap();
let class = self.get_class(class_name.as_str())?;
println!("{:?}", class); //TODO
}
GETFIELD => { GETFIELD => {
unsafe { unsafe {
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
if let CpEntry::Fieldref(_class_index, name_and_type_index) = let (class_index, field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap();
method.constant_pool.get(&cp_index).unwrap() let (field_name_index, _) = class.get_name_and_type(field_name_and_type_index).unwrap();
{ let class_name_index = class.get_class_ref(class_index).unwrap();
if let Value::Ref(instance) = &*self.local_stack().pop()?.get() { let class_name = class.get_utf8(class_name_index).unwrap();
if let CpEntry::NameAndType(name, _) = let field_name = class.get_utf8(field_name_index).unwrap();
method.constant_pool.get(name_and_type_index).unwrap()
{ let mut objectref = self.local_stack().pop()?;
let objectref = &(*instance.get()); if let Value::Ref(instance) = &mut *objectref.get() {
if let ObjectRef::Object(object) = objectref { if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
let value = object.data.get(name).unwrap(); let value = object.get(class_name, field_name);
self.local_stack().push_arc(Arc::clone(value)); self.local_stack().push_arc(Arc::clone(value));
}
}
} }
} }
} }
} }
PUTFIELD => unsafe { PUTFIELD => unsafe {
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
if let CpEntry::Fieldref(_class_index, name_and_type_index) = let (class_index, field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap();
method.constant_pool.get(&cp_index).unwrap() let (field_name_index, _) = class.get_name_and_type(field_name_and_type_index).unwrap();
{ let class_name_index = class.get_class_ref(class_index).unwrap();
if let CpEntry::NameAndType(name_index, _) = method.constant_pool.get(name_and_type_index).unwrap() { let class_name = class.get_utf8(class_name_index).unwrap();
let value = self.local_stack().pop()?; let field_name = class.get_utf8(field_name_index).unwrap();
let mut objectref = self.local_stack().pop()?;
if let Value::Ref(instance) = &mut *objectref.get() { let value = self.local_stack().pop()?;
if let ObjectRef::Object(ref mut object) = &mut *instance.get() { let mut objectref = self.local_stack().pop()?;
object.data.insert(*name_index, value); if let Value::Ref(instance) = &mut *objectref.get() {
} else { if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
panic!("not an object, maybe array"); object.set(class_name, field_name, value);
}
} // else?
} }
} }
} }
@ -348,7 +358,7 @@ impl Vm {
{ {
println!("new {}", new_class); println!("new {}", new_class);
let class = self.get_class(new_class)?; let class = self.get_class(new_class)?;
let object = Arc::new(UnsafeCell::new(ObjectRef::Object(Box::new(self.new_instance(class))))); let object = Arc::new(UnsafeCell::new(ObjectRef::Object(Box::new(Vm::new_instance(class)))));
self.local_stack().push(Value::Ref(Arc::clone(&object))); self.local_stack().push(Value::Ref(Arc::clone(&object)));
self.heap.new_object(object); self.heap.new_object(object);
} }
@ -523,6 +533,7 @@ fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<Method
None None
} }
fn get_hum_args(signature: &str) -> usize { fn get_hum_args(signature: &str) -> usize {
let mut num = 0; let mut num = 0;
let mut i = 1; let mut i = 1;

44
tests/Inheritance.java Normal file
View file

@ -0,0 +1,44 @@
public class Inheritance {
public static void main(String[] args) {
Father father = new Son();
System.out.println(father.i); //why 1?
System.out.println(father.getI()); //2
System.out.println(father.j); //why 10?
System.out.println(father.getJ()); //why 10?
System.out.println();
Son son = new Son();
System.out.println(son.i); //2
System.out.println(son.getI()); //2
System.out.println(son.j); //20
System.out.println(son.getJ()); //why 10?
}
}
class Son extends Father {
int i = 2;
int j = 20;
@Override
public int getI() {
return i;
}
}
class Father {
int i = 1;
int j = 10;
public int getI() {
return i;
}
public int getJ() {
return j;
}
}

Binary file not shown.

View file

@ -3,6 +3,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());
} }
} }