Working up until registerNatives()
This commit is contained in:
parent
5bc0d813e5
commit
3282694b32
4 changed files with 268 additions and 58 deletions
|
@ -25,6 +25,7 @@ impl Bytecode {
|
|||
0x10 => (Instruction::LoadByteImmediate(self.bytes[offset+1]), 2),
|
||||
0x11 => (Instruction::LoadShortImmediate((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||
0x12 => (Instruction::LoadConstant(self.bytes[offset+1]), 2),
|
||||
0x13 => (Instruction::LoadWideConstant((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||
0x14 => (Instruction::LoadConstant64((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||
|
||||
0x1A => (Instruction::LoadLocalInt0(), 1),
|
||||
|
@ -41,6 +42,7 @@ impl Bytecode {
|
|||
0x2D => (Instruction::LoadLocalReference3(), 1),
|
||||
|
||||
0x32 => (Instruction::ArrayElement(), 1),
|
||||
0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2),
|
||||
0x3B => (Instruction::StoreLocalInt0(), 1),
|
||||
0x3C => (Instruction::StoreLocalInt1(), 1),
|
||||
0x3D => (Instruction::StoreLocalInt2(), 1),
|
||||
|
@ -50,6 +52,9 @@ impl Bytecode {
|
|||
0x4D => (Instruction::StoreReference2(), 1),
|
||||
0x4E => (Instruction::StoreReference3(), 1),
|
||||
|
||||
0x53 => (Instruction::StoreIntoRArray(), 1),
|
||||
0x54 => (Instruction::StoreIntoBArray(), 1),
|
||||
|
||||
0x57 => (Instruction::Pop(), 1),
|
||||
0x59 => (Instruction::Duplicate(), 1),
|
||||
|
||||
|
@ -85,6 +90,31 @@ impl Bytecode {
|
|||
(Instruction::BranchNonNegative(i16::from_be_bytes(bytes)), 3)
|
||||
}
|
||||
|
||||
0x9F => {
|
||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||
(Instruction::BranchIntEquality(i16::from_be_bytes(bytes)), 3)
|
||||
}
|
||||
0xA0 => {
|
||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||
(Instruction::BranchIntInequality(i16::from_be_bytes(bytes)), 3)
|
||||
}
|
||||
0xA1 => {
|
||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||
(Instruction::BranchIntLessThan(i16::from_be_bytes(bytes)), 3)
|
||||
}
|
||||
0xA2 => {
|
||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||
(Instruction::BranchIntGreaterEquals(i16::from_be_bytes(bytes)), 3)
|
||||
}
|
||||
0xA3 => {
|
||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||
(Instruction::BranchIntGreaterThan(i16::from_be_bytes(bytes)), 3)
|
||||
}
|
||||
0xA4 => {
|
||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||
(Instruction::BranchIntLessEquals(i16::from_be_bytes(bytes)), 3)
|
||||
}
|
||||
|
||||
0xAC => (Instruction::ReturnInt(), 1),
|
||||
0xA7 => {
|
||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||
|
@ -102,6 +132,7 @@ impl Bytecode {
|
|||
0xB8 => (Instruction::InvokeStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||
0xBA => (Instruction::InvokeDynamic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16, (self.bytes[offset+3] as u16) << 8 | self.bytes[offset+4] as u16), 5),
|
||||
0xBB => (Instruction::NewObject((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||
0xBC => (Instruction::NewPrimitiveArray(self.bytes[offset+1]), 2),
|
||||
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||
0xBE => (Instruction::ArrayLength(), 1),
|
||||
_ => (Instruction::Unknown(opcode), 1)
|
||||
|
@ -150,6 +181,8 @@ pub enum Instruction {
|
|||
LoadByteImmediate(u8) = 0x10, // push immediate short
|
||||
LoadShortImmediate(u16) = 0x11, // push immediate short
|
||||
LoadConstant(u8) = 0x12, // Push from constant pool
|
||||
LoadWideConstant(u16) = 0x13, // Push from constant pool with wide index, don't load
|
||||
// double or long or whatever
|
||||
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
|
||||
LoadLocalInt0() = 0x1A, // Load int from local variable
|
||||
LoadLocalInt1() = 0x1B, // Load int from local variable
|
||||
|
@ -166,6 +199,7 @@ pub enum Instruction {
|
|||
LoadLocalReference3() = 0x2D, // Load local reference variable reference onto stack
|
||||
|
||||
ArrayElement() = 0x32, // load element from array
|
||||
StoreLocalInt(u8) = 0x36, // store into indexed local variable
|
||||
StoreLocalInt0() = 0x3B, // store int into local variable
|
||||
StoreLocalInt1() = 0x3C, // store int into local variable
|
||||
StoreLocalInt2() = 0x3D, // store int into local variable
|
||||
|
@ -175,6 +209,8 @@ pub enum Instruction {
|
|||
StoreReference2() = 0x4D, // store reference into local variable
|
||||
StoreReference3() = 0x4E, // store reference into local variable
|
||||
|
||||
StoreIntoRArray() = 0x53, // store value into reference array
|
||||
StoreIntoBArray() = 0x54, // store value into byte or boolean array
|
||||
Pop() = 0x57, // Pop top stack value
|
||||
Duplicate() = 0x59, // duplicate top stack value
|
||||
|
||||
|
@ -197,6 +233,7 @@ pub enum Instruction {
|
|||
BranchIntLessThan(i16) = 0xA1,
|
||||
BranchIntGreaterEquals(i16) = 0xA2,
|
||||
BranchIntGreaterThan(i16) = 0xA3,
|
||||
BranchIntLessEquals(i16) = 0xA4,
|
||||
|
||||
BranchAlways(i16) = 0xA7, // branch if true
|
||||
ReturnInt() = 0xAC, // return integer from function
|
||||
|
@ -212,6 +249,7 @@ pub enum Instruction {
|
|||
InvokeStatic(u16) = 0xB8, // invoke static function
|
||||
InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function
|
||||
NewObject(u16) = 0xBB, // Create a new object from a constant-pool class reference
|
||||
NewPrimitiveArray(u8) = 0xBC, // make a primitive array
|
||||
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
|
||||
ArrayLength() = 0xBE, // Get length from array reference
|
||||
Unknown(u8),
|
||||
|
|
|
@ -202,7 +202,7 @@ impl JavaClassFile {
|
|||
return None;
|
||||
}
|
||||
|
||||
fn pool_entry(&self, index: u16) -> Result<&ConstantPoolInfo, Error> {
|
||||
pub fn pool_entry(&self, index: u16) -> Result<&ConstantPoolInfo, Error> {
|
||||
return pool_entry(&self.constant_pool, index);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,13 @@ impl HeapArea {
|
|||
self.memory_used += self.object_area.fill_byte_cache(class_store);
|
||||
}
|
||||
|
||||
pub fn make_primitive_byte_array(&mut self, capacity: usize, class_store: &ClassStore) -> ObjectReference {
|
||||
let (array_ref, size) = self.object_area.make_primitive_byte_array(capacity, class_store);
|
||||
self.memory_used += size;
|
||||
|
||||
array_ref
|
||||
}
|
||||
|
||||
pub fn make_handmade_string(&mut self, s: &String, class_store: &ClassStore) -> ObjectReference {
|
||||
let utf16_bytes = {
|
||||
let utf16 = s.encode_utf16();
|
||||
|
@ -127,8 +134,29 @@ impl ObjectArea {
|
|||
self.byte_object_cache[byte as usize]
|
||||
}
|
||||
|
||||
fn make_primitive_byte_array(&mut self, capacity: usize, class_store: &ClassStore) -> (ObjectReference, usize) {
|
||||
// make new type desc
|
||||
let array_type_desc = AbstractTypeDescription {
|
||||
array_level: 1,
|
||||
kind: AbstractTypeKind::Byte(),
|
||||
};
|
||||
|
||||
let array_class_ref = class_store.get_array_class_ref(&array_type_desc).unwrap();
|
||||
|
||||
let array_size = capacity * std::mem::size_of::<u8>() + std::mem::size_of::<ByteArray>();
|
||||
|
||||
let array_object = ByteArray {
|
||||
class_ref: array_class_ref,
|
||||
content: vec![0_u8; capacity].into(),
|
||||
};
|
||||
|
||||
let array_ref = self.store_entry(CompartmentEntry::ByteArray(array_object));
|
||||
|
||||
(array_ref, array_size)
|
||||
}
|
||||
|
||||
fn make_empty_array(&mut self, class_store: &ClassStore, element_type_desc: AbstractTypeDescription, capacity: usize) -> (ObjectReference, usize) {
|
||||
//
|
||||
|
||||
// make new type desc
|
||||
let array_type_desc = AbstractTypeDescription {
|
||||
array_level: 1 + element_type_desc.array_level,
|
||||
|
@ -137,14 +165,14 @@ impl ObjectArea {
|
|||
|
||||
let array_class_ref = class_store.get_array_class_ref(&array_type_desc).unwrap();
|
||||
|
||||
let array_object = HeapArray {
|
||||
let array_object = ReferenceArray {
|
||||
class_ref: array_class_ref,
|
||||
content: vec![ObjectReference::NULL; capacity].into_boxed_slice(),
|
||||
};
|
||||
|
||||
let array_size = std::mem::size_of::<HeapArray>() + std::mem::size_of::<ObjectReference>() * array_object.content.len();
|
||||
let array_size = std::mem::size_of::<ReferenceArray>() + std::mem::size_of::<ObjectReference>() * array_object.content.len();
|
||||
|
||||
let array_object_ref = self.store_entry(CompartmentEntry::Array(array_object));
|
||||
let array_object_ref = self.store_entry(CompartmentEntry::ReferenceArray(array_object));
|
||||
|
||||
self.memory_used += array_size;
|
||||
|
||||
|
@ -159,13 +187,13 @@ impl ObjectArea {
|
|||
let (array_object_ref, array_size) = self.make_empty_array(class_store, array_element_type_desc, elements.len());
|
||||
|
||||
for (index, element) in elements.iter().enumerate() {
|
||||
self.set_array_element(array_object_ref, index, *element);
|
||||
self.set_array_element(array_object_ref, index, FieldValue::Reference(*element));
|
||||
}
|
||||
|
||||
return (array_object_ref, array_size);
|
||||
}
|
||||
|
||||
pub fn make(&mut self, class_store: &ClassStore, target_class_index: usize) -> (ObjectReference, usize) {
|
||||
fn make(&mut self, class_store: &ClassStore, target_class_index: usize) -> (ObjectReference, usize) {
|
||||
let fields: Vec<_> = ClassFieldIterator::new(target_class_index, class_store)
|
||||
.filter(|f| ! (f.access_flags & FieldAccessFlag::Static))
|
||||
.map(|f| ObjectField { value: FieldValue::default_for(&f.descriptor) })
|
||||
|
@ -210,7 +238,7 @@ impl ObjectArea {
|
|||
fn get_reference_class_ref(&self, reference: ObjectReference, class_store: &ClassStore) -> ObjectReference {
|
||||
match self.get_entry(reference) {
|
||||
CompartmentEntry::Object(o) => class_store.get_class_objectref_from_index(o.class_index),
|
||||
CompartmentEntry::Array(a) => a.class_ref,
|
||||
CompartmentEntry::ReferenceArray(a) => a.class_ref,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +258,7 @@ impl ObjectArea {
|
|||
return ObjectReference(object_index + (DEFAULT_COMPARTMENT_CAPACITY * (compartment_index as u32 + 1)));
|
||||
}
|
||||
|
||||
fn get_entry(&self, reference: ObjectReference) -> &CompartmentEntry {
|
||||
pub fn get_entry(&self, reference: ObjectReference) -> &CompartmentEntry {
|
||||
let index = reference.0;
|
||||
let compartment_index: u32 = (index / DEFAULT_COMPARTMENT_CAPACITY) - 1;
|
||||
let object_index: u32 = index % DEFAULT_COMPARTMENT_CAPACITY;
|
||||
|
@ -255,7 +283,7 @@ impl ObjectArea {
|
|||
pub fn get_array_length(&self, reference: ObjectReference) -> usize {
|
||||
// TODO: Throw errors
|
||||
let array = match self.get_entry(reference) {
|
||||
CompartmentEntry::Array(a) => a,
|
||||
CompartmentEntry::ReferenceArray(a) => a,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
|
@ -265,7 +293,7 @@ impl ObjectArea {
|
|||
pub fn get_array_element(&self, array_ref: ObjectReference, element_index: i32) -> ObjectReference {
|
||||
// TODO: Throw errors
|
||||
let array = match self.get_entry(array_ref) {
|
||||
CompartmentEntry::Array(a) => a,
|
||||
CompartmentEntry::ReferenceArray(a) => a,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
|
@ -301,15 +329,21 @@ impl ObjectArea {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_array_element(&mut self, array_reference: ObjectReference, index: usize, element: ObjectReference) {
|
||||
let array = match self.get_entry_mut(array_reference) {
|
||||
CompartmentEntry::Array(a) => a,
|
||||
pub fn set_array_element(&mut self, array_reference: ObjectReference, index: usize, element: FieldValue) {
|
||||
match self.get_entry_mut(array_reference) {
|
||||
CompartmentEntry::ReferenceArray(array) => {
|
||||
let array_element = array.content.get_mut(index).unwrap();
|
||||
|
||||
*array_element = match element { FieldValue::Reference(r) => r, _ => unreachable!() } ;
|
||||
},
|
||||
CompartmentEntry::ByteArray(array) => {
|
||||
let array_element = array.content.get_mut(index).unwrap();
|
||||
|
||||
*array_element = match element { FieldValue::Byte(b) => b, _ => unreachable!() } ;
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let array_element = array.content.get_mut(index).unwrap();
|
||||
|
||||
*array_element = element;
|
||||
}
|
||||
|
||||
pub fn set_object_field(&mut self, reference: ObjectReference, field_name: &str, value: FieldValue, accessing_class_idx: usize, class_store: &ClassStore) -> Result<(), Error> {
|
||||
|
@ -392,7 +426,8 @@ impl ObjectCompartment {
|
|||
},
|
||||
|
||||
CompartmentEntry::Object(_) => unreachable!(),
|
||||
CompartmentEntry::Array(_) => unreachable!(),
|
||||
CompartmentEntry::ReferenceArray(_) => unreachable!(),
|
||||
CompartmentEntry::ByteArray(_) => unreachable!(),
|
||||
}
|
||||
|
||||
*self.objects.get_mut(compartment_index).unwrap() = object;
|
||||
|
@ -420,13 +455,20 @@ impl DebugTrait for ObjectCompartment {
|
|||
#[derive(Debug)]
|
||||
pub enum CompartmentEntry {
|
||||
Object(HeapObject),
|
||||
Array(HeapArray),
|
||||
ReferenceArray(ReferenceArray),
|
||||
ByteArray(ByteArray),
|
||||
EmptyNext(usize),
|
||||
EmptyTail(), // last empty value
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HeapArray {
|
||||
pub struct ByteArray {
|
||||
class_ref: ObjectReference,
|
||||
content: Box<[u8]>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReferenceArray {
|
||||
class_ref: ObjectReference,
|
||||
content: Box<[ObjectReference]>,
|
||||
}
|
||||
|
|
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…
Reference in a new issue