broke through the wall. most unsafe gone. internal mutability gone. better design for classloading
This commit is contained in:
parent
fa10621c56
commit
ceeec215e4
17 changed files with 1335 additions and 1302 deletions
Binary file not shown.
771
src/class.rs
771
src/class.rs
|
|
@ -1,126 +1,10 @@
|
||||||
use std::cell::{RefCell, UnsafeCell};
|
use std::collections::{HashMap, LinkedList};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::Error;
|
use crate::class::ObjectRef::*;
|
||||||
use log::info;
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
|
|
||||||
use crate::classloader::{CpEntry, load_class};
|
pub type ClassId = usize;
|
||||||
use crate::heap::{ObjectRef};
|
|
||||||
use crate::io::{find_class, read_bytecode, read_u16};
|
|
||||||
use crate::vm::Vm;
|
|
||||||
|
|
||||||
//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
|
#[derive(Debug, Clone)]
|
||||||
pub static mut CLASSDEFS: Lazy<HashMap<String, Arc<RefCell<Class>>>> = Lazy::new(|| HashMap::new());
|
|
||||||
//TODO add mutex..
|
|
||||||
pub static mut CLASSES: Lazy<HashMap<String, Value>> = Lazy::new(|| HashMap::new()); //TODO add mutex..
|
|
||||||
|
|
||||||
// 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(crate) fn get_class(
|
|
||||||
vm: &mut Vm,
|
|
||||||
class_name: &str,
|
|
||||||
) -> Result<Arc<RefCell<Class>>, Error> {
|
|
||||||
info!("get_class {}", class_name);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
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();
|
|
||||||
let bytecode = read_bytecode(resolved_path).unwrap();
|
|
||||||
let class = load_class(bytecode).unwrap();
|
|
||||||
Arc::new(RefCell::new(class))
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
let clone = class.clone();
|
|
||||||
let inited = class.borrow().inited;
|
|
||||||
if !inited {
|
|
||||||
// not sure why I have to create the clones first
|
|
||||||
let clone2 = class.clone();
|
|
||||||
let clone3 = class.clone();
|
|
||||||
let clone4 = class.clone();
|
|
||||||
let mut some_class = class.clone();
|
|
||||||
|
|
||||||
if class_name != "java/lang/Class" {
|
|
||||||
let klazz = get_class(vm, "java/lang/Class")?;
|
|
||||||
let mut class_instance = Vm::new_instance(klazz);
|
|
||||||
class_instance.set(&"java/lang/Class".to_owned(), &"name".to_owned(), Value::Utf8(class_name.into()));
|
|
||||||
CLASSES.insert(class_name.into(), Value::Ref(unsafe_ref(ObjectRef::Object(Box::new(class_instance)))));
|
|
||||||
}
|
|
||||||
|
|
||||||
// must not enter here twice!
|
|
||||||
clone2.borrow_mut().inited = true;
|
|
||||||
|
|
||||||
let mut supers = vec![];
|
|
||||||
if class_name != "java/lang/Class" {
|
|
||||||
loop {
|
|
||||||
let super_class_name = some_class
|
|
||||||
.clone()
|
|
||||||
.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, &super_class_name) {
|
|
||||||
supers.push(super_class.clone());
|
|
||||||
some_class = super_class.clone();
|
|
||||||
clone4.borrow_mut().super_class = Some(super_class);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Class::initialize_fields(clone3, supers);
|
|
||||||
let clinit = clone2.borrow().methods.contains_key("<clinit>()V");
|
|
||||||
let name = &clone2.borrow().name.to_owned();
|
|
||||||
if clinit {
|
|
||||||
vm.execute_special(name, "<clinit>()V", vec![]).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(clone)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// the class definition as read from the class file + derived values
|
|
||||||
// TODO implement call to static initializers
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Class {
|
|
||||||
pub minor_version: u16,
|
|
||||||
pub major_version: u16,
|
|
||||||
pub constant_pool: Rc<HashMap<u16, CpEntry>>,
|
|
||||||
pub access_flags: u16,
|
|
||||||
pub name: String,
|
|
||||||
pub super_class_name: Option<String>,
|
|
||||||
pub super_class: Option<Type>,
|
|
||||||
pub super_classes: Vec<Type>,
|
|
||||||
pub interface_indices: Vec<u16>,
|
|
||||||
pub interfaces: Vec<Class>,
|
|
||||||
pub fields: HashMap<String, Field>,
|
|
||||||
pub methods: HashMap<String, Rc<Method>>,
|
|
||||||
pub attributes: HashMap<String, AttributeType>,
|
|
||||||
pub inited: bool,
|
|
||||||
|
|
||||||
// lookup index and type from the name
|
|
||||||
pub(crate) object_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
|
||||||
pub(crate) static_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
|
||||||
// static fields
|
|
||||||
pub(crate) static_data: Vec<Value>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct TypeIndex {
|
pub(crate) struct TypeIndex {
|
||||||
pub type_name: String,
|
pub type_name: String,
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
|
|
@ -135,43 +19,23 @@ impl TypeIndex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// could move classdef into here. Saves one hashmap lookup
|
||||||
|
// have to look at ownership though
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Class {
|
||||||
|
pub id: ClassId,
|
||||||
|
pub initialized: bool,
|
||||||
|
pub name: String,
|
||||||
|
pub superclass: Option<ClassId>,
|
||||||
|
pub parents: LinkedList<ClassId>,
|
||||||
|
pub interfaces: Vec<ClassId>,
|
||||||
|
// lookup index and type from the name
|
||||||
|
pub(crate) object_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
||||||
|
pub(crate) static_field_mapping: HashMap<String, HashMap<String, TypeIndex>>,
|
||||||
|
// pub(crate) static_field_data: Vec<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
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, Rc<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
|
|
||||||
super_classes: vec![],
|
|
||||||
interface_indices,
|
|
||||||
interfaces: vec![], // same
|
|
||||||
fields,
|
|
||||||
methods,
|
|
||||||
attributes,
|
|
||||||
inited: false,
|
|
||||||
object_field_mapping: HashMap::new(),
|
|
||||||
static_field_mapping: HashMap::new(),
|
|
||||||
static_data: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn n_object_fields(&self) -> usize {
|
pub(crate) fn n_object_fields(&self) -> usize {
|
||||||
self.object_field_mapping
|
self.object_field_mapping
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -179,448 +43,8 @@ impl Class {
|
||||||
.reduce(|acc, e| acc + e)
|
.reduce(|acc, e| acc + e)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn n_static_fields(&self) -> usize {
|
|
||||||
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.
|
|
||||||
// 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_fields(class: Arc<RefCell<Class>>, super_classes: Vec<Arc<RefCell<Class>>>) {
|
|
||||||
let mut this_field_mapping = HashMap::new();
|
|
||||||
let mut static_field_mapping = HashMap::new();
|
|
||||||
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 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;
|
|
||||||
|
|
||||||
let static_data = Class::set_field_data(class.clone());
|
|
||||||
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(
|
|
||||||
this_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
|
|
||||||
static_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
|
|
||||||
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);
|
|
||||||
|
|
||||||
// // 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(
|
|
||||||
this_field_mapping,
|
|
||||||
static_field_mapping,
|
|
||||||
c.clone(),
|
|
||||||
object_field_map_index,
|
|
||||||
static_field_map_index,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// part of the initialize procedure
|
|
||||||
/// here the actual indices are created
|
|
||||||
fn map_fields(
|
|
||||||
class: Arc<RefCell<Class>>,
|
|
||||||
object_field_map_index: &mut usize,
|
|
||||||
static_field_map_index: &mut usize,
|
|
||||||
) -> (
|
|
||||||
HashMap<String, TypeIndex>,
|
|
||||||
HashMap<String, TypeIndex>,
|
|
||||||
) {
|
|
||||||
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.
|
|
||||||
|
|
||||||
for (name, field) in &class.borrow().fields {
|
|
||||||
if field.is(Modifier::Static) {
|
|
||||||
static_fields.insert(
|
|
||||||
name.to_owned(),
|
|
||||||
TypeIndex::new(field.type_of().to_owned(), *static_field_map_index),
|
|
||||||
);
|
|
||||||
*static_field_map_index += 1;
|
|
||||||
} else {
|
|
||||||
this_fields.insert(
|
|
||||||
name.to_owned(),
|
|
||||||
TypeIndex::new(field.type_of().to_owned(), *object_field_map_index),
|
|
||||||
); //name => (type,index)
|
|
||||||
*object_field_map_index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(this_fields, static_fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// the bytecode version
|
|
||||||
pub fn get_version(&self) -> (u16, u16) {
|
|
||||||
(self.major_version, self.minor_version)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get a method by signature
|
|
||||||
pub fn get_method(&self, name: &str) -> Option<&Rc<Method>> {
|
|
||||||
self.methods.get(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get the class name
|
|
||||||
fn class_name(
|
|
||||||
super_class_index: u16,
|
|
||||||
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
|
||||||
) -> Option<String> {
|
|
||||||
if super_class_index == 0 {
|
|
||||||
None
|
|
||||||
} 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// creates default values for every field, ie null for objects, 0 for integers etc
|
|
||||||
/// 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 (_name, type_index) in this_class {
|
|
||||||
let value = match type_index.type_name.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),
|
|
||||||
_ => Value::Null,
|
|
||||||
};
|
|
||||||
// println!("{} = {:?}", name, value);
|
|
||||||
field_data[type_index.index] = value.into();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
field_data
|
|
||||||
}
|
|
||||||
|
|
||||||
// convienence methods for data from the constantpool
|
|
||||||
|
|
||||||
pub fn cp_field_ref(&self, index: &u16) -> (&u16, &u16) {
|
|
||||||
if let CpEntry::Fieldref(class_index, name_and_type_index) =
|
|
||||||
self.constant_pool.get(index).unwrap()
|
|
||||||
{
|
|
||||||
(class_index, name_and_type_index)
|
|
||||||
} else {
|
|
||||||
unreachable!("should be field")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// both methodRef and InterfaceMethodRef
|
|
||||||
/// returns (class_index, name_and_type_index)
|
|
||||||
pub fn cp_method_ref(&self, index: &u16) -> (&u16, &u16) {
|
|
||||||
if let CpEntry::MethodRef(class_index, name_and_type_index)
|
|
||||||
| CpEntry::InterfaceMethodref(class_index, name_and_type_index) =
|
|
||||||
self.constant_pool.get(index).unwrap()
|
|
||||||
{
|
|
||||||
(class_index, name_and_type_index)
|
|
||||||
} else {
|
|
||||||
unreachable!("should be method")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cp_class_ref(&self, index: &u16) -> &u16 {
|
|
||||||
if let CpEntry::ClassRef(name_index) = self.constant_pool.get(index).unwrap() {
|
|
||||||
name_index
|
|
||||||
} else {
|
|
||||||
unreachable!("should be class entry")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cp_utf8(&self, index: &u16) -> &String {
|
|
||||||
if let CpEntry::Utf8(utf8) = self.constant_pool.get(index).unwrap() {
|
|
||||||
utf8
|
|
||||||
} else {
|
|
||||||
unreachable!("should be utf8 entry")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
(name_index, type_index)
|
|
||||||
} else {
|
|
||||||
unreachable!("should be name_and_type entry")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for Class {}
|
|
||||||
|
|
||||||
unsafe impl Sync for Class {}
|
|
||||||
|
|
||||||
pub struct Method {
|
|
||||||
pub(crate) constant_pool: Rc<HashMap<u16, CpEntry>>,
|
|
||||||
access_flags: u16,
|
|
||||||
name_index: u16,
|
|
||||||
descriptor_index: u16,
|
|
||||||
pub(crate) attributes: HashMap<String, AttributeType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Method {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Method {{access_flags: {}, name_index: {}, descriptor_index: {}, attributes: {:?} }}",
|
|
||||||
self.access_flags, self.name_index, self.descriptor_index, self.attributes
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Method {
|
|
||||||
pub fn new(
|
|
||||||
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
|
||||||
access_flags: u16,
|
|
||||||
name_index: u16,
|
|
||||||
descriptor_index: u16,
|
|
||||||
attributes: HashMap<String, AttributeType>,
|
|
||||||
) -> Self {
|
|
||||||
Method {
|
|
||||||
constant_pool,
|
|
||||||
access_flags,
|
|
||||||
name_index,
|
|
||||||
descriptor_index,
|
|
||||||
attributes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> String {
|
|
||||||
let mut full_name = String::new();
|
|
||||||
if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.name_index).unwrap() {
|
|
||||||
full_name.push_str(s);
|
|
||||||
}
|
|
||||||
if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.descriptor_index).unwrap() {
|
|
||||||
full_name.push_str(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
full_name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is(&self, modifier: Modifier) -> bool {
|
|
||||||
let m = modifier as u16;
|
|
||||||
(self.access_flags & m) == m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Field {
|
|
||||||
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
|
||||||
access_flags: u16,
|
|
||||||
pub(crate) name_index: u16,
|
|
||||||
descriptor_index: u16,
|
|
||||||
attributes: HashMap<String, AttributeType>,
|
|
||||||
_index: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Field {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Field {{access_flags: {}, name_index: {}, descriptor_index: {}, attributes: {:?} }}",
|
|
||||||
self.access_flags, self.name_index, self.descriptor_index, self.attributes
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Field {
|
|
||||||
pub fn new(
|
|
||||||
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
|
||||||
access_flags: u16,
|
|
||||||
name_index: u16,
|
|
||||||
descriptor_index: u16,
|
|
||||||
attributes: HashMap<String, AttributeType>,
|
|
||||||
field_index: u16,
|
|
||||||
) -> Self {
|
|
||||||
Field {
|
|
||||||
constant_pool,
|
|
||||||
access_flags,
|
|
||||||
name_index,
|
|
||||||
descriptor_index,
|
|
||||||
attributes,
|
|
||||||
_index: field_index,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is(&self, modifier: Modifier) -> bool {
|
|
||||||
let modifier = modifier as u16;
|
|
||||||
self.access_flags & modifier == modifier
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &String {
|
|
||||||
if let CpEntry::Utf8(utf8) = &self.constant_pool.get(&self.name_index).unwrap() {
|
|
||||||
return utf8;
|
|
||||||
}
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_of(&self) -> &String {
|
|
||||||
if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.descriptor_index).unwrap() {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const _MODIFIERS: [(Modifier, &str); 12] = [
|
|
||||||
(Modifier::Public, "public "),
|
|
||||||
(Modifier::Private, "private "),
|
|
||||||
(Modifier::Protected, "protected "),
|
|
||||||
(Modifier::Static, "static "),
|
|
||||||
(Modifier::Final, "final "),
|
|
||||||
(Modifier::Synchronized, "synchronized "),
|
|
||||||
(Modifier::Volatile, "volatile "),
|
|
||||||
(Modifier::Transient, "transient "),
|
|
||||||
(Modifier::Native, "native "),
|
|
||||||
(Modifier::Abstract, "abstract"),
|
|
||||||
(Modifier::Strict, "strict"),
|
|
||||||
(Modifier::Synthetic, "synthetic"),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub enum Modifier {
|
|
||||||
Public = 0x0001,
|
|
||||||
Private = 0x0002,
|
|
||||||
Protected = 0x0004,
|
|
||||||
Static = 0x0008,
|
|
||||||
Final = 0x0010,
|
|
||||||
Synchronized = 0x0020,
|
|
||||||
Volatile = 0x0040,
|
|
||||||
Transient = 0x0080,
|
|
||||||
Native = 0x0100,
|
|
||||||
Abstract = 0x0400,
|
|
||||||
Strict = 0x0800,
|
|
||||||
Synthetic = 0x1000,
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO implement more types
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AttributeType {
|
|
||||||
ConstantValue(u16),
|
|
||||||
Code(Box<MethodCode>),
|
|
||||||
StackMapTable,
|
|
||||||
BootstrapMethods,
|
|
||||||
NestHost,
|
|
||||||
NestMembers,
|
|
||||||
PermittedSubclasses,
|
|
||||||
Exceptions,
|
|
||||||
InnerClasses,
|
|
||||||
EnclosingMethod,
|
|
||||||
Synthetic,
|
|
||||||
Signature,
|
|
||||||
Record,
|
|
||||||
SourceFile,
|
|
||||||
LineNumberTable,
|
|
||||||
LocalVariableTable,
|
|
||||||
LocalVariableTypeTable,
|
|
||||||
SourceDebugExtension,
|
|
||||||
Deprecated,
|
|
||||||
RuntimeVisibleAnnotations,
|
|
||||||
RuntimeInvisibleAnnotations,
|
|
||||||
RuntimeVisibleParameterAnnotations,
|
|
||||||
RuntimeInvisibleParameterAnnotations,
|
|
||||||
RuntimeVisibleTypeAnnotations,
|
|
||||||
RuntimeInvisibleTypeAnnotations,
|
|
||||||
AnnotationDefault,
|
|
||||||
MethodParameters,
|
|
||||||
Module,
|
|
||||||
ModulePackages,
|
|
||||||
ModuleMainClass,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Exception {
|
|
||||||
pub start_pc: u16,
|
|
||||||
pub end_pc: u16,
|
|
||||||
pub handler_pc: u16,
|
|
||||||
pub catch_type: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Exception {
|
|
||||||
pub fn read(code: &[u8], index: &mut usize) -> Self {
|
|
||||||
Self {
|
|
||||||
start_pc: read_u16(code, index),
|
|
||||||
end_pc: read_u16(code, index),
|
|
||||||
handler_pc: read_u16(code, index),
|
|
||||||
catch_type: read_u16(code, index),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MethodCode {
|
|
||||||
_max_stack: u16,
|
|
||||||
_max_locals: u16,
|
|
||||||
pub(crate) opcodes: Vec<u8>,
|
|
||||||
_exception_table: Vec<Exception>,
|
|
||||||
_code_attributes: HashMap<String, AttributeType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MethodCode {
|
|
||||||
pub(crate) fn new(
|
|
||||||
_max_stack: u16,
|
|
||||||
_max_locals: u16,
|
|
||||||
code: Vec<u8>,
|
|
||||||
_exception_table: Vec<Exception>,
|
|
||||||
_code_attributes: HashMap<String, AttributeType>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
_max_stack,
|
|
||||||
_max_locals,
|
|
||||||
opcodes: code,
|
|
||||||
_exception_table,
|
|
||||||
_code_attributes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
|
|
@ -636,7 +60,7 @@ pub enum Value {
|
||||||
BOOL(bool),
|
BOOL(bool),
|
||||||
CHAR(char),
|
CHAR(char),
|
||||||
// objects and arrays
|
// objects and arrays
|
||||||
Ref(UnsafeRef),
|
Ref(ObjectRef),
|
||||||
// special object
|
// special object
|
||||||
Utf8(String),
|
Utf8(String),
|
||||||
}
|
}
|
||||||
|
|
@ -651,7 +75,7 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_object(self) -> UnsafeRef {
|
pub fn into_object(self) -> ObjectRef {
|
||||||
if let Value::Ref(v) = self {
|
if let Value::Ref(v) = self {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -660,22 +84,145 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type UnsafeRef = Arc<UnsafeCell<ObjectRef>>;
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ObjectRef {
|
||||||
pub fn unsafe_ref(object: ObjectRef) -> UnsafeRef {
|
ByteArray(Vec<i8>),
|
||||||
return Arc::new(UnsafeCell::new(object));
|
ShortArray(Vec<i16>),
|
||||||
|
IntArray(Vec<i32>),
|
||||||
|
LongArray(Vec<i64>),
|
||||||
|
FloatArray(Vec<f32>),
|
||||||
|
DoubleArray(Vec<f64>),
|
||||||
|
BooleanArray(Vec<bool>),
|
||||||
|
CharArray(Vec<char>),
|
||||||
|
StringArray(Vec<String>),
|
||||||
|
ObjectArray(ClassId, Vec<ObjectRef>),
|
||||||
|
Object(Object),
|
||||||
|
//Box necessary??
|
||||||
|
Class(Class),
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn unsafe_val(val: Value) -> UnsafeValue {
|
impl ObjectRef {
|
||||||
// return Arc::new(UnsafeCell::new(val));
|
pub fn get_array_length(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
ByteArray(d) => d.len(),
|
||||||
|
ShortArray(d) => d.len(),
|
||||||
|
IntArray(d) => d.len(),
|
||||||
|
LongArray(d) => d.len(),
|
||||||
|
FloatArray(d) => d.len(),
|
||||||
|
DoubleArray(d) => d.len(),
|
||||||
|
BooleanArray(d) => d.len(),
|
||||||
|
CharArray(d) => d.len(),
|
||||||
|
StringArray(d) => d.len(),
|
||||||
|
ObjectArray(_, d) => d.len(),
|
||||||
|
_ => unreachable!("not an array")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectRef {
|
||||||
|
pub fn new_object_array(class: &Class, size: usize) -> Self {
|
||||||
|
ObjectArray(class.id, Vec::with_capacity(size))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_int_array(size: usize) -> Self {
|
||||||
|
IntArray(Vec::with_capacity(size))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_byte_array(d: Vec<u8>) -> Self {
|
||||||
|
ByteArray(into_vec_i8(d))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_vec_i8(v: Vec<u8>) -> Vec<i8> {
|
||||||
|
let mut v = std::mem::ManuallyDrop::new(v);
|
||||||
|
|
||||||
|
// then, pick apart the existing Vec
|
||||||
|
let p = v.as_mut_ptr();
|
||||||
|
let len = v.len();
|
||||||
|
let cap = v.capacity();
|
||||||
|
|
||||||
|
// finally, adopt the data into a new Vec
|
||||||
|
unsafe { Vec::from_raw_parts(p as *mut i8, len, cap) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Object {
|
||||||
|
// locked: bool,
|
||||||
|
// hashcode: i32,
|
||||||
|
pub class_id: ClassId,
|
||||||
|
pub data: Vec<Value>,
|
||||||
|
} //arrays
|
||||||
|
|
||||||
|
// object, not array
|
||||||
|
impl Object {
|
||||||
|
pub fn new(class: &Class) -> Self {
|
||||||
|
let instance_data = Object::init_fields(class);
|
||||||
|
Self {
|
||||||
|
class_id: class.id,
|
||||||
|
data: instance_data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initializes all non-static fields to their default values
|
||||||
|
pub(crate) fn init_fields(class: &Class) -> Vec<Value> {
|
||||||
|
let mut field_data = Vec::with_capacity(class.n_object_fields());
|
||||||
|
|
||||||
|
for (_, fields) in &class.object_field_mapping {
|
||||||
|
for (_, type_index) in fields {
|
||||||
|
let value = match type_index.type_name.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),
|
||||||
|
_ => Value::Null,
|
||||||
|
};
|
||||||
|
field_data.push(value.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
field_data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, class: &Class, declared_type: &str, field_name: &str, value: Value) {
|
||||||
|
let type_index = class
|
||||||
|
.object_field_mapping
|
||||||
|
.get(declared_type)
|
||||||
|
.unwrap()
|
||||||
|
.get(field_name)
|
||||||
|
.unwrap();
|
||||||
|
self.data[type_index.index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&mut self, instancedef: &Class, declared_type: &String, field_name: &String) -> &Value {
|
||||||
|
let type_index = instancedef
|
||||||
|
.object_field_mapping
|
||||||
|
.get(declared_type)
|
||||||
|
.unwrap()
|
||||||
|
.get(field_name)
|
||||||
|
.unwrap();
|
||||||
|
&self.data[type_index.index]
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn get_field_name(&self, cp_index: &u16) -> &str {
|
||||||
|
// if let CpEntry::Utf8(name) = self.class.constant_pool.get(cp_index).unwrap() {
|
||||||
|
// return name;
|
||||||
|
// }
|
||||||
|
// panic!()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn type_ref(class: Class) -> Type {
|
|
||||||
return Arc::new(RefCell::new(class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Type = Arc<RefCell<Class>>;
|
// impl Debug for Object {
|
||||||
|
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
unsafe impl Send for Value {}
|
// // let fields: Vec<String> = self.data.unwrap().iter().map(|(k)| {
|
||||||
|
// // // let mut r: String = self.get_field_name(k).into();
|
||||||
unsafe impl Sync for Value {}
|
// // // r.push(':');
|
||||||
|
// // // r.push_str(format!("{:?}").as_str());
|
||||||
|
// // // r
|
||||||
|
// // }
|
||||||
|
// // ).collect();
|
||||||
|
// write!(f, "{}", self.class.name)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
|
||||||
367
src/classloader/classdef.rs
Normal file
367
src/classloader/classdef.rs
Normal file
|
|
@ -0,0 +1,367 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt;
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::classloader::io::read_u16;
|
||||||
|
|
||||||
|
/// This is the class representation when the bytecode had just been loaded.
|
||||||
|
|
||||||
|
pub struct ClassDef {
|
||||||
|
pub minor_version: u16,
|
||||||
|
pub major_version: u16,
|
||||||
|
pub constant_pool: Rc<HashMap<u16, CpEntry>>,
|
||||||
|
pub access_flags: u16,
|
||||||
|
this_class: u16,
|
||||||
|
pub super_class: Option<u16>,
|
||||||
|
pub interfaces: Vec<u16>,
|
||||||
|
pub fields: HashMap<String, Field>,
|
||||||
|
pub methods: HashMap<String, Method>,
|
||||||
|
pub attributes: HashMap<String, AttributeType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for ClassDef{
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.cp_class_name(&self.this_class))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClassDef {
|
||||||
|
pub fn new(
|
||||||
|
minor_version: u16,
|
||||||
|
major_version: u16,
|
||||||
|
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
||||||
|
access_flags: u16,
|
||||||
|
this_class: u16,
|
||||||
|
super_class: Option<u16>,
|
||||||
|
interfaces: Vec<u16>,
|
||||||
|
fields: HashMap<String, Field>,
|
||||||
|
methods: HashMap<String, Method>,
|
||||||
|
attributes: HashMap<String, AttributeType>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
major_version,
|
||||||
|
minor_version,
|
||||||
|
constant_pool,
|
||||||
|
access_flags,
|
||||||
|
this_class,
|
||||||
|
super_class,
|
||||||
|
interfaces,
|
||||||
|
fields,
|
||||||
|
methods,
|
||||||
|
attributes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// the bytecode version
|
||||||
|
pub fn version(&self) -> (u16, u16) {
|
||||||
|
(self.major_version, self.minor_version)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get the class name
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
self.cp_class_name(&self.this_class)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_method(&self, name: &str) -> Option<&Method> {
|
||||||
|
self.methods.get(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cp_field_ref(&self, index: &u16) -> (&u16, &u16) {
|
||||||
|
if let CpEntry::Fieldref(class_index, name_and_type_index) =
|
||||||
|
self.constant_pool.get(index).unwrap()
|
||||||
|
{
|
||||||
|
(class_index, name_and_type_index)
|
||||||
|
} else {
|
||||||
|
unreachable!("should be field")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// both methodRef and InterfaceMethodRef
|
||||||
|
/// returns (class_index, name_and_type_index)
|
||||||
|
pub fn cp_method_ref(&self, index: &u16) -> (&u16, &u16) {
|
||||||
|
if let CpEntry::MethodRef(class_index, name_and_type_index)
|
||||||
|
| CpEntry::InterfaceMethodref(class_index, name_and_type_index) =
|
||||||
|
self.constant_pool.get(index).unwrap()
|
||||||
|
{
|
||||||
|
(class_index, name_and_type_index)
|
||||||
|
} else {
|
||||||
|
unreachable!("should be method")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cp_class_name(&self, index: &u16) -> &String {
|
||||||
|
let cr = self.cp_class_ref(index);
|
||||||
|
self.cp_utf8(cr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cp_class_ref(&self, index: &u16) -> &u16 {
|
||||||
|
if let CpEntry::ClassRef(name_index) = self.constant_pool.get(index).unwrap() {
|
||||||
|
name_index
|
||||||
|
} else {
|
||||||
|
unreachable!("should be class entry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cp_utf8(&self, index: &u16) -> &String {
|
||||||
|
if let CpEntry::Utf8(utf8) = self.constant_pool.get(index).unwrap() {
|
||||||
|
utf8
|
||||||
|
} else {
|
||||||
|
unreachable!("should be utf8 entry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
(name_index, type_index)
|
||||||
|
} else {
|
||||||
|
unreachable!("should be name_and_type entry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CpEntry {
|
||||||
|
Utf8(String),
|
||||||
|
Integer(i32),
|
||||||
|
Float(f32),
|
||||||
|
Long(i64),
|
||||||
|
Double(f64),
|
||||||
|
ClassRef(u16),
|
||||||
|
// (utf8)
|
||||||
|
StringRef(u16),
|
||||||
|
// (utf8)
|
||||||
|
Fieldref(u16, u16),
|
||||||
|
// (class, name_and_type)
|
||||||
|
MethodRef(u16, u16),
|
||||||
|
// (class, name_and_type)
|
||||||
|
InterfaceMethodref(u16, u16),
|
||||||
|
// (class, name_and_type)
|
||||||
|
NameAndType(u16, u16),
|
||||||
|
// (name, descriptor)
|
||||||
|
MethodHandle(u8, u16),
|
||||||
|
MethodType(u16),
|
||||||
|
InvokeDynamic(u16, u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Modifier {
|
||||||
|
Public = 0x0001,
|
||||||
|
Private = 0x0002,
|
||||||
|
Protected = 0x0004,
|
||||||
|
Static = 0x0008,
|
||||||
|
Final = 0x0010,
|
||||||
|
Synchronized = 0x0020,
|
||||||
|
Volatile = 0x0040,
|
||||||
|
Transient = 0x0080,
|
||||||
|
Native = 0x0100,
|
||||||
|
Abstract = 0x0400,
|
||||||
|
Strict = 0x0800,
|
||||||
|
Synthetic = 0x1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO implement more types
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AttributeType {
|
||||||
|
ConstantValue(u16),
|
||||||
|
Code(Box<MethodCode>),
|
||||||
|
StackMapTable,
|
||||||
|
BootstrapMethods,
|
||||||
|
NestHost,
|
||||||
|
NestMembers,
|
||||||
|
PermittedSubclasses,
|
||||||
|
Exceptions,
|
||||||
|
InnerClasses,
|
||||||
|
EnclosingMethod,
|
||||||
|
Synthetic,
|
||||||
|
Signature,
|
||||||
|
Record,
|
||||||
|
SourceFile,
|
||||||
|
LineNumberTable,
|
||||||
|
LocalVariableTable,
|
||||||
|
LocalVariableTypeTable,
|
||||||
|
SourceDebugExtension,
|
||||||
|
Deprecated,
|
||||||
|
RuntimeVisibleAnnotations,
|
||||||
|
RuntimeInvisibleAnnotations,
|
||||||
|
RuntimeVisibleParameterAnnotations,
|
||||||
|
RuntimeInvisibleParameterAnnotations,
|
||||||
|
RuntimeVisibleTypeAnnotations,
|
||||||
|
RuntimeInvisibleTypeAnnotations,
|
||||||
|
AnnotationDefault,
|
||||||
|
MethodParameters,
|
||||||
|
Module,
|
||||||
|
ModulePackages,
|
||||||
|
ModuleMainClass,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Exception {
|
||||||
|
pub start_pc: u16,
|
||||||
|
pub end_pc: u16,
|
||||||
|
pub handler_pc: u16,
|
||||||
|
pub catch_type: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Exception {
|
||||||
|
pub fn read(code: &[u8], index: &mut usize) -> Self {
|
||||||
|
Self {
|
||||||
|
start_pc: read_u16(code, index),
|
||||||
|
end_pc: read_u16(code, index),
|
||||||
|
handler_pc: read_u16(code, index),
|
||||||
|
catch_type: read_u16(code, index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MethodCode {
|
||||||
|
_max_stack: u16,
|
||||||
|
_max_locals: u16,
|
||||||
|
pub(crate) opcodes: Vec<u8>,
|
||||||
|
_exception_table: Vec<Exception>,
|
||||||
|
_code_attributes: HashMap<String, AttributeType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MethodCode {
|
||||||
|
pub(crate) fn new(
|
||||||
|
_max_stack: u16,
|
||||||
|
_max_locals: u16,
|
||||||
|
code: Vec<u8>,
|
||||||
|
_exception_table: Vec<Exception>,
|
||||||
|
_code_attributes: HashMap<String, AttributeType>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
_max_stack,
|
||||||
|
_max_locals,
|
||||||
|
opcodes: code,
|
||||||
|
_exception_table,
|
||||||
|
_code_attributes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const _MODIFIERS: [(Modifier, &str); 12] = [
|
||||||
|
(Modifier::Public, "public "),
|
||||||
|
(Modifier::Private, "private "),
|
||||||
|
(Modifier::Protected, "protected "),
|
||||||
|
(Modifier::Static, "static "),
|
||||||
|
(Modifier::Final, "final "),
|
||||||
|
(Modifier::Synchronized, "synchronized "),
|
||||||
|
(Modifier::Volatile, "volatile "),
|
||||||
|
(Modifier::Transient, "transient "),
|
||||||
|
(Modifier::Native, "native "),
|
||||||
|
(Modifier::Abstract, "abstract"),
|
||||||
|
(Modifier::Strict, "strict"),
|
||||||
|
(Modifier::Synthetic, "synthetic"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub struct Field {
|
||||||
|
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
||||||
|
access_flags: u16,
|
||||||
|
pub(crate) name_index: u16,
|
||||||
|
descriptor_index: u16,
|
||||||
|
attributes: HashMap<String, AttributeType>,
|
||||||
|
_index: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Field {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Field {{access_flags: {}, name_index: {}, descriptor_index: {}, attributes: {:?} }}",
|
||||||
|
self.access_flags, self.name_index, self.descriptor_index, self.attributes
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Field {
|
||||||
|
pub fn new(
|
||||||
|
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
||||||
|
access_flags: u16,
|
||||||
|
name_index: u16,
|
||||||
|
descriptor_index: u16,
|
||||||
|
attributes: HashMap<String, AttributeType>,
|
||||||
|
field_index: u16,
|
||||||
|
) -> Self {
|
||||||
|
Field {
|
||||||
|
constant_pool,
|
||||||
|
access_flags,
|
||||||
|
name_index,
|
||||||
|
descriptor_index,
|
||||||
|
attributes,
|
||||||
|
_index: field_index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is(&self, modifier: Modifier) -> bool {
|
||||||
|
let modifier = modifier as u16;
|
||||||
|
self.access_flags & modifier == modifier
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &String {
|
||||||
|
if let CpEntry::Utf8(utf8) = &self.constant_pool.get(&self.name_index).unwrap() {
|
||||||
|
return utf8;
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_of(&self) -> &String {
|
||||||
|
if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.descriptor_index).unwrap() {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Method {
|
||||||
|
pub(crate) constant_pool: Rc<HashMap<u16, CpEntry>>,
|
||||||
|
access_flags: u16,
|
||||||
|
name_index: u16,
|
||||||
|
descriptor_index: u16,
|
||||||
|
pub(crate) attributes: HashMap<String, AttributeType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Method {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Method {{access_flags: {}, name_index: {}, descriptor_index: {}, attributes: {:?} }}",
|
||||||
|
self.access_flags, self.name_index, self.descriptor_index, self.attributes
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Method {
|
||||||
|
pub fn new(
|
||||||
|
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
||||||
|
access_flags: u16,
|
||||||
|
name_index: u16,
|
||||||
|
descriptor_index: u16,
|
||||||
|
attributes: HashMap<String, AttributeType>,
|
||||||
|
) -> Self {
|
||||||
|
Method {
|
||||||
|
constant_pool,
|
||||||
|
access_flags,
|
||||||
|
name_index,
|
||||||
|
descriptor_index,
|
||||||
|
attributes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
let mut full_name = String::new();
|
||||||
|
if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.name_index).unwrap() {
|
||||||
|
full_name.push_str(s);
|
||||||
|
}
|
||||||
|
if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.descriptor_index).unwrap() {
|
||||||
|
full_name.push_str(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
full_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is(&self, modifier: Modifier) -> bool {
|
||||||
|
let m = modifier as u16;
|
||||||
|
(self.access_flags & m) == m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
|
use std::fs::{self};
|
||||||
|
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use std::fs::{self, File};
|
|
||||||
use std::io::Read;
|
#[cfg(target_family = "unix")]
|
||||||
|
pub const PATH_SEPARATOR: char = ':';
|
||||||
|
|
||||||
|
#[cfg(target_family = "windows")]
|
||||||
|
pub const PATH_SEPARATOR: char = ';';
|
||||||
|
|
||||||
/// resolves the actual path where the class file is found
|
/// resolves the actual path where the class file is found
|
||||||
/// for std lib there is a special case that resolves to the jmod
|
/// for std lib there is a special case that resolves to the jmod
|
||||||
|
|
@ -38,25 +44,7 @@ pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, E
|
||||||
Err(anyhow!("Class not found {}", class_name))
|
Err(anyhow!("Class not found {}", class_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// reads the binary class file from file path or archive
|
|
||||||
/// and returns the byte array as Vec
|
|
||||||
pub fn read_bytecode(name: String) -> Result<Vec<u8>, Error> {
|
|
||||||
let mut buffer;
|
|
||||||
if name.contains('#') {
|
|
||||||
let parts: Vec<&str> = name.split('#').collect();
|
|
||||||
let archive_file = File::open(parts[0])?;
|
|
||||||
let mut archive_zip = zip::ZipArchive::new(archive_file)?;
|
|
||||||
let mut entry = archive_zip.by_name(parts[1])?;
|
|
||||||
buffer = vec![0; entry.size() as usize];
|
|
||||||
entry.read_exact(&mut buffer)?;
|
|
||||||
} else {
|
|
||||||
let mut f = File::open(&name)?;
|
|
||||||
let metadata = fs::metadata(&name)?;
|
|
||||||
buffer = vec![0; metadata.len() as usize];
|
|
||||||
f.read_exact(&mut buffer)?;
|
|
||||||
}
|
|
||||||
Ok(buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// methods to read values from big-endian binary data
|
// methods to read values from big-endian binary data
|
||||||
|
|
||||||
|
|
@ -1,11 +1,46 @@
|
||||||
use crate::class::{AttributeType, Class, Exception, Field, Method, MethodCode};
|
|
||||||
use crate::io::{read_bytes, read_f32, read_f64, read_i32, read_i64, read_u16, read_u32, read_u8};
|
|
||||||
use anyhow::Error;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fs;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use anyhow::Error;
|
||||||
|
|
||||||
|
use crate::classloader::io::{find_class, read_bytes, read_f32, read_f64, read_i32, read_i64, read_u16, read_u32, read_u8};
|
||||||
|
use crate::classloader::classdef::{AttributeType, ClassDef, CpEntry, Exception, Field, Method, MethodCode};
|
||||||
|
|
||||||
|
pub(crate) mod classdef;
|
||||||
|
pub(crate) mod io;
|
||||||
|
|
||||||
|
pub(crate) fn get_classdef(classpath: &Vec<String>, class_name: &str) -> Result<ClassDef,Error> {
|
||||||
|
println!("read class {} ", class_name);
|
||||||
|
let resolved_path = find_class(classpath, class_name)?;
|
||||||
|
let bytecode = read_bytecode(resolved_path)?;
|
||||||
|
load_class(bytecode)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// reads the binary class file from file path or archive
|
||||||
|
/// and returns the byte array as Vec
|
||||||
|
fn read_bytecode(name: String) -> Result<Vec<u8>, Error> {
|
||||||
|
let mut buffer;
|
||||||
|
if name.contains('#') {
|
||||||
|
let parts: Vec<&str> = name.split('#').collect();
|
||||||
|
let archive_file = File::open(parts[0])?;
|
||||||
|
let mut archive_zip = zip::ZipArchive::new(archive_file)?;
|
||||||
|
let mut entry = archive_zip.by_name(parts[1])?;
|
||||||
|
buffer = vec![0; entry.size() as usize];
|
||||||
|
entry.read_exact(&mut buffer)?;
|
||||||
|
} else {
|
||||||
|
let mut f = File::open(&name)?;
|
||||||
|
let metadata = fs::metadata(&name)?;
|
||||||
|
buffer = vec![0; metadata.len() as usize];
|
||||||
|
f.read_exact(&mut buffer)?;
|
||||||
|
}
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
// The native classoader
|
// The native classoader
|
||||||
pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
|
fn load_class(bytecode: Vec<u8>) -> Result<ClassDef, Error> {
|
||||||
let pos = &mut 0;
|
let pos = &mut 0;
|
||||||
check_magic(&bytecode, pos);
|
check_magic(&bytecode, pos);
|
||||||
let minor_version = read_u16(&bytecode, pos);
|
let minor_version = read_u16(&bytecode, pos);
|
||||||
|
|
@ -22,13 +57,11 @@ pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
|
||||||
);
|
);
|
||||||
cp_index += 1;
|
cp_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let constant_pool = Rc::new(constant_pool);
|
let constant_pool = Rc::new(constant_pool);
|
||||||
|
|
||||||
let access_flags = read_u16(&bytecode, pos);
|
let access_flags = read_u16(&bytecode, pos);
|
||||||
let this_class = read_u16(&bytecode, pos);
|
let this_class = read_u16(&bytecode, pos);
|
||||||
let super_class = read_u16(&bytecode, pos);
|
let super_class = read_u16(&bytecode, pos);
|
||||||
|
let super_class = if super_class != 0 { Some(super_class) } else { None };
|
||||||
let interfaces_count = read_u16(&bytecode, pos);
|
let interfaces_count = read_u16(&bytecode, pos);
|
||||||
let mut interfaces = vec![];
|
let mut interfaces = vec![];
|
||||||
for _ in 0..interfaces_count {
|
for _ in 0..interfaces_count {
|
||||||
|
|
@ -46,7 +79,7 @@ pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
|
||||||
let mut methods = HashMap::new();
|
let mut methods = HashMap::new();
|
||||||
for _ in 0..methods_count {
|
for _ in 0..methods_count {
|
||||||
let m = read_method(constant_pool.clone(), pos, &bytecode);
|
let m = read_method(constant_pool.clone(), pos, &bytecode);
|
||||||
methods.insert(m.name(), Rc::new(m));
|
methods.insert(m.name(), m);
|
||||||
}
|
}
|
||||||
|
|
||||||
let attributes_count = read_u16(&bytecode, pos);
|
let attributes_count = read_u16(&bytecode, pos);
|
||||||
|
|
@ -60,7 +93,7 @@ pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Class::new(
|
Ok(ClassDef::new(
|
||||||
minor_version,
|
minor_version,
|
||||||
major_version,
|
major_version,
|
||||||
constant_pool,
|
constant_pool,
|
||||||
|
|
@ -224,7 +257,6 @@ 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);
|
|
||||||
return match s.as_str() {
|
return match s.as_str() {
|
||||||
"ConstantValue" => {
|
"ConstantValue" => {
|
||||||
assert_eq!(info.len(), 2);
|
assert_eq!(info.len(), 2);
|
||||||
|
|
@ -274,6 +306,7 @@ fn read_attribute(
|
||||||
"Signature" => Some(("".into(), AttributeType::Signature)), //stub
|
"Signature" => Some(("".into(), AttributeType::Signature)), //stub
|
||||||
"NestHost" => Some(("".into(), AttributeType::NestHost)), //stub
|
"NestHost" => Some(("".into(), AttributeType::NestHost)), //stub
|
||||||
"EnclosingMethod" => Some(("".into(), AttributeType::EnclosingMethod)), //stub
|
"EnclosingMethod" => Some(("".into(), AttributeType::EnclosingMethod)), //stub
|
||||||
|
"PermittedSubclasses" => Some(("".into(), AttributeType::PermittedSubclasses)), //stub
|
||||||
//TODO more actual attribute implementations
|
//TODO more actual attribute implementations
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
@ -281,20 +314,3 @@ fn read_attribute(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum CpEntry {
|
|
||||||
Utf8(String),
|
|
||||||
Integer(i32),
|
|
||||||
Float(f32),
|
|
||||||
Long(i64),
|
|
||||||
Double(f64),
|
|
||||||
ClassRef(u16), // (utf8)
|
|
||||||
StringRef(u16), // (utf8)
|
|
||||||
Fieldref(u16, u16), // (class, name_and_type)
|
|
||||||
MethodRef(u16, u16), // (class, name_and_type)
|
|
||||||
InterfaceMethodref(u16, u16), // (class, name_and_type)
|
|
||||||
NameAndType(u16, u16), // (name, descriptor)
|
|
||||||
MethodHandle(u8, u16),
|
|
||||||
MethodType(u16),
|
|
||||||
InvokeDynamic(u16, u16),
|
|
||||||
}
|
|
||||||
319
src/classmanager.rs
Normal file
319
src/classmanager.rs
Normal file
|
|
@ -0,0 +1,319 @@
|
||||||
|
use std::collections::{HashMap, LinkedList};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
use crate::class::{Class, ClassId, ObjectRef, TypeIndex, Value::*, Value};
|
||||||
|
use crate::class::Object;
|
||||||
|
use crate::classloader;
|
||||||
|
use crate::classloader::classdef::{ClassDef, Modifier};
|
||||||
|
use crate::classloader::io::PATH_SEPARATOR;
|
||||||
|
use crate::vm::Vm;
|
||||||
|
|
||||||
|
static mut CLASSMANAGER: Lazy<ClassManager> = Lazy::new(|| ClassManager::new());
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.classes.clear();
|
||||||
|
CLASSMANAGER.names.clear();
|
||||||
|
CLASSMANAGER.classdefs.clear();
|
||||||
|
CLASSMANAGER.class_objects.clear();
|
||||||
|
CLASSMANAGER.static_class_data.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_classpath(classpath: &str) {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.set_classpath(classpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_class_by_id(id: ClassId) -> Option<&'static Class> {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.get_class_by_id(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn classdef_name(id: &ClassId) -> Option<String> {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.classdef_name(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_classid(name: &str) -> &ClassId {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.get_classid(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_classdef(id: &ClassId) -> &ClassDef {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.get_classdef(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_class_by_name(name: &str) {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.load_class_by_name(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_class_by_name(name: &str) -> Option<&Class> {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.get_class_by_name(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_class(name: &str) -> ClassId {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.add_class(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_static(id: &ClassId, index: usize) -> Value {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.static_class_data.get(id).unwrap()[index].clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_static(id: &ClassId, index: usize, value: Value) {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.static_class_data.get_mut(id).unwrap()[index] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_classobject(id: &ClassId) -> Option<&Value> {
|
||||||
|
unsafe {
|
||||||
|
CLASSMANAGER.class_objects.get(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO less pubs
|
||||||
|
pub struct ClassManager {
|
||||||
|
static_class_data: HashMap<ClassId, Vec<Value>>,
|
||||||
|
// sequence for passing new classIds
|
||||||
|
current_id: ClassId,
|
||||||
|
// the classpath
|
||||||
|
classpath: Vec<String>,
|
||||||
|
|
||||||
|
//references to classdefs, ie the static class info
|
||||||
|
pub classdefs: HashMap<ClassId, ClassDef>,
|
||||||
|
|
||||||
|
// references to the runtime class
|
||||||
|
pub classes: HashMap<ClassId, Class>,
|
||||||
|
|
||||||
|
pub names: HashMap<String, ClassId>,
|
||||||
|
pub class_objects: HashMap<ClassId, Value>,
|
||||||
|
vm: Vm,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClassManager {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
static_class_data: HashMap::new(),
|
||||||
|
current_id: 0,
|
||||||
|
classdefs: HashMap::new(),
|
||||||
|
classes: HashMap::new(),
|
||||||
|
class_objects: HashMap::new(),
|
||||||
|
names: HashMap::new(),
|
||||||
|
classpath: vec![],
|
||||||
|
vm:Vm::new_internal(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_classpath(&mut self, classpath: &str) {
|
||||||
|
self.classpath = classpath
|
||||||
|
.split(PATH_SEPARATOR)
|
||||||
|
.map(|s| s.into())
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_class_by_id(&mut self, id: ClassId) -> Option<&Class> {
|
||||||
|
if !self.classes.contains_key(&id) {
|
||||||
|
let name = self.classdef_name(&id);
|
||||||
|
if name.is_some() {
|
||||||
|
self.add_class(&name.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.classes.get(&id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classdef_name(&self, id: &ClassId) -> Option<String> {
|
||||||
|
self.classdefs.get(id).map(|c| c.name().to_owned()) //drops borrow to self here
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_classid(&self, name: &str) -> &ClassId {
|
||||||
|
self.names.get(name).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_classdef(&self, id: &ClassId) -> &ClassDef {
|
||||||
|
self.classdefs.get(&id).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_class_by_name(&mut self, name: &str) {
|
||||||
|
let id = self.names.get(name);
|
||||||
|
match id {
|
||||||
|
Some(id) => if self.classes.get(id).is_none() {
|
||||||
|
self.add_class(name);
|
||||||
|
}
|
||||||
|
None => { self.add_class(name); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_class_by_name(&self, name: &str) -> Option<&Class> {
|
||||||
|
let id = self.names.get(name);
|
||||||
|
self.classes.get(id.unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_class(&mut self, name: &str) -> ClassId {
|
||||||
|
let this_classid = self.load(name);
|
||||||
|
let this_classdef = self.classdefs.get(&this_classid).unwrap();
|
||||||
|
|
||||||
|
//compute indices to fields
|
||||||
|
let mut object_field_mapping = HashMap::new();
|
||||||
|
let mut static_field_mapping = HashMap::new();
|
||||||
|
let object_field_map_index: &mut usize = &mut 0;
|
||||||
|
let static_field_map_index: &mut usize = &mut 0;
|
||||||
|
|
||||||
|
let mut current_id = Some(this_classid);
|
||||||
|
let mut current_classdef;
|
||||||
|
let mut parents = LinkedList::new();
|
||||||
|
while let Some(c) = current_id {
|
||||||
|
parents.push_front(current_id.unwrap());
|
||||||
|
current_classdef = self.classdefs.get(&c).unwrap();
|
||||||
|
Self::add_fields_for_this_or_parents(&mut object_field_mapping, &mut static_field_mapping, object_field_map_index, static_field_map_index, current_classdef);
|
||||||
|
|
||||||
|
current_id = current_classdef.super_class.as_ref()
|
||||||
|
.map(|i| current_classdef.cp_class_name(i).to_owned())
|
||||||
|
.map(|n| *self.names.get(&n).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
//handrolled references to superclass and interfaces
|
||||||
|
let superclass_id = this_classdef.super_class.as_ref()
|
||||||
|
.map(|i| this_classdef.cp_class_name(i).to_owned())
|
||||||
|
.map(|n| *self.names.get(&n).unwrap());
|
||||||
|
|
||||||
|
let interface_ids: Vec<ClassId> = this_classdef.interfaces.iter()
|
||||||
|
.map(|i| this_classdef.cp_class_name(i).to_owned())
|
||||||
|
.map(|n| *self.names.get(n.as_str()).unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
self.static_class_data.insert(this_classid, Self::set_field_data(&static_field_mapping));
|
||||||
|
|
||||||
|
self.names.get(name)
|
||||||
|
.and_then(|id|
|
||||||
|
self.classes.insert(*id, Class {
|
||||||
|
id: *id,
|
||||||
|
initialized: false,
|
||||||
|
name: name.into(),
|
||||||
|
superclass: superclass_id,
|
||||||
|
parents,
|
||||||
|
interfaces: interface_ids,
|
||||||
|
object_field_mapping,
|
||||||
|
static_field_mapping,
|
||||||
|
// static_field_data: static_values,
|
||||||
|
}));
|
||||||
|
if name != "java/lang/Class" {
|
||||||
|
let cls = self.get_class_by_name("java/lang/Class").unwrap();
|
||||||
|
let mut instance = Object::new(cls);
|
||||||
|
instance.set(cls, "java/lang/Class", "name", Value::Utf8(name.into()));
|
||||||
|
let instance = Ref(ObjectRef::Object(instance));
|
||||||
|
|
||||||
|
self.class_objects.insert(this_classid, instance);
|
||||||
|
}
|
||||||
|
let clinit = this_classdef.methods.contains_key("<clinit>()V");
|
||||||
|
|
||||||
|
if clinit {
|
||||||
|
self.vm.execute_special(&mut vec![],name, "<clinit>()V", vec![]).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
this_classid
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_fields_for_this_or_parents(object_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
|
||||||
|
static_field_mapping: &mut HashMap<String, HashMap<String, TypeIndex>>,
|
||||||
|
object_field_map_index: &mut usize, static_field_map_index:
|
||||||
|
&mut usize,
|
||||||
|
current_classdef: &ClassDef) {
|
||||||
|
let mut instance_field_mappings: HashMap<String, TypeIndex> = HashMap::new();
|
||||||
|
let mut static_field_mappings: HashMap<String, TypeIndex> = HashMap::new();
|
||||||
|
for (field_name, field) in ¤t_classdef.fields {
|
||||||
|
if !field.is(Modifier::Static) {
|
||||||
|
instance_field_mappings.insert(field_name.to_owned(),
|
||||||
|
TypeIndex::new(field.type_of().to_owned(), *object_field_map_index));
|
||||||
|
*object_field_map_index += 1;
|
||||||
|
} else {
|
||||||
|
static_field_mappings.insert(field_name.to_owned(),
|
||||||
|
TypeIndex::new(field.type_of().to_owned(), *static_field_map_index));
|
||||||
|
*static_field_map_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object_field_mapping.insert(current_classdef.name().to_owned(), instance_field_mappings);
|
||||||
|
static_field_mapping.insert(current_classdef.name().to_owned(), static_field_mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// loads the class and recursively its dependencies
|
||||||
|
fn load(&mut self, name: &str) -> ClassId {
|
||||||
|
let (id, mut classes_to_load) = self.load_class_and_deps(name);
|
||||||
|
while !classes_to_load.is_empty() {
|
||||||
|
if let Some(classname) = classes_to_load.pop() {
|
||||||
|
classes_to_load.append(&mut self.load_class_and_deps(classname.as_str()).1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// loads the class and returns it's dependencies
|
||||||
|
fn load_class_and_deps(&mut self, name: &str) -> (ClassId, Vec<String>) {
|
||||||
|
let id = *self.names.entry(name.to_string()).or_insert_with(|| {
|
||||||
|
self.current_id += 1;
|
||||||
|
self.current_id
|
||||||
|
});
|
||||||
|
|
||||||
|
let classdef = self.classdefs
|
||||||
|
.entry(id)
|
||||||
|
.or_insert_with(|| classloader::get_classdef(&self.classpath, name).expect("ClassNotFound"));
|
||||||
|
(self.current_id, inspect_dependencies(classdef))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_field_data(field_mapping: &HashMap<String, HashMap<String, TypeIndex>>) -> Vec<Value> {
|
||||||
|
let mut field_data = vec![Null; n_fields(field_mapping)];
|
||||||
|
|
||||||
|
for (_, this_class) in field_mapping {
|
||||||
|
for (_name, type_index) in this_class {
|
||||||
|
let value = match type_index.type_name.as_str() {
|
||||||
|
"Z" => BOOL(false),
|
||||||
|
"B" => I32(0),
|
||||||
|
"S" => I32(0),
|
||||||
|
"I" => I32(0),
|
||||||
|
"J" => I64(0),
|
||||||
|
"F" => F32(0.0),
|
||||||
|
"D" => F64(0.0),
|
||||||
|
_ => Null,
|
||||||
|
};
|
||||||
|
// println!("{} = {:?}", name, value);
|
||||||
|
field_data[type_index.index] = value.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
field_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn n_fields(field_mapping: &HashMap<String, HashMap<String, TypeIndex>>) -> usize {
|
||||||
|
field_mapping
|
||||||
|
.iter()
|
||||||
|
.map(|(_, v)| v.len())
|
||||||
|
.reduce(|acc, e| acc + e)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn inspect_dependencies(classdef: &ClassDef) -> Vec<String> {
|
||||||
|
let mut classes_to_load: Vec<String> = vec![];
|
||||||
|
|
||||||
|
if let Some(superclass) = &classdef.super_class {
|
||||||
|
classes_to_load.push(classdef.cp_class_name(superclass).into());
|
||||||
|
}
|
||||||
|
for interface in &classdef.interfaces {
|
||||||
|
classes_to_load.push(classdef.cp_class_name(interface).into());
|
||||||
|
}
|
||||||
|
classes_to_load
|
||||||
|
}
|
||||||
190
src/heap.rs
190
src/heap.rs
|
|
@ -1,190 +0,0 @@
|
||||||
use std::cell::{RefCell, UnsafeCell};
|
|
||||||
use std::fmt;
|
|
||||||
use std::fmt::{Debug, Formatter};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use ObjectRef::{BooleanArray, CharArray, DoubleArray, FloatArray, LongArray, ShortArray};
|
|
||||||
|
|
||||||
use crate::class::{Class, Type, Value};
|
|
||||||
use crate::heap::ObjectRef::{ByteArray, IntArray, ObjectArray, StringArray};
|
|
||||||
|
|
||||||
// can contain object or array
|
|
||||||
pub enum ObjectRef {
|
|
||||||
ByteArray(Vec<i8>),
|
|
||||||
ShortArray(Vec<i16>),
|
|
||||||
IntArray(Vec<i32>),
|
|
||||||
LongArray(Vec<i64>),
|
|
||||||
FloatArray(Vec<f32>),
|
|
||||||
DoubleArray(Vec<f64>),
|
|
||||||
BooleanArray(Vec<bool>),
|
|
||||||
CharArray(Vec<char>),
|
|
||||||
StringArray(Vec<String>),
|
|
||||||
ObjectArray(Type, Vec<Arc<UnsafeCell<ObjectRef>>>),
|
|
||||||
Object(Box<Object>),//Box necessary??
|
|
||||||
Class(Arc<RefCell<Class>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectRef {
|
|
||||||
pub fn get_array_length(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
ByteArray(d) => d.len(),
|
|
||||||
ShortArray(d) => d.len(),
|
|
||||||
IntArray(d) => d.len(),
|
|
||||||
LongArray(d) => d.len(),
|
|
||||||
FloatArray(d) => d.len(),
|
|
||||||
DoubleArray(d) => d.len(),
|
|
||||||
BooleanArray(d) => d.len(),
|
|
||||||
CharArray(d) => d.len(),
|
|
||||||
StringArray(d) => d.len(),
|
|
||||||
ObjectArray(_, d) => d.len(),
|
|
||||||
_ => unreachable!("not an array")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_vec_i8(v: Vec<u8>) -> Vec<i8> {
|
|
||||||
let mut v = std::mem::ManuallyDrop::new(v);
|
|
||||||
|
|
||||||
// then, pick apart the existing Vec
|
|
||||||
let p = v.as_mut_ptr();
|
|
||||||
let len = v.len();
|
|
||||||
let cap = v.capacity();
|
|
||||||
|
|
||||||
// finally, adopt the data into a new Vec
|
|
||||||
unsafe { Vec::from_raw_parts(p as *mut i8, len, cap) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectRef {
|
|
||||||
pub fn new_object_array(class: Type, size: usize) -> Self {
|
|
||||||
ObjectArray(class, Vec::with_capacity(size))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_int_array(size: usize) -> Self {
|
|
||||||
IntArray(Vec::with_capacity(size))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_byte_array(d: Vec<u8>) -> Arc<UnsafeCell<Self>> {
|
|
||||||
Arc::new(UnsafeCell::new(ByteArray(into_vec_i8(d))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for ObjectRef {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
BooleanArray(d) => write!(f, "[Z;{}]", d.len()),
|
|
||||||
ByteArray(d) => write!(f, "[B;{}]", d.len()),
|
|
||||||
CharArray(d) => write!(f, "[C;{}]", d.len()),
|
|
||||||
DoubleArray(d) => write!(f, "[D;{}]", d.len()),
|
|
||||||
FloatArray(d) => write!(f, "[F;{}]", d.len()),
|
|
||||||
IntArray(d) => write!(f, "[I;{}]", d.len()),
|
|
||||||
LongArray(d) => write!(f, "[J;{}]", d.len()),
|
|
||||||
ObjectArray(t, d) => write!(f, "[L{};{}]", t.borrow().name, d.len()),
|
|
||||||
ShortArray(d) => write!(f, "[S;{}]", d.len()),
|
|
||||||
StringArray(d) => write!(f, "[S;{}]", d.len()),
|
|
||||||
ObjectRef::Object(r) => write!(f, "{}{{ {:?} }}", r.class.borrow().name, r.data),
|
|
||||||
ObjectRef::Class(s) => write!(f, "Class {:?}", s.borrow().name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// trying to implement efficient object instance storage
|
|
||||||
pub struct Object {
|
|
||||||
// locked: bool,
|
|
||||||
// hashcode: i32,
|
|
||||||
pub class: Arc<RefCell<Class>>,
|
|
||||||
pub data: Vec<Value>,
|
|
||||||
} //arrays
|
|
||||||
|
|
||||||
unsafe impl Send for Object {}
|
|
||||||
|
|
||||||
unsafe impl Sync for Object {}
|
|
||||||
|
|
||||||
// object, not array
|
|
||||||
impl Object {
|
|
||||||
pub fn new(class: Arc<RefCell<Class>>) -> Self {
|
|
||||||
let instance_data = Object::init_fields(class.clone());
|
|
||||||
Self {
|
|
||||||
class,
|
|
||||||
data: instance_data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initializes all non-static fields to their default values
|
|
||||||
pub(crate) fn init_fields(class: Arc<RefCell<Class>>) -> Vec<Value> {
|
|
||||||
let mut field_data = Vec::with_capacity(class.borrow().n_object_fields());
|
|
||||||
|
|
||||||
for (_, fields) in &class.borrow().object_field_mapping {
|
|
||||||
for (_, type_index) in fields {
|
|
||||||
let value = match type_index.type_name.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),
|
|
||||||
_ => Value::Null,
|
|
||||||
};
|
|
||||||
field_data.push(value.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
field_data
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(&mut self, class_name: &String, field_name: &String, value: Value) {
|
|
||||||
let borrow = self.class.borrow();
|
|
||||||
let type_index = borrow
|
|
||||||
.object_field_mapping
|
|
||||||
.get(class_name)
|
|
||||||
.unwrap()
|
|
||||||
.get(field_name)
|
|
||||||
.unwrap();
|
|
||||||
self.data[type_index.index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&mut self, class_name: &String, field_name: &String) -> &Value {
|
|
||||||
let borrow = self.class.borrow();
|
|
||||||
let type_index = borrow
|
|
||||||
.object_field_mapping
|
|
||||||
.get(class_name)
|
|
||||||
.unwrap()
|
|
||||||
.get(field_name)
|
|
||||||
.unwrap();
|
|
||||||
&self.data[type_index.index]
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn get_field_name(&self, cp_index: &u16) -> &str {
|
|
||||||
// if let CpEntry::Utf8(name) = self.class.constant_pool.get(cp_index).unwrap() {
|
|
||||||
// return name;
|
|
||||||
// }
|
|
||||||
// panic!()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Object {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
// let fields: Vec<String> = self.data.unwrap().iter().map(|(k)| {
|
|
||||||
// // let mut r: String = self.get_field_name(k).into();
|
|
||||||
// // r.push(':');
|
|
||||||
// // r.push_str(format!("{:?}").as_str());
|
|
||||||
// // r
|
|
||||||
// }
|
|
||||||
// ).collect();
|
|
||||||
write!(f, "{}", self.class.borrow().name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// will using Arc's enable a GC-less heap????
|
|
||||||
pub(crate) struct Heap {
|
|
||||||
objects: Vec<Arc<UnsafeCell<ObjectRef>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Heap {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self { objects: vec![] }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn new_object(&mut self, object: Arc<UnsafeCell<ObjectRef>>) {
|
|
||||||
self.objects.push(object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
|
mod classloader;
|
||||||
|
pub mod classmanager;
|
||||||
pub mod class;
|
pub mod class;
|
||||||
pub mod classloader;
|
|
||||||
pub mod heap;
|
|
||||||
pub mod io;
|
|
||||||
pub mod opcodes;
|
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
|
pub mod heap;
|
||||||
pub mod native;
|
|
||||||
18
src/main.rs
18
src/main.rs
|
|
@ -1,17 +1,11 @@
|
||||||
use std::io::Error;
|
use java_rs::classmanager::set_classpath;
|
||||||
use java_rs::vm::Vm;
|
use java_rs::vm::Vm;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut stackframes = Vec::new();
|
||||||
fn main() -> Result<(), Error> {
|
let mut vm = Vm::new(&mut stackframes);
|
||||||
// TODO cmdline args
|
set_classpath("/Users/Shautvast/dev/java/tests");
|
||||||
// TODO build index for package -> jarfile?
|
|
||||||
|
|
||||||
let mut vm = Vm::new("tests");
|
|
||||||
// let main_class = "Inheritance";
|
|
||||||
let main_class = "testclasses.Main";
|
let main_class = "testclasses.Main";
|
||||||
|
vm.execute_static( &mut stackframes, main_class, "main([Ljava/lang/String;)V", vec![])
|
||||||
vm.execute_static( main_class, "main([Ljava/lang/String;)V", vec![])
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use crate::class::Value::{self,*};
|
|
||||||
use crate::heap::ObjectRef;
|
|
||||||
|
|
||||||
pub(crate) unsafe fn array_load(index: Value, arrayref: Value) -> Result<Value, Error> {
|
use crate::class::ObjectRef;
|
||||||
if let I32(index) = &index {
|
use crate::class::Value::{self, *};
|
||||||
let index = *index as usize;
|
|
||||||
|
pub(crate) fn array_load(index: Value, arrayref: Value) -> Result<Value, Error> {
|
||||||
|
if let I32(index) = index {
|
||||||
|
let index = index as usize;
|
||||||
|
|
||||||
if let Null = arrayref {
|
if let Null = arrayref {
|
||||||
return Err(anyhow!("NullpointerException"));
|
return Err(anyhow!("NullpointerException"));
|
||||||
}
|
}
|
||||||
if let Ref(objectref) = arrayref {
|
if let Ref(objectref) = arrayref {
|
||||||
match &*objectref.get() {
|
match objectref {
|
||||||
ObjectRef::ByteArray(array) => {
|
ObjectRef::ByteArray(array) => {
|
||||||
return Ok(I32(array[index] as i32));
|
return Ok(I32(array[index] as i32));
|
||||||
}
|
}
|
||||||
|
|
@ -53,14 +54,14 @@ pub(crate) unsafe fn array_load(index: Value, arrayref: Value) -> Result<Value,
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn array_store(value: Value, index: Value, arrayref: &mut Value) -> Result<(), Error> {
|
pub(crate) fn array_store(value: Value, index: Value, arrayref: Value) -> Result<(), Error> {
|
||||||
if let Null = &*arrayref {
|
if let Null = arrayref {
|
||||||
return Err(anyhow!("NullpointerException"));
|
return Err(anyhow!("NullpointerException"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let I32(index) = index {
|
if let I32(index) = index {
|
||||||
if let Ref(ref mut objectref) = arrayref {
|
if let Ref(mut objectref) = arrayref {
|
||||||
match &mut *objectref.get() {
|
match objectref {
|
||||||
ObjectRef::ByteArray(ref mut array) => {
|
ObjectRef::ByteArray(ref mut array) => {
|
||||||
if let I32(value) = value {
|
if let I32(value) = value {
|
||||||
// is i32 correct?
|
// is i32 correct?
|
||||||
|
|
@ -91,7 +92,7 @@ pub(crate) unsafe fn array_store(value: Value, index: Value, arrayref: &mut Valu
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::CharArray(ref mut array) => {
|
ObjectRef::CharArray(ref mut array) => unsafe{
|
||||||
if let I32(value) = value {
|
if let I32(value) = value {
|
||||||
array[index as usize] = char::from_u32_unchecked(value as u32);
|
array[index as usize] = char::from_u32_unchecked(value as u32);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,5 @@ pub use vm::Vm;
|
||||||
mod operations;
|
mod operations;
|
||||||
mod stack;
|
mod stack;
|
||||||
mod array;
|
mod array;
|
||||||
|
mod opcodes;
|
||||||
|
mod native;
|
||||||
|
|
@ -1,48 +1,48 @@
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use std::ptr::hash;
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use log::{debug, info};
|
use log::{info};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::class::{get_class, unsafe_ref, Value};
|
use crate::class::{ObjectRef, Value};
|
||||||
|
use crate::class::ObjectRef::Object;
|
||||||
use crate::class::Value::Void;
|
use crate::class::Value::Void;
|
||||||
use crate::heap::ObjectRef;
|
use crate::classmanager;
|
||||||
use crate::heap::ObjectRef::Object;
|
use crate::vm::stack::StackFrame;
|
||||||
use crate::vm::Vm;
|
use crate::vm::Vm;
|
||||||
|
|
||||||
pub fn invoke_native(vm: &mut Vm, class_name: &String, method_name: &String, _args: Vec<Value>) -> Result<Value,Error> {
|
pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec<StackFrame>, class_name: &String, method_name: &str, _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(vm, method_name),
|
"java/lang/Class" => java_lang_class(vm, method_name),
|
||||||
"jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(vm, method_name),
|
"jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(vm, stackframes, method_name),
|
||||||
_ => Ok(Void)
|
_ => Ok(Void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn java_lang_class(_vm: &mut Vm, method_name: &String) -> Result<Value,Error> {
|
fn java_lang_class(_vm: &Vm, method_name: &str) -> Result<Value, Error> {
|
||||||
Ok(match method_name.as_str() {
|
Ok(match method_name {
|
||||||
"desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false),
|
"desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false),
|
||||||
_ => Void
|
_ => Void
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn jdk_internal_util_SystemProps_Raw(vm: &mut Vm,method_name: &String) -> Result<Value,Error> {
|
fn jdk_internal_util_SystemProps_Raw(vm: &mut Vm, stackframes: &mut Vec<StackFrame>, method_name: &str) -> Result<Value, Error> {
|
||||||
match method_name.as_str() {
|
match method_name {
|
||||||
"platformProperties()[Ljava/lang/String;" => systemProps(),
|
"platformProperties()[Ljava/lang/String;" => systemProps(),
|
||||||
"cmdProperties()Ljava/util/HashMap;" => cmdProps(vm), //TODO ability to instantiate classes here
|
"cmdProperties()Ljava/util/HashMap;" => cmdProps(vm, stackframes), //TODO ability to instantiate classes here
|
||||||
"vmProperties()[Ljava/lang/String;" => cmdProps(vm),
|
"vmProperties()[Ljava/lang/String;" => cmdProps(vm, stackframes),
|
||||||
_ => Ok(Void)
|
_ => Ok(Void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmdProps(vm: &mut Vm,) -> Result<Value,Error> {
|
fn cmdProps(vm: &mut Vm, stackframes: &mut Vec<StackFrame>) -> Result<Value, Error> {
|
||||||
let hashmap_class = get_class(vm, "java/util/HashMap")?;
|
classmanager::load_class_by_name("java/util/HashMap");
|
||||||
|
let hashmap_class = classmanager::get_class_by_name("java/util/HashMap").unwrap();
|
||||||
let hashmap = Vm::new_instance(hashmap_class);
|
let hashmap = Vm::new_instance(hashmap_class);
|
||||||
let hashmap = Value::Ref(unsafe_ref(Object(Box::new(hashmap))));
|
let hashmap = Value::Ref(Object(hashmap));
|
||||||
vm.execute_special("java/util/HashMap", "<init>()V", vec![hashmap.clone()]);
|
vm.execute_special(stackframes, "java/util/HashMap", "<init>()V", vec![hashmap.clone()]);
|
||||||
unsafe {debug!("hashmap {:?}", *hashmap.into_object().get());}
|
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,6 +131,6 @@ fn systemProps() -> Result<Value,Error> {
|
||||||
|
|
||||||
vec
|
vec
|
||||||
});
|
});
|
||||||
Ok(Value::Ref(unsafe_ref(ObjectRef::StringArray(props.to_vec()))))
|
Ok(Value::Ref(ObjectRef::StringArray(props.to_vec())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,29 +1,27 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
|
|
||||||
use crate::class::{Class, get_class, Value};
|
use crate::class::{Class, Value};
|
||||||
use crate::classloader::CpEntry;
|
use crate::classloader::classdef::CpEntry;
|
||||||
use crate::vm::Vm;
|
use crate::classmanager;
|
||||||
use crate::vm::vm::{Invocation, MethodSignature};
|
use crate::vm::vm::{Invocation, MethodSignature};
|
||||||
|
|
||||||
/// the place for opcode implementations that are a bit long
|
/// the place for opcode implementations that are a bit long
|
||||||
|
|
||||||
// GET_STATIC opcode
|
// GET_STATIC opcode
|
||||||
pub(crate) fn get_static(vm: &mut Vm, this_class: Arc<RefCell<Class>>, field_index: u16) -> Result<Value,Error> {
|
pub(crate) fn get_static(this_class: &Class, field_index: u16) -> Result<Value, Error> {
|
||||||
let this_class = this_class.borrow();
|
let classdef = classmanager::get_classdef(&this_class.id);
|
||||||
let (class_index, field_name_and_type_index) =
|
let (class_index, field_name_and_type_index) =
|
||||||
this_class.cp_field_ref(&field_index); // all these unwraps are safe as long as the class is valid
|
classdef.cp_field_ref(&field_index); // all these unwraps are safe as long as the class is valid
|
||||||
let (name_index, _) =
|
let (name_index, _) =
|
||||||
this_class.cp_name_and_type(field_name_and_type_index);
|
classdef.cp_name_and_type(field_name_and_type_index);
|
||||||
let field_name = this_class.cp_utf8(name_index);
|
let field_name = classdef.cp_utf8(name_index);
|
||||||
|
|
||||||
let that_class_name_index = this_class.cp_class_ref(class_index);
|
let that_class_name_index = classdef.cp_class_ref(class_index);
|
||||||
let that_class_name = this_class.cp_utf8(that_class_name_index);
|
let that_class_name = classdef.cp_utf8(that_class_name_index);
|
||||||
let that_class = get_class(vm, that_class_name.as_str())?;
|
classmanager::load_class_by_name(that_class_name);
|
||||||
let that_class = that_class.borrow();
|
let that_class = classmanager::get_class_by_name(that_class_name).unwrap();
|
||||||
|
|
||||||
let type_index = that_class
|
let type_index = that_class
|
||||||
.static_field_mapping
|
.static_field_mapping
|
||||||
|
|
@ -32,10 +30,10 @@ pub(crate) fn get_static(vm: &mut Vm, this_class: Arc<RefCell<Class>>, field_ind
|
||||||
.get(field_name)
|
.get(field_name)
|
||||||
.unwrap(); // safe because field must be there
|
.unwrap(); // safe because field must be there
|
||||||
|
|
||||||
Ok(that_class.static_data[type_index.index].clone())
|
Ok(classmanager::get_static(&this_class.id, type_index.index))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<MethodSignature> {
|
pub(crate) fn get_name_and_type(cp: &HashMap<u16, CpEntry>, index: u16) -> Option<MethodSignature> {
|
||||||
if let CpEntry::NameAndType(method_name_index, signature_index) = cp.get(&index).unwrap() {
|
if let CpEntry::NameAndType(method_name_index, signature_index) = cp.get(&index).unwrap() {
|
||||||
if let CpEntry::Utf8(method_name) = cp.get(method_name_index).unwrap() {
|
if let CpEntry::Utf8(method_name) = cp.get(method_name_index).unwrap() {
|
||||||
if let CpEntry::Utf8(signature) = cp.get(signature_index).unwrap() {
|
if let CpEntry::Utf8(signature) = cp.get(signature_index).unwrap() {
|
||||||
|
|
@ -48,11 +46,12 @@ pub(crate) fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Op
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pub(crate) fn get_signature_for_invoke(cp: &Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<Invocation> {
|
|
||||||
|
pub(crate) fn get_signature_for_invoke(cp: &HashMap<u16, CpEntry>, index: u16) -> Option<Invocation> {
|
||||||
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) = cp.get(&index).unwrap()
|
| CpEntry::InterfaceMethodref(class_index, name_and_type_index) = cp.get(&index).unwrap()
|
||||||
{
|
{
|
||||||
if let Some(method_signature) = get_name_and_type(Rc::clone(&cp), *name_and_type_index) {
|
if let Some(method_signature) = get_name_and_type(cp, *name_and_type_index) {
|
||||||
if let CpEntry::ClassRef(class_name_index) = cp.get(class_index).unwrap() {
|
if let CpEntry::ClassRef(class_name_index) = cp.get(class_index).unwrap() {
|
||||||
if let CpEntry::Utf8(class_name) = cp.get(class_name_index).unwrap() {
|
if let CpEntry::Utf8(class_name) = cp.get(class_name_index).unwrap() {
|
||||||
return Some(Invocation::new(
|
return Some(Invocation::new(
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
use crate::class::Value;
|
use crate::class::Value;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct StackFrame {
|
pub struct StackFrame {
|
||||||
pub(crate) at: String,
|
pub(crate) at: String,
|
||||||
pub(crate) data: Vec<Value>,
|
pub(crate) data: Vec<Value>,
|
||||||
}
|
}
|
||||||
|
|
@ -17,12 +19,14 @@ impl StackFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn push(&mut self, val: Value) {
|
pub(crate) fn push(&mut self, val: Value) {
|
||||||
|
debug!("push {:?}", val);
|
||||||
self.data.push(val);
|
self.data.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn len(&self) -> usize {
|
pub(crate) fn len(&self) -> usize {
|
||||||
self.data.len()
|
self.data.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn pop(&mut self) -> Result<Value, Error> {
|
pub(crate) fn pop(&mut self) -> Result<Value, Error> {
|
||||||
Ok(self.data.pop().unwrap())
|
Ok(self.data.pop().unwrap())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
523
src/vm/vm.rs
523
src/vm/vm.rs
|
|
@ -1,42 +1,22 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::Error;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
|
|
||||||
use Value::*;
|
use crate::class::{Class, ClassId, Object, ObjectRef, Value};
|
||||||
|
use crate::class::Value::{F32, F64, I32, I64, Null, Ref, Utf8, Void};
|
||||||
use crate::class::{AttributeType, Class, CLASSES, get_class, Method, Modifier, unsafe_ref, Value};
|
use crate::classloader::classdef::{AttributeType, CpEntry, Method, Modifier};
|
||||||
use crate::class::Value::{Null, Void};
|
use crate::classloader::io::{read_u16, read_u8};
|
||||||
use crate::classloader::CpEntry;
|
use crate::classmanager;
|
||||||
use crate::heap::{Heap, Object, ObjectRef};
|
|
||||||
use crate::io::*;
|
|
||||||
use crate::native::invoke_native;
|
|
||||||
use crate::opcodes;
|
|
||||||
use crate::opcodes::*;
|
|
||||||
use crate::vm::array::{array_load, array_store};
|
use crate::vm::array::{array_load, array_store};
|
||||||
|
use crate::vm::native::invoke_native;
|
||||||
|
use crate::vm::opcodes;
|
||||||
|
use crate::vm::opcodes::*;
|
||||||
use crate::vm::operations::{get_signature_for_invoke, get_static};
|
use crate::vm::operations::{get_signature_for_invoke, get_static};
|
||||||
use crate::vm::stack::StackFrame;
|
use crate::vm::stack::StackFrame;
|
||||||
|
|
||||||
pub struct Vm {
|
pub struct Vm {}
|
||||||
pub classpath: Vec<String>,
|
|
||||||
heap: Heap,
|
|
||||||
pub(crate) stackframes: Vec<StackFrame>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vm {
|
|
||||||
fn init(vm: &mut Vm) {
|
|
||||||
Self::initialize_class(vm, "java/lang/System");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn initialize_class(vm: &mut Vm, class: &str) {
|
|
||||||
vm.execute_static(class, "initPhase1()V", vec![]).expect("cannot create VM");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
const PATH_SEPARATOR: char = ':';
|
const PATH_SEPARATOR: char = ':';
|
||||||
|
|
@ -48,81 +28,89 @@ const PATH_SEPARATOR: char = ';';
|
||||||
//TODO goto
|
//TODO goto
|
||||||
//TODO error handling
|
//TODO error handling
|
||||||
impl Vm {
|
impl Vm {
|
||||||
fn current_frame(&mut self) -> &mut StackFrame {
|
|
||||||
let i = self.stackframes.len() - 1;
|
/// for running static initializers
|
||||||
self.stackframes.get_mut(i).unwrap()
|
pub fn new_internal() -> Self {
|
||||||
|
Self {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(classpath: &'static str) -> Self {
|
pub fn new(stack: &mut Vec<StackFrame>) -> Self {
|
||||||
env_logger::builder()
|
env_logger::builder()
|
||||||
.format(|buf, record| {
|
.format(|buf, record| {
|
||||||
writeln!(buf, "{}: {}", record.level(), record.args())
|
writeln!(buf, "{}: {}", record.level(), record.args())
|
||||||
})
|
})
|
||||||
.init();
|
.try_init();
|
||||||
let mut vm_instance = Self {
|
let mut vm_instance = Self {};
|
||||||
classpath: classpath
|
classmanager::init();
|
||||||
.split(PATH_SEPARATOR)
|
Vm::init(&mut vm_instance, stack);
|
||||||
.map(|s| s.to_owned())
|
|
||||||
.collect(),
|
|
||||||
heap: Heap::new(),
|
|
||||||
stackframes: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
Vm::init(&mut vm_instance);
|
|
||||||
|
|
||||||
vm_instance
|
vm_instance
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_instance(class: Arc<RefCell<Class>>) -> Object {
|
fn init(vm: &mut Vm, stack: &mut Vec<StackFrame>) {
|
||||||
Object::new(class.clone())
|
classmanager::load_class_by_name("java/lang/Class");
|
||||||
|
Self::initialize_class(vm, stack, "java/lang/System");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize_class(vm: &mut Vm, stack: &mut Vec<StackFrame>, class: &str) {
|
||||||
|
vm.execute_static(stack, class, "initPhase1()V", vec![]).expect("cannot create VM");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_frame(stackframes: &mut Vec<StackFrame>) -> &mut StackFrame {
|
||||||
|
let i = stackframes.len() - 1;
|
||||||
|
stackframes.get_mut(i).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_instance(class: &Class) -> Object {
|
||||||
|
Object::new(class)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// execute the bytecode
|
/// execute the bytecode
|
||||||
/// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM
|
|
||||||
pub fn execute_virtual(
|
pub fn execute_virtual(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
stack: &mut Vec<StackFrame>,
|
||||||
class_name: &str,
|
class_name: &str,
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
unsafe {
|
|
||||||
for arg in &args {
|
for arg in &args {
|
||||||
if let Ref(r) = arg {
|
if let Ref(r) = arg {
|
||||||
info!("arg {:?}",&*r.get());
|
info!("arg {:?}",r);
|
||||||
} else {
|
} else {
|
||||||
info!("arg {:?}",arg);
|
info!("arg {:?}",arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if let Null = args[0] {
|
if let Null = args[0] {
|
||||||
panic!("NPE");
|
panic!("NPE");
|
||||||
}
|
}
|
||||||
if let Ref(this) = &args[0] {
|
if let Ref(this) = &args[0] {
|
||||||
if let ObjectRef::Object(this) = &*this.get() {
|
if let ObjectRef::Object(this) = this {
|
||||||
let class = &this.class;
|
let cd = classmanager::get_classdef(&this.class_id);
|
||||||
let borrow = class.borrow();
|
let method = cd.get_method(method_name);
|
||||||
let method = borrow.get_method(method_name);
|
|
||||||
if let Some(method) = method {
|
if let Some(method) = method {
|
||||||
return self.execute_class(class.clone(), method.clone(), args);
|
return self.execute_class_id(stack, this.class_id, &method, args.clone());
|
||||||
} else {
|
} else {
|
||||||
for s in &borrow.super_classes {
|
let name = classmanager::classdef_name(&this.class_id);
|
||||||
let borrow2 = s.borrow();
|
if let Some(name) = name {
|
||||||
let method = borrow2.get_method(method_name);
|
classmanager::load_class_by_name(&name);
|
||||||
|
let class = classmanager::get_class_by_name(&name).unwrap();
|
||||||
|
for parent_id in &class.parents {
|
||||||
if let Some(method) = method {
|
if let Some(method) = method {
|
||||||
return self.execute_class(class.clone(), method.clone(), args);
|
return self.execute_class(stack, class, method_name, args);
|
||||||
} else {
|
} else {
|
||||||
debug!("not {:?}", s);
|
debug!("not {:?}", parent_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("not found {}", method_name);
|
} else {
|
||||||
|
panic!("ClassNotFound");
|
||||||
}
|
}
|
||||||
} else if let ObjectRef::Class(class) = &*this.get() {
|
|
||||||
let klazz = get_class(self, "java/lang/Class")?;
|
|
||||||
let borrow = klazz.borrow();
|
|
||||||
let method = borrow.get_method(method_name).unwrap();
|
|
||||||
return self.execute_class(class.clone(), method.clone(), args);
|
|
||||||
}
|
}
|
||||||
|
} else if let ObjectRef::Class(_class) = this {
|
||||||
|
//TODO is this right??
|
||||||
|
classmanager::load_class_by_name("java/lang/Class");//TODO preload, so this is not needed
|
||||||
|
let klazz = classmanager::get_class_by_name("java/lang/Class").unwrap();
|
||||||
|
// let klazzdef = self.classmanager.get_classdef(&klazz.id);
|
||||||
|
return self.execute_class(stack, klazz, method_name, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("this is not an object reference {}", class_name);
|
println!("this is not an object reference {}", class_name);
|
||||||
|
|
@ -131,137 +119,139 @@ impl Vm {
|
||||||
|
|
||||||
pub fn execute_special(
|
pub fn execute_special(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
stack: &mut Vec<StackFrame>,
|
||||||
class_name: &str,
|
class_name: &str,
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
let class = get_class(self, class_name)?;
|
classmanager::load_class_by_name(class_name);
|
||||||
let method = class.clone().borrow().get_method(method_name).expect("execute special needs invoked method on the class").clone();
|
let class = classmanager::get_class_by_name(class_name).unwrap();
|
||||||
self.execute_class(class.clone(), method.clone(), args)
|
self.execute_class(stack, class, method_name, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_static(
|
pub fn execute_static(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
stack: &mut Vec<StackFrame>,
|
||||||
class_name: &str,
|
class_name: &str,
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
let class = get_class(self, class_name)?;
|
classmanager::load_class_by_name(class_name);
|
||||||
let method = class.clone().borrow().get_method(method_name).expect("execute static needs this method").clone();
|
let class = classmanager::get_class_by_name(class_name).unwrap();
|
||||||
self.execute_class(class, method, args)
|
let _classdef = classmanager::get_classdef(&class.id);
|
||||||
|
self.execute_class(stack, class, method_name, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_class_id(&self, _stack: &mut Vec<StackFrame>, _this_class: ClassId, _method: &Method, _args: Vec<Value>) -> Result<Value, Error> {
|
||||||
|
Ok(Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_class(
|
pub fn execute_class(
|
||||||
&mut self,
|
&mut self,
|
||||||
class: Arc<RefCell<Class>>,
|
stackframes: &mut Vec<StackFrame>,
|
||||||
method: Rc<Method>,
|
this_class: &Class,
|
||||||
|
method_name: &str,
|
||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
let this_class = class;
|
info!("execute {}.{}", this_class.name, method_name);
|
||||||
info!("execute {}.{}", this_class.borrow().name, method.name());
|
|
||||||
|
|
||||||
//TODO implement dynamic dispatch -> get method from instance
|
//TODO implement dynamic dispatch -> get method from instance
|
||||||
|
let method = classmanager::get_classdef(&this_class.id).get_method(method_name).unwrap();
|
||||||
let mut local_params: Vec<Option<Value>> =
|
let mut local_params: Vec<Option<Value>> =
|
||||||
args.clone().iter().map(|e| Some(e.clone())).collect();
|
args.clone().iter().map(|e| Some(e.clone())).collect();
|
||||||
if method.is(Modifier::Native) {
|
if method.is(Modifier::Native) {
|
||||||
return invoke_native(self, &this_class.borrow().name, &method.name(), args);
|
return invoke_native(self, stackframes, &this_class.name, method_name, args);
|
||||||
}
|
}
|
||||||
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
|
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
|
||||||
let stackframe = StackFrame::new(&this_class.borrow().name, &method.name());
|
let stackframe = StackFrame::new(&this_class.name, method_name);
|
||||||
self.stackframes.push(stackframe);
|
stackframes.push(stackframe);
|
||||||
|
|
||||||
let pc = &mut 0;
|
let 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);
|
||||||
let cur_frame = self.current_frame();
|
let cur_frame = Self::current_frame(stackframes);
|
||||||
info!("\t{} #{} {} - {}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.len());
|
info!("\t{} #{} {} - {}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.len());
|
||||||
match opcode {
|
match opcode {
|
||||||
ACONST_NULL => {
|
ACONST_NULL => {
|
||||||
self.current_frame().push(Value::Null);
|
Self::current_frame(stackframes).push(Value::Null);
|
||||||
}
|
}
|
||||||
ICONST_M1 => {
|
ICONST_M1 => {
|
||||||
self.current_frame().push(I32(-1));
|
Self::current_frame(stackframes).push(I32(-1));
|
||||||
}
|
}
|
||||||
ICONST_0 => {
|
ICONST_0 => {
|
||||||
self.current_frame().push(I32(0));
|
Self::current_frame(stackframes).push(I32(0));
|
||||||
}
|
}
|
||||||
ICONST_1 => {
|
ICONST_1 => {
|
||||||
self.current_frame().push(I32(1));
|
Self::current_frame(stackframes).push(I32(1));
|
||||||
}
|
}
|
||||||
ICONST_2 => {
|
ICONST_2 => {
|
||||||
self.current_frame().push(I32(2));
|
Self::current_frame(stackframes).push(I32(2));
|
||||||
}
|
}
|
||||||
ICONST_3 => {
|
ICONST_3 => {
|
||||||
self.current_frame().push(I32(3));
|
Self::current_frame(stackframes).push(I32(3));
|
||||||
}
|
}
|
||||||
ICONST_4 => {
|
ICONST_4 => {
|
||||||
self.current_frame().push(I32(4));
|
Self::current_frame(stackframes).push(I32(4));
|
||||||
}
|
}
|
||||||
ICONST_5 => {
|
ICONST_5 => {
|
||||||
self.current_frame().push(I32(5));
|
Self::current_frame(stackframes).push(I32(5));
|
||||||
}
|
}
|
||||||
LCONST_0 => {
|
LCONST_0 => {
|
||||||
self.current_frame().push(I64(0));
|
Self::current_frame(stackframes).push(I64(0));
|
||||||
}
|
}
|
||||||
LCONST_1 => {
|
LCONST_1 => {
|
||||||
self.current_frame().push(I64(1));
|
Self::current_frame(stackframes).push(I64(1));
|
||||||
}
|
}
|
||||||
FCONST_0 => {
|
FCONST_0 => {
|
||||||
self.current_frame().push(F32(0.0));
|
Self::current_frame(stackframes).push(F32(0.0));
|
||||||
}
|
}
|
||||||
FCONST_1 => {
|
FCONST_1 => {
|
||||||
self.current_frame().push(F32(1.0));
|
Self::current_frame(stackframes).push(F32(1.0));
|
||||||
}
|
}
|
||||||
FCONST_2 => {
|
FCONST_2 => {
|
||||||
self.current_frame().push(F32(2.0));
|
Self::current_frame(stackframes).push(F32(2.0));
|
||||||
}
|
}
|
||||||
DCONST_0 => {
|
DCONST_0 => {
|
||||||
self.current_frame().push(F64(0.0));
|
Self::current_frame(stackframes).push(F64(0.0));
|
||||||
}
|
}
|
||||||
DCONST_1 => {
|
DCONST_1 => {
|
||||||
self.current_frame().push(F64(1.0));
|
Self::current_frame(stackframes).push(F64(1.0));
|
||||||
}
|
}
|
||||||
SIPUSH => {
|
SIPUSH => {
|
||||||
let s = read_u16(&code.opcodes, pc) as i32;
|
let s = read_u16(&code.opcodes, pc) as i32;
|
||||||
self.current_frame().push(I32(s));
|
Self::current_frame(stackframes).push(I32(s));
|
||||||
}
|
}
|
||||||
BIPUSH => {
|
BIPUSH => {
|
||||||
let c = read_u8(&code.opcodes, pc) as i32;
|
let c = read_u8(&code.opcodes, pc) as i32;
|
||||||
self.current_frame().push(I32(c));
|
Self::current_frame(stackframes).push(I32(c));
|
||||||
}
|
}
|
||||||
LDC => {
|
LDC => {
|
||||||
let cp_index = read_u8(&code.opcodes, pc) as u16;
|
let cp_index = read_u8(&code.opcodes, pc) as u16;
|
||||||
let c = method.constant_pool.get(&cp_index).unwrap();
|
let c = method.constant_pool.get(&cp_index).unwrap();
|
||||||
match c {
|
match c {
|
||||||
CpEntry::Integer(i) => {
|
CpEntry::Integer(i) => {
|
||||||
self.current_frame().push(I32(*i));
|
Self::current_frame(stackframes).push(I32(*i));
|
||||||
}
|
}
|
||||||
CpEntry::Float(f) => {
|
CpEntry::Float(f) => {
|
||||||
self.current_frame().push(Value::F32(*f));
|
Self::current_frame(stackframes).push(Value::F32(*f));
|
||||||
}
|
}
|
||||||
CpEntry::Double(d) => {
|
CpEntry::Double(d) => {
|
||||||
self.current_frame().push(Value::F64(*d));
|
Self::current_frame(stackframes).push(Value::F64(*d));
|
||||||
}
|
}
|
||||||
CpEntry::StringRef(utf8) => {
|
CpEntry::StringRef(utf8) => {
|
||||||
//TODO
|
//TODO
|
||||||
let stringclass = get_class(
|
classmanager::load_class_by_name("java/lang/String");
|
||||||
self,
|
let stringclass = classmanager::get_class_by_name("java/lang/String").unwrap();
|
||||||
"java/lang/String",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let stringinstance =
|
let stringinstance =
|
||||||
Ref(unsafe_ref(ObjectRef::Object(
|
Ref(ObjectRef::Object(Vm::new_instance(stringclass)));
|
||||||
Box::new(Vm::new_instance(stringclass.clone())),
|
|
||||||
)));
|
let string: Vec<u8> =
|
||||||
let string: Vec<u8> = this_class
|
classmanager::get_classdef(&this_class.id).cp_utf8(utf8)
|
||||||
.borrow()
|
|
||||||
.cp_utf8(utf8)
|
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
self.execute_special(
|
self.execute_special(stackframes,
|
||||||
"java/lang/String",
|
"java/lang/String",
|
||||||
"<init>([B)V",
|
"<init>([B)V",
|
||||||
vec![
|
vec![
|
||||||
|
|
@ -269,21 +259,22 @@ impl Vm {
|
||||||
Ref(ObjectRef::new_byte_array(string)),
|
Ref(ObjectRef::new_byte_array(string)),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
self.current_frame().push(stringinstance);
|
Self::current_frame(stackframes).push(stringinstance);
|
||||||
}
|
}
|
||||||
CpEntry::Long(l) => {
|
CpEntry::Long(l) => {
|
||||||
self.current_frame().push(Value::I64(*l));
|
Self::current_frame(stackframes).push(Value::I64(*l));
|
||||||
}
|
}
|
||||||
CpEntry::ClassRef(utf8) => {
|
CpEntry::ClassRef(utf8) => {
|
||||||
let class_name = this_class.borrow().cp_utf8(utf8).to_owned();
|
let classdef = classmanager::get_classdef(&this_class.id);
|
||||||
unsafe {
|
let class_name = classdef.cp_utf8(utf8);
|
||||||
if let Some(class) = CLASSES.get(&class_name) {
|
classmanager::load_class_by_name(class_name);
|
||||||
self.current_frame().push(class.clone());
|
let klass_id = classmanager::get_classid(class_name);
|
||||||
|
if let Some(class) = classmanager::get_classobject(klass_id) {
|
||||||
|
Self::current_frame(stackframes).push(class.clone());
|
||||||
} else {
|
} else {
|
||||||
unreachable!("should not be here");
|
unreachable!("should not be here");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
panic!("add variant {:?}", c)
|
panic!("add variant {:?}", c)
|
||||||
}
|
}
|
||||||
|
|
@ -294,14 +285,14 @@ impl Vm {
|
||||||
let cp_entry = method.constant_pool.get(&cp_index).unwrap();
|
let cp_entry = method.constant_pool.get(&cp_index).unwrap();
|
||||||
match cp_entry {
|
match cp_entry {
|
||||||
CpEntry::Integer(i) => {
|
CpEntry::Integer(i) => {
|
||||||
self.current_frame().push(I32(*i));
|
Self::current_frame(stackframes).push(I32(*i));
|
||||||
}
|
}
|
||||||
CpEntry::Float(f) => {
|
CpEntry::Float(f) => {
|
||||||
self.current_frame().push(F32(*f));
|
Self::current_frame(stackframes).push(F32(*f));
|
||||||
}
|
}
|
||||||
CpEntry::StringRef(utf8_index) => {
|
CpEntry::StringRef(utf8_index) => {
|
||||||
if let CpEntry::Utf8(s) = method.constant_pool.get(utf8_index).unwrap() {
|
if let CpEntry::Utf8(s) = method.constant_pool.get(utf8_index).unwrap() {
|
||||||
self.current_frame().push(Utf8(s.to_owned()));
|
Self::current_frame(stackframes).push(Utf8(s.to_owned()));
|
||||||
} else {}
|
} else {}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -314,10 +305,10 @@ impl Vm {
|
||||||
let cp_index = read_u16(&code.opcodes, pc);
|
let cp_index = read_u16(&code.opcodes, pc);
|
||||||
match method.constant_pool.get(&cp_index).unwrap() {
|
match method.constant_pool.get(&cp_index).unwrap() {
|
||||||
CpEntry::Double(d) => {
|
CpEntry::Double(d) => {
|
||||||
self.current_frame().push(Value::F64(*d));
|
Self::current_frame(stackframes).push(Value::F64(*d));
|
||||||
}
|
}
|
||||||
CpEntry::Long(l) => {
|
CpEntry::Long(l) => {
|
||||||
self.current_frame().push(Value::I64(*l));
|
Self::current_frame(stackframes).push(Value::I64(*l));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|
@ -327,115 +318,112 @@ impl Vm {
|
||||||
ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => {
|
ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => {
|
||||||
// omitting the type checks so far
|
// omitting the type checks so far
|
||||||
let n = read_u8(&code.opcodes, pc) as usize;
|
let n = read_u8(&code.opcodes, pc) as usize;
|
||||||
self.current_frame()
|
Self::current_frame(stackframes)
|
||||||
.push(local_params[n].as_ref().unwrap().clone());
|
.push(local_params[n].as_ref().unwrap().clone());
|
||||||
}
|
}
|
||||||
ILOAD_0 | LLOAD_0 | FLOAD_0 | DLOAD_0 | ALOAD_0 => {
|
ILOAD_0 | LLOAD_0 | FLOAD_0 | DLOAD_0 | ALOAD_0 => {
|
||||||
self.current_frame()
|
Self::current_frame(stackframes)
|
||||||
.push(local_params[0].as_ref().unwrap().clone());
|
.push(local_params[0].as_ref().unwrap().clone());
|
||||||
}
|
}
|
||||||
ILOAD_1 | LLOAD_1 | FLOAD_1 | DLOAD_1 | ALOAD_1 => {
|
ILOAD_1 | LLOAD_1 | FLOAD_1 | DLOAD_1 | ALOAD_1 => {
|
||||||
self.current_frame()
|
Self::current_frame(stackframes)
|
||||||
.push(local_params[1].as_ref().unwrap().clone());
|
.push(local_params[1].as_ref().unwrap().clone());
|
||||||
}
|
}
|
||||||
ILOAD_2 | LLOAD_2 | FLOAD_2 | DLOAD_2 | ALOAD_2 => {
|
ILOAD_2 | LLOAD_2 | FLOAD_2 | DLOAD_2 | ALOAD_2 => {
|
||||||
self.current_frame()
|
Self::current_frame(stackframes)
|
||||||
.push(local_params[2].as_ref().unwrap().clone());
|
.push(local_params[2].as_ref().unwrap().clone());
|
||||||
}
|
}
|
||||||
ILOAD_3 | LLOAD_3 | FLOAD_3 | DLOAD_3 | ALOAD_3 => {
|
ILOAD_3 | LLOAD_3 | FLOAD_3 | DLOAD_3 | ALOAD_3 => {
|
||||||
self.current_frame()
|
Self::current_frame(stackframes)
|
||||||
.push(local_params[3].as_ref().unwrap().clone());
|
.push(local_params[3].as_ref().unwrap().clone());
|
||||||
}
|
}
|
||||||
IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => unsafe {
|
IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => {
|
||||||
let index = self.current_frame().pop()?;
|
let index = Self::current_frame(stackframes).pop()?;
|
||||||
let arrayref = self.current_frame().pop()?;
|
let arrayref = Self::current_frame(stackframes).pop()?;
|
||||||
self.current_frame().push(array_load(index, arrayref)?);
|
Self::current_frame(stackframes).push(array_load(index, arrayref)?);
|
||||||
},
|
}
|
||||||
ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => {
|
ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => {
|
||||||
let index = read_u8(&code.opcodes, pc) as usize;
|
let index = read_u8(&code.opcodes, pc) as usize;
|
||||||
self.store(&mut local_params, index)?;
|
self.store(stackframes, &mut local_params, index)?;
|
||||||
}
|
}
|
||||||
ISTORE_0 | LSTORE_0 | DSTORE_0 | ASTORE_0 | FSTORE_0 => {
|
ISTORE_0 | LSTORE_0 | DSTORE_0 | ASTORE_0 | FSTORE_0 => {
|
||||||
self.store(&mut local_params, 0)?;
|
self.store(stackframes, &mut local_params, 0)?;
|
||||||
}
|
}
|
||||||
ISTORE_1 | LSTORE_1 | DSTORE_1 | ASTORE_1 | FSTORE_1 => {
|
ISTORE_1 | LSTORE_1 | DSTORE_1 | ASTORE_1 | FSTORE_1 => {
|
||||||
self.store(&mut local_params, 1)?;
|
self.store(stackframes, &mut local_params, 1)?;
|
||||||
}
|
}
|
||||||
ISTORE_2 | LSTORE_2 | DSTORE_2 | ASTORE_2 | FSTORE_2 => {
|
ISTORE_2 | LSTORE_2 | DSTORE_2 | ASTORE_2 | FSTORE_2 => {
|
||||||
self.store(&mut local_params, 2)?;
|
self.store(stackframes, &mut local_params, 2)?;
|
||||||
}
|
}
|
||||||
ISTORE_3 | LSTORE_3 | DSTORE_3 | ASTORE_3 | FSTORE_3 => {
|
ISTORE_3 | LSTORE_3 | DSTORE_3 | ASTORE_3 | FSTORE_3 => {
|
||||||
self.store(&mut local_params, 3)?;
|
self.store(stackframes, &mut local_params, 3)?;
|
||||||
}
|
}
|
||||||
BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE
|
BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE
|
||||||
| AASTORE => unsafe {
|
| AASTORE => {
|
||||||
let value = self.current_frame().pop()?;
|
let value = Self::current_frame(stackframes).pop()?;
|
||||||
let index = self.current_frame().pop()?;
|
let index = Self::current_frame(stackframes).pop()?;
|
||||||
let arrayref = &mut self.current_frame().pop()?;
|
let arrayref = Self::current_frame(stackframes).pop()?;
|
||||||
array_store(value, index, arrayref)?
|
array_store(value, index, arrayref)?
|
||||||
},
|
}
|
||||||
POP => {
|
POP => {
|
||||||
self.current_frame().pop()?;
|
Self::current_frame(stackframes).pop()?;
|
||||||
}
|
}
|
||||||
DUP => {
|
DUP => {
|
||||||
let value = self.current_frame().pop()?;
|
let value = Self::current_frame(stackframes).pop()?;
|
||||||
self.current_frame().push(value.clone());
|
Self::current_frame(stackframes).push(value.clone());
|
||||||
self.current_frame().push(value);
|
Self::current_frame(stackframes).push(value);
|
||||||
}
|
}
|
||||||
IDIV => {
|
IDIV => {
|
||||||
let value1 = self.current_frame().pop()?;
|
let value1 = Self::current_frame(stackframes).pop()?;
|
||||||
let value2 = self.current_frame().pop()?;
|
let value2 = Self::current_frame(stackframes).pop()?;
|
||||||
self.current_frame().push(I32(value1.into_i32() / value2.into_i32()));
|
Self::current_frame(stackframes).push(I32(value1.into_i32() / value2.into_i32()));
|
||||||
}
|
}
|
||||||
|
|
||||||
IFEQ | IFNE | IFLT | IFGE | IFGT | IFLE => {
|
IFEQ | IFNE | IFLT | IFGE | IFGT | IFLE => {
|
||||||
let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode
|
let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode
|
||||||
let value = self.current_frame().pop()?;
|
let value = Self::current_frame(stackframes).pop()?;
|
||||||
unsafe {
|
|
||||||
Self::if_cmp(pc, opcode, jmp_to, &value, &I32(0));
|
Self::if_cmp(pc, opcode, jmp_to, &value, &I32(0));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
IF_ICMPEQ | IF_ICMPNE | IF_ICMPGT | IF_ICMPGE | IF_ICMPLT | IF_ICMPLE => {
|
IF_ICMPEQ | IF_ICMPNE | IF_ICMPGT | IF_ICMPGE | IF_ICMPLT | IF_ICMPLE => {
|
||||||
let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode
|
let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode
|
||||||
let value1 = self.current_frame().pop()?;
|
let value1 = Self::current_frame(stackframes).pop()?;
|
||||||
let value2 = self.current_frame().pop()?;
|
let value2 = Self::current_frame(stackframes).pop()?;
|
||||||
unsafe {
|
|
||||||
Self::if_cmp(pc, opcode, jmp_to, &value1, &value2);
|
Self::if_cmp(pc, opcode, jmp_to, &value1, &value2);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
GOTO => {
|
GOTO => {
|
||||||
let jmp_to = read_u16(&code.opcodes, pc) - 3;
|
let jmp_to = read_u16(&code.opcodes, pc) - 3;
|
||||||
*pc += jmp_to as usize;
|
*pc += jmp_to as usize;
|
||||||
}
|
}
|
||||||
IRETURN | FRETURN | DRETURN | ARETURN => {
|
IRETURN | FRETURN | DRETURN | ARETURN => {
|
||||||
let result = self.current_frame().pop();
|
let result = Self::current_frame(stackframes).pop();
|
||||||
self.stackframes.pop();
|
stackframes.pop();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
RETURN_VOID => {
|
RETURN_VOID => {
|
||||||
self.stackframes.pop();
|
stackframes.pop();
|
||||||
return Ok(Void);
|
return Ok(Void);
|
||||||
}
|
}
|
||||||
GETSTATIC => {
|
GETSTATIC => {
|
||||||
let field_index = read_u16(&code.opcodes, pc);
|
let field_index = read_u16(&code.opcodes, pc);
|
||||||
let field_value = get_static(self, this_class.clone(), field_index)?;
|
let field_value = get_static(this_class, field_index)?;
|
||||||
self.current_frame().push(field_value);
|
|
||||||
|
Self::current_frame(stackframes).push(field_value);
|
||||||
}
|
}
|
||||||
PUTSTATIC => {
|
PUTSTATIC => {
|
||||||
let mut borrow = this_class.borrow_mut();
|
let classdef = classmanager::get_classdef(&this_class.id);
|
||||||
let cp_index = read_u16(&code.opcodes, pc);
|
let cp_index = read_u16(&code.opcodes, pc);
|
||||||
let (class_index, field_name_and_type_index) =
|
let (class_index, field_name_and_type_index) =
|
||||||
borrow.cp_field_ref(&cp_index); // all these unwraps are safe as long as the class is valid
|
classdef.cp_field_ref(&cp_index); // all these unwraps are safe as long as the class is valid
|
||||||
let (name_index, _) =
|
let (name_index, _) =
|
||||||
borrow.cp_name_and_type(field_name_and_type_index);
|
classdef.cp_name_and_type(field_name_and_type_index);
|
||||||
let name = borrow.cp_utf8(name_index);
|
let name = classdef.cp_utf8(name_index);
|
||||||
let class_name_index = borrow.cp_class_ref(class_index);
|
let class_name_index = classdef.cp_class_ref(class_index);
|
||||||
let that_class_name = borrow.cp_utf8(class_name_index);
|
let that_class_name = classdef.cp_utf8(class_name_index);
|
||||||
|
|
||||||
let val_index = if &borrow.name == that_class_name {
|
let val_index = if &this_class.name == that_class_name {
|
||||||
// may have to apply this in GETSTATIC too
|
// may have to apply this in GETSTATIC too
|
||||||
borrow
|
this_class
|
||||||
.static_field_mapping
|
.static_field_mapping
|
||||||
.get(that_class_name)
|
.get(that_class_name)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -443,65 +431,63 @@ impl Vm {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.index
|
.index
|
||||||
} else {
|
} else {
|
||||||
let that =
|
classmanager::load_class_by_name(that_class_name);
|
||||||
get_class(self, that_class_name.as_str())?;
|
let that = classmanager::get_class_by_name(that_class_name).unwrap();
|
||||||
let that_borrow = that.borrow();
|
that.static_field_mapping
|
||||||
that_borrow
|
|
||||||
.static_field_mapping
|
|
||||||
.get(that_class_name)
|
.get(that_class_name)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get(name)
|
.get(name)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.index
|
.index
|
||||||
};
|
};
|
||||||
let value = self.current_frame().pop()?;
|
let value = Self::current_frame(stackframes).pop()?;
|
||||||
borrow.static_data[val_index] = value;
|
classmanager::set_static(&this_class.id, val_index, value);
|
||||||
}
|
}
|
||||||
GETFIELD => unsafe {
|
GETFIELD => {
|
||||||
let borrow = this_class.borrow();
|
let classdef = classmanager::get_classdef(&this_class.id);
|
||||||
let cp_index = read_u16(&code.opcodes, pc);
|
let cp_index = read_u16(&code.opcodes, pc);
|
||||||
let (class_index, field_name_and_type_index) =
|
let (class_index, field_name_and_type_index) =
|
||||||
borrow.cp_field_ref(&cp_index);
|
classdef.cp_field_ref(&cp_index);
|
||||||
let (field_name_index, _) =
|
let (field_name_index, _) =
|
||||||
borrow.cp_name_and_type(field_name_and_type_index);
|
classdef.cp_name_and_type(field_name_and_type_index);
|
||||||
let class_name_index = borrow.cp_class_ref(class_index);
|
let class_name_index = classdef.cp_class_ref(class_index);
|
||||||
let class_name = borrow.cp_utf8(class_name_index);
|
let declared_type = classdef.cp_utf8(class_name_index);
|
||||||
let field_name = borrow.cp_utf8(field_name_index);
|
let field_name = classdef.cp_utf8(field_name_index);
|
||||||
|
|
||||||
let objectref = self.current_frame().pop()?;
|
let objectref = Self::current_frame(stackframes).pop()?;
|
||||||
if let Ref(instance) = objectref {
|
if let Ref(instance) = objectref {
|
||||||
if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
|
if let ObjectRef::Object(mut object) = instance {
|
||||||
let value = object.get(class_name, field_name);
|
let value = object.get(this_class, declared_type, field_name);
|
||||||
self.current_frame().push(value.clone());
|
Self::current_frame(stackframes).push(value.clone());
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!("objectref {:?}", objectref)
|
unreachable!("objectref {:?}", objectref)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
PUTFIELD => unsafe {
|
PUTFIELD => {
|
||||||
let borrow = this_class.borrow();
|
let classdef = classmanager::get_classdef(&this_class.id);
|
||||||
let cp_index = read_u16(&code.opcodes, pc);
|
let cp_index = read_u16(&code.opcodes, pc);
|
||||||
let (class_index, field_name_and_type_index) =
|
let (class_index, field_name_and_type_index) =
|
||||||
borrow.cp_field_ref(&cp_index);
|
classdef.cp_field_ref(&cp_index);
|
||||||
let (field_name_index, _) =
|
let (field_name_index, _) =
|
||||||
borrow.cp_name_and_type(field_name_and_type_index);
|
classdef.cp_name_and_type(field_name_and_type_index);
|
||||||
let class_name_index = borrow.cp_class_ref(class_index);
|
let class_name_index = classdef.cp_class_ref(class_index);
|
||||||
let class_name = borrow.cp_utf8(class_name_index);
|
let declared_type = classdef.cp_utf8(class_name_index);
|
||||||
let field_name = borrow.cp_utf8(field_name_index);
|
let field_name = classdef.cp_utf8(field_name_index);
|
||||||
|
|
||||||
let value = self.current_frame().pop()?;
|
let value = Self::current_frame(stackframes).pop()?;
|
||||||
let objectref = self.current_frame().pop()?;
|
let objectref = Self::current_frame(stackframes).pop()?;
|
||||||
if let Ref(instance) = objectref {
|
if let Ref(instance) = objectref {
|
||||||
if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
|
if let ObjectRef::Object(mut object) = instance {
|
||||||
object.set(class_name, field_name, value);
|
object.set(this_class, declared_type, field_name, value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
INVOKESPECIAL => unsafe {
|
INVOKESPECIAL => {
|
||||||
// TODO differentiate these opcodes
|
// TODO differentiate these opcodes
|
||||||
let cp_index = read_u16(&code.opcodes, pc);
|
let cp_index = read_u16(&code.opcodes, pc);
|
||||||
if let Some(invocation) =
|
if let Some(invocation) =
|
||||||
|
|
@ -509,17 +495,17 @@ impl Vm {
|
||||||
{
|
{
|
||||||
let mut args = Vec::with_capacity(invocation.method.num_args);
|
let mut args = Vec::with_capacity(invocation.method.num_args);
|
||||||
for _ in 0..invocation.method.num_args {
|
for _ in 0..invocation.method.num_args {
|
||||||
args.insert(0, self.current_frame().pop()?.clone());
|
args.insert(0, Self::current_frame(stackframes).pop()?.clone());
|
||||||
}
|
}
|
||||||
args.insert(0, self.current_frame().pop()?);
|
args.insert(0, Self::current_frame(stackframes).pop()?);
|
||||||
let return_value = self.execute_special(
|
let return_value = self.execute_special(stackframes,
|
||||||
&invocation.class_name,
|
&invocation.class_name,
|
||||||
&invocation.method.name,
|
&invocation.method.name,
|
||||||
args,
|
args,
|
||||||
)?;
|
)?;
|
||||||
if let Ref(r) = &return_value {
|
if let Ref(objectref) = &return_value {
|
||||||
if let ObjectRef::Object(p) = &*r.get() {
|
if let ObjectRef::Object(object) = objectref {
|
||||||
info!("return {:?}", p);
|
info!("return {:?}", object);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!("return {:?}", return_value);
|
info!("return {:?}", return_value);
|
||||||
|
|
@ -527,15 +513,15 @@ impl Vm {
|
||||||
match return_value {
|
match return_value {
|
||||||
Void => {}
|
Void => {}
|
||||||
_ => {
|
_ => {
|
||||||
self.current_frame().push(return_value.clone());
|
Self::current_frame(stackframes).push(return_value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// println!("stack {} at {}", self.current_frame().len(), self.current_frame().at)
|
// println!("stack {} at {}", Self::current_frame(stack).len(), Self::current_frame(stack).at)
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
INVOKEVIRTUAL => unsafe {
|
INVOKEVIRTUAL => {
|
||||||
// TODO differentiate these opcodes
|
// TODO differentiate these opcodes
|
||||||
let cp_index = read_u16(&code.opcodes, pc);
|
let cp_index = read_u16(&code.opcodes, pc);
|
||||||
if let Some(invocation) =
|
if let Some(invocation) =
|
||||||
|
|
@ -543,17 +529,18 @@ impl Vm {
|
||||||
{
|
{
|
||||||
let mut args = Vec::with_capacity(invocation.method.num_args);
|
let mut args = Vec::with_capacity(invocation.method.num_args);
|
||||||
for _ in 0..invocation.method.num_args {
|
for _ in 0..invocation.method.num_args {
|
||||||
args.insert(0, self.current_frame().pop()?.clone());
|
args.insert(0, Self::current_frame(stackframes).pop()?.clone());
|
||||||
}
|
}
|
||||||
args.insert(0, self.current_frame().pop()?);
|
args.insert(0, Self::current_frame(stackframes).pop()?);
|
||||||
let return_value = self.execute_virtual(
|
let return_value = self.execute_virtual(
|
||||||
|
stackframes,
|
||||||
&invocation.class_name,
|
&invocation.class_name,
|
||||||
&invocation.method.name,
|
&invocation.method.name,
|
||||||
args,
|
args,
|
||||||
)?;
|
)?;
|
||||||
if let Ref(r) = &return_value {
|
if let Ref(objectref) = &return_value {
|
||||||
if let ObjectRef::Object(p) = &*r.get() {
|
if let ObjectRef::Object(object) = objectref {
|
||||||
info!("return {:?}", p);
|
info!("return {:?}", object);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!("return {:?}", return_value);
|
info!("return {:?}", return_value);
|
||||||
|
|
@ -561,31 +548,30 @@ impl Vm {
|
||||||
match return_value {
|
match return_value {
|
||||||
Void => {}
|
Void => {}
|
||||||
_ => {
|
_ => {
|
||||||
self.current_frame().push(return_value.clone());
|
Self::current_frame(stackframes).push(return_value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// println!("stack {} at {}", self.current_frame().len(), self.current_frame().at)
|
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
INVOKESTATIC => unsafe {
|
INVOKESTATIC => {
|
||||||
let cp_index = read_u16(&code.opcodes, pc);
|
let cp_index = read_u16(&code.opcodes, pc);
|
||||||
if let Some(invocation) =
|
if let Some(invocation) =
|
||||||
get_signature_for_invoke(&method.constant_pool, cp_index)
|
get_signature_for_invoke(&method.constant_pool, cp_index)
|
||||||
{
|
{
|
||||||
let mut args = Vec::with_capacity(invocation.method.num_args);
|
let mut args = Vec::with_capacity(invocation.method.num_args);
|
||||||
for _ in 0..invocation.method.num_args {
|
for _ in 0..invocation.method.num_args {
|
||||||
args.insert(0, self.current_frame().pop()?.clone());
|
args.insert(0, Self::current_frame(stackframes).pop()?.clone());
|
||||||
}
|
}
|
||||||
let return_value = self.execute_static(
|
let return_value = self.execute_static(stackframes,
|
||||||
&invocation.class_name,
|
&invocation.class_name,
|
||||||
&invocation.method.name,
|
&invocation.method.name,
|
||||||
args,
|
args,
|
||||||
)?;
|
)?;
|
||||||
if let Ref(r) = &return_value {
|
if let Ref(objectref) = &return_value {
|
||||||
if let ObjectRef::Object(p) = &*r.get() {
|
if let ObjectRef::Object(object) = objectref {
|
||||||
info!("return {:?}", p);
|
info!("return {:?}", object);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!("return {:?}", return_value);
|
info!("return {:?}", return_value);
|
||||||
|
|
@ -593,59 +579,55 @@ impl Vm {
|
||||||
match return_value {
|
match return_value {
|
||||||
Void => {}
|
Void => {}
|
||||||
_ => {
|
_ => {
|
||||||
self.current_frame().push(return_value.clone());
|
Self::current_frame(stackframes).push(return_value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
},
|
|
||||||
NEW => {
|
|
||||||
let class_index = &read_u16(&code.opcodes, pc);
|
|
||||||
let borrow = this_class.borrow();
|
|
||||||
let class_name_index = borrow.cp_class_ref(class_index);
|
|
||||||
let class_name = borrow.cp_utf8(class_name_index);
|
|
||||||
let class_to_instantiate = get_class(self, class_name)?;
|
|
||||||
|
|
||||||
let object = unsafe_ref(ObjectRef::Object(Box::new(Vm::new_instance(
|
|
||||||
class_to_instantiate,
|
|
||||||
))));
|
|
||||||
self.current_frame().push(Value::Ref(Arc::clone(&object)));
|
|
||||||
self.heap.new_object(object);
|
|
||||||
}
|
}
|
||||||
ANEWARRAY => unsafe {
|
NEW => {
|
||||||
|
let classdef = classmanager::get_classdef(&this_class.id);
|
||||||
let class_index = &read_u16(&code.opcodes, pc);
|
let class_index = &read_u16(&code.opcodes, pc);
|
||||||
let borrow = this_class.borrow();
|
let class_name_index = classdef.cp_class_ref(class_index);
|
||||||
let class_name_index = borrow.cp_class_ref(class_index);
|
let class_name = classdef.cp_utf8(class_name_index);
|
||||||
let class_name = borrow.cp_utf8(class_name_index);
|
classmanager::load_class_by_name(class_name);
|
||||||
let arraytype = get_class(self, class_name)?;
|
let class_to_instantiate = classmanager::get_class_by_name(class_name).unwrap();
|
||||||
let count = self.current_frame().pop()?;
|
|
||||||
if let I32(count) = count {
|
|
||||||
// why does pop()?.get() give weird results?
|
|
||||||
let array = ObjectRef::new_object_array(arraytype, count as usize);
|
|
||||||
let array = unsafe_ref(array);
|
|
||||||
|
|
||||||
self.current_frame().push(Value::Ref(Arc::clone(&array)));
|
let object = ObjectRef::Object(Vm::new_instance(
|
||||||
self.heap.new_object(array);
|
class_to_instantiate,
|
||||||
|
));
|
||||||
|
Self::current_frame(stackframes).push(Ref(object));
|
||||||
|
// self.heap.new_object(object);
|
||||||
|
}
|
||||||
|
ANEWARRAY => {
|
||||||
|
let classdef = classmanager::get_classdef(&this_class.id);
|
||||||
|
let class_index = &read_u16(&code.opcodes, pc);
|
||||||
|
let class_name_index = classdef.cp_class_ref(class_index);
|
||||||
|
let class_name = classdef.cp_utf8(class_name_index);
|
||||||
|
classmanager::load_class_by_name(class_name);
|
||||||
|
let arraytype = classmanager::get_class_by_name(class_name).unwrap();
|
||||||
|
let count = Self::current_frame(stackframes).pop()?;
|
||||||
|
if let I32(count) = count {
|
||||||
|
let array = ObjectRef::new_object_array(arraytype, count as usize);
|
||||||
|
|
||||||
|
Self::current_frame(stackframes).push(Value::Ref(array));
|
||||||
} else {
|
} else {
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
ARRAYLENGTH => {
|
|
||||||
let val = self.current_frame().pop()?;
|
|
||||||
unsafe {
|
|
||||||
if let Ref(val) = val {
|
|
||||||
let o = &*val.get();
|
|
||||||
self.current_frame().push(I32(o.get_array_length() as i32));
|
|
||||||
}
|
}
|
||||||
|
ARRAYLENGTH => {
|
||||||
|
let val = Self::current_frame(stackframes).pop()?;
|
||||||
|
if let Ref(val) = val {
|
||||||
|
Self::current_frame(stackframes).push(I32(val.get_array_length() as i32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MONITORENTER => {
|
MONITORENTER => {
|
||||||
self.current_frame().pop()?;
|
Self::current_frame(stackframes).pop()?;
|
||||||
} //TODO implement
|
} //TODO implement
|
||||||
IFNULL | IFNONNULL => unsafe {
|
IFNULL | IFNONNULL => {
|
||||||
let jmp_to = read_u16(&code.opcodes, pc) - 3;
|
let jmp_to = read_u16(&code.opcodes, pc) - 3;
|
||||||
let value = self.current_frame().pop()?;
|
let value = Self::current_frame(stackframes).pop()?;
|
||||||
let its_null = if let Null = value { true } else { false };
|
let its_null = if let Null = value { true } else { false };
|
||||||
|
|
||||||
if its_null && opcode == IFNULL {
|
if its_null && opcode == IFNULL {
|
||||||
|
|
@ -666,7 +648,7 @@ impl Vm {
|
||||||
},
|
},
|
||||||
//TODO implement all opcodes
|
//TODO implement all opcodes
|
||||||
_ => {
|
_ => {
|
||||||
panic!("opcode {} not implemented {:?}", opcode, self.stackframes)
|
panic!("opcode {} not implemented {:?}", opcode, stackframes)
|
||||||
//TODO implement proper --stacktraces-- error handling
|
//TODO implement proper --stacktraces-- error handling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -697,16 +679,19 @@ impl Vm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// store in local param
|
||||||
fn store(
|
fn store(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
stack: &mut Vec<StackFrame>,
|
||||||
local_params: &mut Vec<Option<Value>>,
|
local_params: &mut Vec<Option<Value>>,
|
||||||
index: usize,
|
index: usize,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let value = self.current_frame().pop()?;
|
let value = Self::current_frame(stack).pop()?;
|
||||||
while local_params.len() < index + 1 {
|
while local_params.len() < index + 1 {
|
||||||
local_params.push(None);
|
local_params.push(None);
|
||||||
}
|
}
|
||||||
local_params[index] = Some(value.clone());
|
local_params[index] = Some(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
mod test {
|
mod test {
|
||||||
use java_rs::class::Value;
|
use java_rs::class::{ObjectRef, Value};
|
||||||
use java_rs::heap::ObjectRef;
|
use java_rs::classmanager::set_classpath;
|
||||||
use java_rs::vm1::Vm;
|
use java_rs::vm::Vm;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn if_cmp() {
|
fn if_cmp() {
|
||||||
let mut vm = Vm::new("tests");
|
let mut stackframes = Vec::new();
|
||||||
let ret = vm.execute_virtual("testclasses.IfCmp", "i_is_1()Z", vec![]).unwrap();
|
let mut vm = Vm::new(&mut stackframes);
|
||||||
|
set_classpath("/Users/Shautvast/dev/java/tests");
|
||||||
|
let ret = vm.execute_virtual(&mut stackframes,"testclasses.IfCmp", "i_is_1()Z", vec![]).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Value::I32(b) = *ret.get() {
|
if let Value::I32(b) = ret {
|
||||||
// internally a boolean is an int
|
// internally a boolean is an int
|
||||||
assert_eq!(0, b);
|
assert_eq!(0, b);
|
||||||
} else {
|
} else {
|
||||||
println!("{:?}", *ret.get());
|
println!("{:?}", ret);
|
||||||
assert!(false)
|
assert!(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,18 +22,20 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn consts() {
|
fn consts() {
|
||||||
let mut vm = Vm::new("tests");
|
let mut stackframes = Vec::new();
|
||||||
|
let mut vm = Vm::new(&mut stackframes);
|
||||||
|
set_classpath("/Users/Shautvast/dev/java/tests");
|
||||||
let ret = vm
|
let ret = vm
|
||||||
.execute_static("testclasses.Const", "hello()Ljava/lang/String;", vec![])
|
.execute_static(&mut stackframes, "testclasses.Const", "hello()Ljava/lang/String;", vec![])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Value::Ref(s) = &*ret.get() {
|
if let Value::Ref(s) = ret {
|
||||||
// internally a boolean is an int
|
// internally a boolean is an int
|
||||||
if let ObjectRef::Object(a) = &*s.get() {
|
if let ObjectRef::Object(a) = s {
|
||||||
println!("{:?}", a);
|
println!("{:?}", a);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("{:?}", *ret.get());
|
println!("{:?}", ret);
|
||||||
assert!(false)
|
assert!(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue