Working up until registerNatives()
This commit is contained in:
parent
5bc0d813e5
commit
3282694b32
4 changed files with 268 additions and 58 deletions
206
src/jvm.rs
206
src/jvm.rs
|
@ -10,8 +10,8 @@ use crate::classfile::{ JavaClassFile, FieldInfo, MethodInfo, MethodDescriptor,
|
|||
use crate::classstore;
|
||||
use crate::classstore::ClassStore;
|
||||
use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo};
|
||||
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference };
|
||||
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator, CompatibleTypesIterator };
|
||||
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference, CompartmentEntry };
|
||||
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator };
|
||||
use crate::stackframe;
|
||||
use crate::stackframe::{ StackFrame, StackValue, OperandStack };
|
||||
|
||||
|
@ -129,21 +129,8 @@ impl JVM {
|
|||
self.class_store.set_class_objectref_by_index(self.class_store.class_idx_from_name(&parsed_class_name).unwrap(), class_object);
|
||||
}
|
||||
|
||||
fn make_array_class(&mut self, element_descriptor_string: &str) {
|
||||
let (chars_consumed, element_descriptor) = AbstractTypeDescription::parse_first(element_descriptor_string).unwrap();
|
||||
assert!(chars_consumed == element_descriptor_string.len());
|
||||
let element_class_ref = if element_descriptor.array_level == 0 {
|
||||
match element_descriptor.kind {
|
||||
AbstractTypeKind::Classname(ref name) => {
|
||||
self.class_store.get_class_objectref_from_index(
|
||||
self.class_store.class_idx_from_name(&name).unwrap()
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
self.class_store.get_array_class_ref(&element_descriptor).unwrap()
|
||||
};
|
||||
fn make_array_class(&mut self, element_class_ref: ObjectReference, element_descriptor: AbstractTypeDescription) {
|
||||
let class_class_index = self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap();
|
||||
|
||||
let array_class_object = self.heap_area.make_object(&self.class_store, 6);
|
||||
let array_class_data_object = self.heap_area.make_object(&self.class_store, 1);
|
||||
|
@ -156,7 +143,7 @@ impl JVM {
|
|||
array_class_object,
|
||||
"componentType",
|
||||
FieldValue::Reference(element_class_ref),
|
||||
self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap(),
|
||||
class_class_index,
|
||||
&self.class_store,
|
||||
).unwrap();
|
||||
// set classdata object
|
||||
|
@ -164,7 +151,7 @@ impl JVM {
|
|||
array_class_object,
|
||||
"classData",
|
||||
FieldValue::Reference(array_class_data_object),
|
||||
self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap(),
|
||||
class_class_index,
|
||||
&self.class_store,
|
||||
).unwrap();
|
||||
// set native name index on class data
|
||||
|
@ -181,6 +168,46 @@ impl JVM {
|
|||
);
|
||||
}
|
||||
|
||||
fn make_primitive_class(&mut self, class_name: &str, class_descriptor: &str) -> ObjectReference {
|
||||
let class_class_index = self.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap();
|
||||
let data_class_index = self.class_store.class_idx_from_name(&String::from("::NativeClassData")).unwrap();
|
||||
|
||||
let primitive_class_object = self.heap_area.make_object(&self.class_store, class_class_index);
|
||||
let primitive_class_data_object = self.heap_area.make_object(&self.class_store, data_class_index);
|
||||
|
||||
// set classdata object
|
||||
self.heap_area.object_area.set_object_field(
|
||||
primitive_class_object,
|
||||
"classData",
|
||||
FieldValue::Reference(primitive_class_data_object),
|
||||
class_class_index,
|
||||
&self.class_store,
|
||||
).unwrap();
|
||||
|
||||
let name_string_ref = self.heap_area.make_handmade_string(&class_name.into(), &self.class_store);
|
||||
// set name string object
|
||||
self.heap_area.object_area.set_object_field(
|
||||
primitive_class_object,
|
||||
"name",
|
||||
FieldValue::Reference(name_string_ref),
|
||||
class_class_index,
|
||||
&self.class_store,
|
||||
).unwrap();
|
||||
|
||||
// set native name index on class data
|
||||
self.heap_area.object_area.set_object_field(
|
||||
primitive_class_data_object,
|
||||
"native_class_descriptor_index",
|
||||
FieldValue::Int(self.class_store.add_native_class_descriptor(class_descriptor.into()) as i32),
|
||||
self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap(),
|
||||
&self.class_store,
|
||||
).unwrap();
|
||||
|
||||
// TODO: Set Static
|
||||
|
||||
primitive_class_object
|
||||
}
|
||||
|
||||
pub fn entrypoint(&mut self, class_name: &String, method_name: &String, arguments: &[&str]) -> Result<(), Error> {
|
||||
let entry_class = JavaClassFile {
|
||||
minor_version: 0,
|
||||
|
@ -259,11 +286,42 @@ impl JVM {
|
|||
|
||||
self.make_class_class("Ljava/lang/Byte;");
|
||||
self.make_class_class("Ljava/lang/String;");
|
||||
self.make_array_class("Ljava/lang/Byte;");
|
||||
self.make_array_class("Ljava/lang/String;");
|
||||
self.make_array_class(
|
||||
self.class_store.get_class_objectref_from_index(4),
|
||||
AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: AbstractTypeKind::Classname("java/lang/Byte".into()),
|
||||
}
|
||||
);
|
||||
self.make_array_class(
|
||||
self.class_store.get_class_objectref_from_index(5),
|
||||
AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: AbstractTypeKind::Classname("java/lang/String".into()),
|
||||
}
|
||||
);
|
||||
|
||||
self.heap_area.fill_byte_cache(&self.class_store);
|
||||
|
||||
let int_class_ref = self.make_primitive_class("int", "I");
|
||||
let byte_class_ref = self.make_primitive_class("byte", "B");
|
||||
|
||||
self.make_array_class(
|
||||
int_class_ref,
|
||||
AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: AbstractTypeKind::Int(),
|
||||
}
|
||||
);
|
||||
self.make_array_class(
|
||||
byte_class_ref,
|
||||
AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: AbstractTypeKind::Byte(),
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
let string_refs = arguments.iter()
|
||||
.map(|s| self.heap_area.make_handmade_string(&s.to_string(), &self.class_store))
|
||||
.collect();
|
||||
|
@ -312,8 +370,8 @@ impl JVM {
|
|||
self.init_class_hierarchy(&name)?;
|
||||
},
|
||||
|
||||
JVMCallbackOperation::MakeArrayClass(component_descriptor_string) => {
|
||||
self.make_array_class(&component_descriptor_string);
|
||||
JVMCallbackOperation::MakeArrayClass(component_class_ref, component_descriptor) => {
|
||||
self.make_array_class(component_class_ref, component_descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -519,6 +577,16 @@ impl JVM {
|
|||
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
|
||||
}
|
||||
|
||||
Instruction::BranchIntInequality(branch_offset) => {
|
||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
if value_1 != value_2 {
|
||||
frame.instruction_pointer -= offset as u32;
|
||||
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
|
||||
}
|
||||
}
|
||||
|
||||
Instruction::BranchZero(branch_offset) => {
|
||||
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
|
@ -783,6 +851,21 @@ impl JVM {
|
|||
}
|
||||
},
|
||||
|
||||
Instruction::LoadWideConstant(wide_index) => {
|
||||
// TODO: Handle error instead of unwrap
|
||||
match class.pool_entry(wide_index).unwrap() {
|
||||
ConstantPoolInfo::String(_) => {
|
||||
// TODO: Handle error instead of unwrap
|
||||
let string_constant = class.gather_string(wide_index).unwrap();
|
||||
|
||||
let string_obj_ref = self.heap_area.make_handmade_string(string_constant, &self.class_store);
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?;
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
},
|
||||
|
||||
Instruction::LoadLocalInt0() => {
|
||||
load_local_int(class, method, frame, 0)?;
|
||||
}
|
||||
|
@ -815,44 +898,61 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(factor_1 * factor_2)))?;
|
||||
}
|
||||
|
||||
Instruction::NewArray(class_index) => {
|
||||
Instruction::NewArray(component_class_index) => {
|
||||
// construct single level array
|
||||
let class_name = class.gather_class(class_index)?;
|
||||
let component_class_name = class.gather_class(component_class_index)?;
|
||||
|
||||
if ! self.class_store.have_class(class_name) {
|
||||
if ! self.class_store.have_class(component_class_name) {
|
||||
// rewind the bytecode offset, I'll need to execute this instruction again
|
||||
frame.instruction_pointer -= offset as u32;
|
||||
return Ok(JVMCallbackOperation::LoadClass(class_name.to_string()));
|
||||
return Ok(JVMCallbackOperation::LoadClass(component_class_name.to_string()));
|
||||
}
|
||||
if ! self.class_store.was_init(class_name).unwrap() {
|
||||
if ! self.class_store.was_init(component_class_name).unwrap() {
|
||||
// rewind the bytecode offset, I'll need to execute this instruction again
|
||||
frame.instruction_pointer -= offset as u32;
|
||||
return Ok(JVMCallbackOperation::InitClass(class_name.to_string()));
|
||||
return Ok(JVMCallbackOperation::InitClass(component_class_name.to_string()));
|
||||
}
|
||||
|
||||
let class_descriptor = AbstractTypeDescription {
|
||||
let component_class_descriptor = AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: match class_name {
|
||||
_ => AbstractTypeKind::Classname(class_name.to_string())
|
||||
kind: match component_class_name {
|
||||
_ => AbstractTypeKind::Classname(component_class_name.to_string())
|
||||
}
|
||||
};
|
||||
|
||||
let array_descriptor = AbstractTypeDescription {
|
||||
array_level: 1,
|
||||
kind: class_descriptor.kind.clone(),
|
||||
kind: component_class_descriptor.kind.clone(),
|
||||
};
|
||||
|
||||
if let None = self.class_store.get_array_class_ref(&array_descriptor) {
|
||||
let complete_type_descriptor = format!("L{};", class_name);
|
||||
|
||||
// rewind the bytecode offset, I'll need to execute this instruction again
|
||||
frame.instruction_pointer -= offset as u32;
|
||||
|
||||
return Ok(JVMCallbackOperation::MakeArrayClass(complete_type_descriptor));
|
||||
let component_class_index = self.class_store.class_idx_from_name(component_class_name).unwrap();
|
||||
let component_class_class_ref = self.class_store.get_class_objectref_from_index(component_class_index);
|
||||
return Ok(JVMCallbackOperation::MakeArrayClass(component_class_class_ref, component_class_descriptor));
|
||||
}
|
||||
|
||||
let array_capacity = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let array_ref = self.heap_area.make_empty_array(&self.class_store, class_descriptor, array_capacity as usize);
|
||||
let array_ref = self.heap_area.make_empty_array(&self.class_store, component_class_descriptor, array_capacity as usize);
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(array_ref)))?;
|
||||
}
|
||||
|
||||
Instruction::NewPrimitiveArray(array_type) => {
|
||||
let array_capacity = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
const BYTE: u8 = 8;
|
||||
let array_ref = match array_type {
|
||||
BYTE => {
|
||||
let array_ref = self.heap_area.make_primitive_byte_array(array_capacity as usize, &self.class_store);
|
||||
|
||||
array_ref
|
||||
}
|
||||
|
||||
_ => todo!()
|
||||
};
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(array_ref)))?;
|
||||
}
|
||||
|
@ -990,6 +1090,36 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int >> shift)))?;
|
||||
},
|
||||
|
||||
Instruction::StoreIntoRArray() => {
|
||||
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let array_ref = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
// TODO: Type checking
|
||||
|
||||
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Reference(value));
|
||||
}
|
||||
|
||||
Instruction::StoreIntoBArray() => {
|
||||
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let array_ref = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
match self.heap_area.object_area.get_entry(array_ref) {
|
||||
CompartmentEntry::ByteArray(_) => {
|
||||
let byte_value = value.to_ne_bytes()[3];
|
||||
|
||||
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Byte(byte_value));
|
||||
}
|
||||
_ => todo!(), // TODO: Handle as error, Boolean arrays also
|
||||
}
|
||||
}
|
||||
|
||||
Instruction::StoreLocalInt(index) => {
|
||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Int(int)))?;
|
||||
},
|
||||
Instruction::StoreLocalInt0() => {
|
||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
|
@ -1051,7 +1181,7 @@ enum JVMCallbackOperation {
|
|||
PushFrame(StackFrame),
|
||||
LoadClass(String),
|
||||
InitClass(String),
|
||||
MakeArrayClass(String),
|
||||
MakeArrayClass(ObjectReference, AbstractTypeDescription),
|
||||
}
|
||||
|
||||
fn load_local_reference(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue