Real classes for arrays, initialization order
This commit is contained in:
parent
70a11283db
commit
5cf17d5ca3
4 changed files with 160 additions and 35 deletions
|
@ -271,7 +271,7 @@ impl ClassStore {
|
||||||
pub fn class_index_for_type(&self, r#type: AbstractTypeDescription) -> Option<usize> {
|
pub fn class_index_for_type(&self, r#type: AbstractTypeDescription) -> Option<usize> {
|
||||||
match (r#type.array_level, &r#type.kind) {
|
match (r#type.array_level, &r#type.kind) {
|
||||||
(0, AbstractTypeKind::Classname(ref name)) => Some(self.class_idx_from_name(name).unwrap()),
|
(0, AbstractTypeKind::Classname(ref name)) => Some(self.class_idx_from_name(name).unwrap()),
|
||||||
_ => None
|
(_, _) => Some(self.class_idx_from_name(&(&r#type).into())?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -273,6 +273,11 @@ impl ObjectArea {
|
||||||
self.get_class_ref_native_class_name(class_ref, class_store)
|
self.get_class_ref_native_class_name(class_ref, class_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_reference_class_index(&self, reference: ObjectReference, class_store: &ClassStore) -> usize {
|
||||||
|
let class_desc = self.get_reference_native_class_name(reference, class_store);
|
||||||
|
class_store.class_index_for_type(AbstractTypeDescription::parse_full(class_desc).unwrap()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_object_class_index(&self, reference: ObjectReference) -> usize {
|
pub fn get_object_class_index(&self, reference: ObjectReference) -> usize {
|
||||||
match self.get_entry(reference) {
|
match self.get_entry(reference) {
|
||||||
CompartmentEntry::Object(o) => o.class_index,
|
CompartmentEntry::Object(o) => o.class_index,
|
||||||
|
@ -518,6 +523,13 @@ impl ObjectArea {
|
||||||
|
|
||||||
(array_ref, array_size)
|
(array_ref, array_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clone_(&mut self, this: ObjectReference) -> ObjectReference {
|
||||||
|
let clone = self.get_entry(this).clone();
|
||||||
|
let clone_ref = self.store_entry(clone);
|
||||||
|
|
||||||
|
clone_ref
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ObjectCompartment {
|
pub struct ObjectCompartment {
|
||||||
|
@ -585,7 +597,7 @@ impl DebugTrait for ObjectCompartment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum CompartmentEntry {
|
pub enum CompartmentEntry {
|
||||||
Object(HeapObject),
|
Object(HeapObject),
|
||||||
ReferenceArray(ReferenceArray),
|
ReferenceArray(ReferenceArray),
|
||||||
|
@ -596,31 +608,31 @@ pub enum CompartmentEntry {
|
||||||
EmptyTail(), // last empty value
|
EmptyTail(), // last empty value
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CharArray {
|
pub struct CharArray {
|
||||||
class_ref: ObjectReference,
|
class_ref: ObjectReference,
|
||||||
content: Box<[u16]>,
|
content: Box<[u16]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IntArray {
|
pub struct IntArray {
|
||||||
class_ref: ObjectReference,
|
class_ref: ObjectReference,
|
||||||
content: Box<[i32]>,
|
content: Box<[i32]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ByteArray {
|
pub struct ByteArray {
|
||||||
class_ref: ObjectReference,
|
class_ref: ObjectReference,
|
||||||
content: Box<[i8]>,
|
content: Box<[i8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ReferenceArray {
|
pub struct ReferenceArray {
|
||||||
class_ref: ObjectReference,
|
class_ref: ObjectReference,
|
||||||
content: Box<[ObjectReference]>,
|
content: Box<[ObjectReference]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct HeapObject {
|
pub struct HeapObject {
|
||||||
class_index: usize,
|
class_index: usize,
|
||||||
fields: Box<[ObjectField]>,
|
fields: Box<[ObjectField]>,
|
||||||
|
|
85
src/jvm.rs
85
src/jvm.rs
|
@ -12,7 +12,7 @@ use crate::classstore;
|
||||||
use crate::classstore::ClassStore;
|
use crate::classstore::ClassStore;
|
||||||
use crate::constantpool::{ ConstantClassInfo, ConstantInterfaceMethodRefInfo, ConstantMethodRefInfo, ConstantNameAndTypeInfo, ConstantPoolInfo, ConstantUtf8Info};
|
use crate::constantpool::{ ConstantClassInfo, ConstantInterfaceMethodRefInfo, ConstantMethodRefInfo, ConstantNameAndTypeInfo, ConstantPoolInfo, ConstantUtf8Info};
|
||||||
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference, CompartmentEntry };
|
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference, CompartmentEntry };
|
||||||
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator };
|
use crate::iterators::{ ClassFieldIterator, ClassMethodIterator, CompatibleTypesIterator };
|
||||||
use crate::native_methods;
|
use crate::native_methods;
|
||||||
use crate::native_methods::EntryPoint;
|
use crate::native_methods::EntryPoint;
|
||||||
use crate::native_registry::NativeRegistry;
|
use crate::native_registry::NativeRegistry;
|
||||||
|
@ -188,6 +188,31 @@ impl JVM {
|
||||||
self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap(),
|
self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap(),
|
||||||
&self.class_store,
|
&self.class_store,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
|
let array_class_file = JavaClassFile {
|
||||||
|
minor_version: 0,
|
||||||
|
major_version: 63,
|
||||||
|
constant_pool: Box::new(
|
||||||
|
[
|
||||||
|
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 2 }),
|
||||||
|
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: (&array_type_description).into() }),
|
||||||
|
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 4 }),
|
||||||
|
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/Object".to_string() }),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
access_flags: ClassAccessFlagMask {
|
||||||
|
mask: ClassAccessFlag::Public.discriminant() | ClassAccessFlag::Synthetic.discriminant()
|
||||||
|
},
|
||||||
|
this_class: 1,
|
||||||
|
super_class: 3,
|
||||||
|
interfaces: Box::new([]),
|
||||||
|
fields: Box::new([]),
|
||||||
|
methods: Box::new([]),
|
||||||
|
attributes: Box::new([]),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.class_store.add_class(array_class_file, true).unwrap();
|
||||||
|
|
||||||
self.class_store.put_array_class_ref(
|
self.class_store.put_array_class_ref(
|
||||||
array_type_description,
|
array_type_description,
|
||||||
array_class_object,
|
array_class_object,
|
||||||
|
@ -557,30 +582,18 @@ impl JVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_class_hierarchy(&mut self, name: &String) -> Result<(), Error> {
|
fn init_class_hierarchy(&mut self, name: &String) -> Result<(), Error> {
|
||||||
let mut class_stack = vec![name.to_string()];
|
// TODO: Work around the clones
|
||||||
|
|
||||||
while class_stack.len() != 0 {
|
let mut current_name = name.clone();
|
||||||
let current_name = class_stack.pop().unwrap();
|
|
||||||
let was_super_init = {
|
|
||||||
let (file, _) = self.class_store.get_class(¤t_name)?;
|
|
||||||
if ! file.has_super_class() {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
let super_name = file.get_super_class_name()?;
|
|
||||||
self.class_store.was_init(super_name).unwrap()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if was_super_init {
|
while ! self.class_store.was_init(¤t_name).unwrap() {
|
||||||
let class_idx = self.class_store.class_idx_from_name(¤t_name).unwrap();
|
let class_index = self.class_store.class_idx_from_name(¤t_name).unwrap();
|
||||||
self.init_class(class_idx)?;
|
self.init_class(class_index)?;
|
||||||
} else {
|
|
||||||
let super_name = {
|
let class_file = self.class_store.class_file_from_idx(class_index).unwrap();
|
||||||
let (file, _) = self.class_store.get_class(¤t_name)?;
|
|
||||||
file.get_super_class_name()?
|
if class_file.has_super_class() {
|
||||||
};
|
current_name = class_file.get_super_class_name().unwrap().clone();
|
||||||
class_stack.push(current_name);
|
|
||||||
class_stack.push(super_name.to_string());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1310,11 +1323,31 @@ impl JVM {
|
||||||
return Ok(JVMCallbackOperation::InitClass(class_name.to_string()));
|
return Ok(JVMCallbackOperation::InitClass(class_name.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let class_index = self.class_store.class_idx_from_name(class_name).unwrap();
|
||||||
|
let owning_class = CompatibleTypesIterator::new(class_index, &self.class_store)
|
||||||
|
.filter(|name| {
|
||||||
|
let index = self.class_store.class_idx_from_name(name).unwrap();
|
||||||
|
let class_file = self.class_store.class_file_from_idx(index).unwrap();
|
||||||
|
class_file.fields.iter()
|
||||||
|
.filter(|finfo| finfo.access_flags & FieldAccessFlag::Static)
|
||||||
|
.filter(|finfo| finfo.name == *field_name)
|
||||||
|
.next()
|
||||||
|
.is_some()
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
.unwrap_or_else(|| class_name);
|
||||||
|
|
||||||
|
if ! self.class_store.was_init(owning_class).unwrap() {
|
||||||
|
// rewind the bytecode offset, I'll need to execute this instruction again
|
||||||
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
return Ok(JVMCallbackOperation::InitClass(owning_class.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Throw error
|
// TODO: Throw error
|
||||||
let parsed_field_descriptor = AbstractTypeDescription::parse_full(field_descriptor).unwrap();
|
let parsed_field_descriptor = AbstractTypeDescription::parse_full(field_descriptor).unwrap();
|
||||||
|
|
||||||
// TODO: Throw error
|
// TODO: Throw error
|
||||||
let fetched_value = self.heap_area.static_area.get(class_name, field_name, parsed_field_descriptor).unwrap();
|
let fetched_value = self.heap_area.static_area.get(owning_class, field_name, parsed_field_descriptor).unwrap();
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(fetched_value))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(fetched_value))?;
|
||||||
}
|
}
|
||||||
|
@ -1569,8 +1602,8 @@ impl JVM {
|
||||||
let this_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
let this_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
arguments.push_front(StackValue::Reference(this_object));
|
arguments.push_front(StackValue::Reference(this_object));
|
||||||
|
|
||||||
// TODO: Are there any methods callable on arrays?
|
// Are there any methods callable on arrays?, turns out there are
|
||||||
let this_object_class_index = self.heap_area.object_area.get_object_class_index(this_object);
|
let this_object_class_index = self.heap_area.object_area.get_reference_class_index(this_object, &self.class_store);
|
||||||
let this_object_class_name = self.class_store.class_name_from_index(this_object_class_index).unwrap().to_string();
|
let this_object_class_name = self.class_store.class_name_from_index(this_object_class_index).unwrap().to_string();
|
||||||
let this_object_descriptor = AbstractTypeDescription {
|
let this_object_descriptor = AbstractTypeDescription {
|
||||||
array_level: 0,
|
array_level: 0,
|
||||||
|
|
|
@ -364,6 +364,17 @@ impl JavaLangDouble {
|
||||||
struct JavaLangObject {}
|
struct JavaLangObject {}
|
||||||
|
|
||||||
impl JavaLangObject {
|
impl JavaLangObject {
|
||||||
|
fn clone(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
|
let frame = {
|
||||||
|
let frame_index = jvm.stack_frames.len() - 1;
|
||||||
|
&mut jvm.stack_frames[frame_index]
|
||||||
|
};
|
||||||
|
let this = frame.load_local_reference(0).unwrap();
|
||||||
|
|
||||||
|
let clone = jvm.heap_area.object_area.clone_(this);
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(clone.into()))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_class(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
fn get_class(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
let frame = {
|
let frame = {
|
||||||
|
@ -455,6 +466,23 @@ impl JavaLangStringUTF16 {
|
||||||
struct JavaLangSystem {}
|
struct JavaLangSystem {}
|
||||||
|
|
||||||
impl JavaLangSystem {
|
impl JavaLangSystem {
|
||||||
|
fn set_in_0(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
|
let frame = {
|
||||||
|
let frame_index = jvm.stack_frames.len() - 1;
|
||||||
|
&mut jvm.stack_frames[frame_index]
|
||||||
|
};
|
||||||
|
let input_stream = frame.load_local_reference(0).unwrap();
|
||||||
|
|
||||||
|
// TODO: Bypass final
|
||||||
|
jvm.heap_area.static_area.set(
|
||||||
|
&String::from("java/lang/System"),
|
||||||
|
&String::from("in"),
|
||||||
|
FieldValue::Reference(input_stream)
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::PopFrame())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn arraycopy(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
pub fn arraycopy(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
let frame = {
|
let frame = {
|
||||||
let frame_index = jvm.stack_frames.len() - 1;
|
let frame_index = jvm.stack_frames.len() - 1;
|
||||||
|
@ -1401,7 +1429,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
argument_types: Box::new([]),
|
argument_types: Box::new([]),
|
||||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Object"))},
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Object"))},
|
||||||
},
|
},
|
||||||
todo_call
|
JavaLangObject::clone
|
||||||
),
|
),
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -1588,7 +1616,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
]),
|
]),
|
||||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void()},
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void()},
|
||||||
},
|
},
|
||||||
todo_call
|
JavaLangSystem::set_in_0
|
||||||
),
|
),
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -3766,6 +3794,58 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
},
|
},
|
||||||
todo_call
|
todo_call
|
||||||
),
|
),
|
||||||
|
|
||||||
|
(
|
||||||
|
"java/io/FileOutputStream",
|
||||||
|
"open0",
|
||||||
|
MethodDescriptor {
|
||||||
|
argument_types: Box::new([
|
||||||
|
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())},
|
||||||
|
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
|
||||||
|
]),
|
||||||
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
||||||
|
},
|
||||||
|
todo_call
|
||||||
|
),
|
||||||
|
|
||||||
|
(
|
||||||
|
"java/io/FileOutputStream",
|
||||||
|
"write",
|
||||||
|
MethodDescriptor {
|
||||||
|
argument_types: Box::new([
|
||||||
|
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() },
|
||||||
|
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
|
||||||
|
]),
|
||||||
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
||||||
|
},
|
||||||
|
todo_call
|
||||||
|
),
|
||||||
|
|
||||||
|
(
|
||||||
|
"java/io/FileOutputStream",
|
||||||
|
"writeBytes",
|
||||||
|
MethodDescriptor {
|
||||||
|
argument_types: Box::new([
|
||||||
|
AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() },
|
||||||
|
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() },
|
||||||
|
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() },
|
||||||
|
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
|
||||||
|
]),
|
||||||
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
||||||
|
},
|
||||||
|
todo_call
|
||||||
|
),
|
||||||
|
|
||||||
|
(
|
||||||
|
"java/io/FileOutputStream",
|
||||||
|
"initIDs",
|
||||||
|
MethodDescriptor {
|
||||||
|
argument_types: Box::new([
|
||||||
|
]),
|
||||||
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
||||||
|
},
|
||||||
|
ignore_call
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (classname, methodname, methoddescriptor, binding) in native_mappings {
|
for (classname, methodname, methoddescriptor, binding) in native_mappings {
|
||||||
|
|
Loading…
Reference in a new issue