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),
|
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),
|
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),
|
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),
|
0x14 => (Instruction::LoadConstant64((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||||
|
|
||||||
0x1A => (Instruction::LoadLocalInt0(), 1),
|
0x1A => (Instruction::LoadLocalInt0(), 1),
|
||||||
|
@ -41,6 +42,7 @@ impl Bytecode {
|
||||||
0x2D => (Instruction::LoadLocalReference3(), 1),
|
0x2D => (Instruction::LoadLocalReference3(), 1),
|
||||||
|
|
||||||
0x32 => (Instruction::ArrayElement(), 1),
|
0x32 => (Instruction::ArrayElement(), 1),
|
||||||
|
0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2),
|
||||||
0x3B => (Instruction::StoreLocalInt0(), 1),
|
0x3B => (Instruction::StoreLocalInt0(), 1),
|
||||||
0x3C => (Instruction::StoreLocalInt1(), 1),
|
0x3C => (Instruction::StoreLocalInt1(), 1),
|
||||||
0x3D => (Instruction::StoreLocalInt2(), 1),
|
0x3D => (Instruction::StoreLocalInt2(), 1),
|
||||||
|
@ -50,6 +52,9 @@ impl Bytecode {
|
||||||
0x4D => (Instruction::StoreReference2(), 1),
|
0x4D => (Instruction::StoreReference2(), 1),
|
||||||
0x4E => (Instruction::StoreReference3(), 1),
|
0x4E => (Instruction::StoreReference3(), 1),
|
||||||
|
|
||||||
|
0x53 => (Instruction::StoreIntoRArray(), 1),
|
||||||
|
0x54 => (Instruction::StoreIntoBArray(), 1),
|
||||||
|
|
||||||
0x57 => (Instruction::Pop(), 1),
|
0x57 => (Instruction::Pop(), 1),
|
||||||
0x59 => (Instruction::Duplicate(), 1),
|
0x59 => (Instruction::Duplicate(), 1),
|
||||||
|
|
||||||
|
@ -85,6 +90,31 @@ impl Bytecode {
|
||||||
(Instruction::BranchNonNegative(i16::from_be_bytes(bytes)), 3)
|
(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),
|
0xAC => (Instruction::ReturnInt(), 1),
|
||||||
0xA7 => {
|
0xA7 => {
|
||||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
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),
|
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),
|
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),
|
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),
|
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||||
0xBE => (Instruction::ArrayLength(), 1),
|
0xBE => (Instruction::ArrayLength(), 1),
|
||||||
_ => (Instruction::Unknown(opcode), 1)
|
_ => (Instruction::Unknown(opcode), 1)
|
||||||
|
@ -150,6 +181,8 @@ pub enum Instruction {
|
||||||
LoadByteImmediate(u8) = 0x10, // push immediate short
|
LoadByteImmediate(u8) = 0x10, // push immediate short
|
||||||
LoadShortImmediate(u16) = 0x11, // push immediate short
|
LoadShortImmediate(u16) = 0x11, // push immediate short
|
||||||
LoadConstant(u8) = 0x12, // Push from constant pool
|
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
|
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
|
||||||
LoadLocalInt0() = 0x1A, // Load int from local variable
|
LoadLocalInt0() = 0x1A, // Load int from local variable
|
||||||
LoadLocalInt1() = 0x1B, // 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
|
LoadLocalReference3() = 0x2D, // Load local reference variable reference onto stack
|
||||||
|
|
||||||
ArrayElement() = 0x32, // load element from array
|
ArrayElement() = 0x32, // load element from array
|
||||||
|
StoreLocalInt(u8) = 0x36, // store into indexed local variable
|
||||||
StoreLocalInt0() = 0x3B, // store int into local variable
|
StoreLocalInt0() = 0x3B, // store int into local variable
|
||||||
StoreLocalInt1() = 0x3C, // store int into local variable
|
StoreLocalInt1() = 0x3C, // store int into local variable
|
||||||
StoreLocalInt2() = 0x3D, // 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
|
StoreReference2() = 0x4D, // store reference into local variable
|
||||||
StoreReference3() = 0x4E, // 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
|
Pop() = 0x57, // Pop top stack value
|
||||||
Duplicate() = 0x59, // duplicate top stack value
|
Duplicate() = 0x59, // duplicate top stack value
|
||||||
|
|
||||||
|
@ -197,6 +233,7 @@ pub enum Instruction {
|
||||||
BranchIntLessThan(i16) = 0xA1,
|
BranchIntLessThan(i16) = 0xA1,
|
||||||
BranchIntGreaterEquals(i16) = 0xA2,
|
BranchIntGreaterEquals(i16) = 0xA2,
|
||||||
BranchIntGreaterThan(i16) = 0xA3,
|
BranchIntGreaterThan(i16) = 0xA3,
|
||||||
|
BranchIntLessEquals(i16) = 0xA4,
|
||||||
|
|
||||||
BranchAlways(i16) = 0xA7, // branch if true
|
BranchAlways(i16) = 0xA7, // branch if true
|
||||||
ReturnInt() = 0xAC, // return integer from function
|
ReturnInt() = 0xAC, // return integer from function
|
||||||
|
@ -212,6 +249,7 @@ pub enum Instruction {
|
||||||
InvokeStatic(u16) = 0xB8, // invoke static function
|
InvokeStatic(u16) = 0xB8, // invoke static function
|
||||||
InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function
|
InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function
|
||||||
NewObject(u16) = 0xBB, // Create a new object from a constant-pool class reference
|
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
|
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
|
||||||
ArrayLength() = 0xBE, // Get length from array reference
|
ArrayLength() = 0xBE, // Get length from array reference
|
||||||
Unknown(u8),
|
Unknown(u8),
|
||||||
|
|
|
@ -202,7 +202,7 @@ impl JavaClassFile {
|
||||||
return None;
|
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);
|
return pool_entry(&self.constant_pool, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,13 @@ impl HeapArea {
|
||||||
self.memory_used += self.object_area.fill_byte_cache(class_store);
|
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 {
|
pub fn make_handmade_string(&mut self, s: &String, class_store: &ClassStore) -> ObjectReference {
|
||||||
let utf16_bytes = {
|
let utf16_bytes = {
|
||||||
let utf16 = s.encode_utf16();
|
let utf16 = s.encode_utf16();
|
||||||
|
@ -127,8 +134,29 @@ impl ObjectArea {
|
||||||
self.byte_object_cache[byte as usize]
|
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) {
|
fn make_empty_array(&mut self, class_store: &ClassStore, element_type_desc: AbstractTypeDescription, capacity: usize) -> (ObjectReference, usize) {
|
||||||
//
|
|
||||||
// make new type desc
|
// make new type desc
|
||||||
let array_type_desc = AbstractTypeDescription {
|
let array_type_desc = AbstractTypeDescription {
|
||||||
array_level: 1 + element_type_desc.array_level,
|
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_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,
|
class_ref: array_class_ref,
|
||||||
content: vec![ObjectReference::NULL; capacity].into_boxed_slice(),
|
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;
|
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());
|
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() {
|
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);
|
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)
|
let fields: Vec<_> = ClassFieldIterator::new(target_class_index, class_store)
|
||||||
.filter(|f| ! (f.access_flags & FieldAccessFlag::Static))
|
.filter(|f| ! (f.access_flags & FieldAccessFlag::Static))
|
||||||
.map(|f| ObjectField { value: FieldValue::default_for(&f.descriptor) })
|
.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 {
|
fn get_reference_class_ref(&self, reference: ObjectReference, class_store: &ClassStore) -> ObjectReference {
|
||||||
match self.get_entry(reference) {
|
match self.get_entry(reference) {
|
||||||
CompartmentEntry::Object(o) => class_store.get_class_objectref_from_index(o.class_index),
|
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!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,7 +258,7 @@ impl ObjectArea {
|
||||||
return ObjectReference(object_index + (DEFAULT_COMPARTMENT_CAPACITY * (compartment_index as u32 + 1)));
|
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 index = reference.0;
|
||||||
let compartment_index: u32 = (index / DEFAULT_COMPARTMENT_CAPACITY) - 1;
|
let compartment_index: u32 = (index / DEFAULT_COMPARTMENT_CAPACITY) - 1;
|
||||||
let object_index: u32 = index % DEFAULT_COMPARTMENT_CAPACITY;
|
let object_index: u32 = index % DEFAULT_COMPARTMENT_CAPACITY;
|
||||||
|
@ -255,7 +283,7 @@ impl ObjectArea {
|
||||||
pub fn get_array_length(&self, reference: ObjectReference) -> usize {
|
pub fn get_array_length(&self, reference: ObjectReference) -> usize {
|
||||||
// TODO: Throw errors
|
// TODO: Throw errors
|
||||||
let array = match self.get_entry(reference) {
|
let array = match self.get_entry(reference) {
|
||||||
CompartmentEntry::Array(a) => a,
|
CompartmentEntry::ReferenceArray(a) => a,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -265,7 +293,7 @@ impl ObjectArea {
|
||||||
pub fn get_array_element(&self, array_ref: ObjectReference, element_index: i32) -> ObjectReference {
|
pub fn get_array_element(&self, array_ref: ObjectReference, element_index: i32) -> ObjectReference {
|
||||||
// TODO: Throw errors
|
// TODO: Throw errors
|
||||||
let array = match self.get_entry(array_ref) {
|
let array = match self.get_entry(array_ref) {
|
||||||
CompartmentEntry::Array(a) => a,
|
CompartmentEntry::ReferenceArray(a) => a,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -301,15 +329,21 @@ impl ObjectArea {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_array_element(&mut self, array_reference: ObjectReference, index: usize, element: ObjectReference) {
|
pub fn set_array_element(&mut self, array_reference: ObjectReference, index: usize, element: FieldValue) {
|
||||||
let array = match self.get_entry_mut(array_reference) {
|
match self.get_entry_mut(array_reference) {
|
||||||
CompartmentEntry::Array(a) => a,
|
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!(),
|
_ => 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> {
|
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::Object(_) => unreachable!(),
|
||||||
CompartmentEntry::Array(_) => unreachable!(),
|
CompartmentEntry::ReferenceArray(_) => unreachable!(),
|
||||||
|
CompartmentEntry::ByteArray(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
*self.objects.get_mut(compartment_index).unwrap() = object;
|
*self.objects.get_mut(compartment_index).unwrap() = object;
|
||||||
|
@ -420,13 +455,20 @@ impl DebugTrait for ObjectCompartment {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CompartmentEntry {
|
pub enum CompartmentEntry {
|
||||||
Object(HeapObject),
|
Object(HeapObject),
|
||||||
Array(HeapArray),
|
ReferenceArray(ReferenceArray),
|
||||||
|
ByteArray(ByteArray),
|
||||||
EmptyNext(usize),
|
EmptyNext(usize),
|
||||||
EmptyTail(), // last empty value
|
EmptyTail(), // last empty value
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HeapArray {
|
pub struct ByteArray {
|
||||||
|
class_ref: ObjectReference,
|
||||||
|
content: Box<[u8]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ReferenceArray {
|
||||||
class_ref: ObjectReference,
|
class_ref: ObjectReference,
|
||||||
content: Box<[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;
|
||||||
use crate::classstore::ClassStore;
|
use crate::classstore::ClassStore;
|
||||||
use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo};
|
use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo};
|
||||||
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference };
|
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference, CompartmentEntry };
|
||||||
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator, CompatibleTypesIterator };
|
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator };
|
||||||
use crate::stackframe;
|
use crate::stackframe;
|
||||||
use crate::stackframe::{ StackFrame, StackValue, OperandStack };
|
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);
|
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) {
|
fn make_array_class(&mut self, element_class_ref: ObjectReference, element_descriptor: AbstractTypeDescription) {
|
||||||
let (chars_consumed, element_descriptor) = AbstractTypeDescription::parse_first(element_descriptor_string).unwrap();
|
let class_class_index = self.class_store.class_idx_from_name(&"java/lang/Class".to_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()
|
|
||||||
};
|
|
||||||
|
|
||||||
let array_class_object = self.heap_area.make_object(&self.class_store, 6);
|
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);
|
let array_class_data_object = self.heap_area.make_object(&self.class_store, 1);
|
||||||
|
@ -156,7 +143,7 @@ impl JVM {
|
||||||
array_class_object,
|
array_class_object,
|
||||||
"componentType",
|
"componentType",
|
||||||
FieldValue::Reference(element_class_ref),
|
FieldValue::Reference(element_class_ref),
|
||||||
self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap(),
|
class_class_index,
|
||||||
&self.class_store,
|
&self.class_store,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
// set classdata object
|
// set classdata object
|
||||||
|
@ -164,7 +151,7 @@ impl JVM {
|
||||||
array_class_object,
|
array_class_object,
|
||||||
"classData",
|
"classData",
|
||||||
FieldValue::Reference(array_class_data_object),
|
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,
|
&self.class_store,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
// set native name index on class data
|
// 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> {
|
pub fn entrypoint(&mut self, class_name: &String, method_name: &String, arguments: &[&str]) -> Result<(), Error> {
|
||||||
let entry_class = JavaClassFile {
|
let entry_class = JavaClassFile {
|
||||||
minor_version: 0,
|
minor_version: 0,
|
||||||
|
@ -259,11 +286,42 @@ impl JVM {
|
||||||
|
|
||||||
self.make_class_class("Ljava/lang/Byte;");
|
self.make_class_class("Ljava/lang/Byte;");
|
||||||
self.make_class_class("Ljava/lang/String;");
|
self.make_class_class("Ljava/lang/String;");
|
||||||
self.make_array_class("Ljava/lang/Byte;");
|
self.make_array_class(
|
||||||
self.make_array_class("Ljava/lang/String;");
|
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);
|
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()
|
let string_refs = arguments.iter()
|
||||||
.map(|s| self.heap_area.make_handmade_string(&s.to_string(), &self.class_store))
|
.map(|s| self.heap_area.make_handmade_string(&s.to_string(), &self.class_store))
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -312,8 +370,8 @@ impl JVM {
|
||||||
self.init_class_hierarchy(&name)?;
|
self.init_class_hierarchy(&name)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
JVMCallbackOperation::MakeArrayClass(component_descriptor_string) => {
|
JVMCallbackOperation::MakeArrayClass(component_class_ref, component_descriptor) => {
|
||||||
self.make_array_class(&component_descriptor_string);
|
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};
|
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) => {
|
Instruction::BranchZero(branch_offset) => {
|
||||||
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
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() => {
|
Instruction::LoadLocalInt0() => {
|
||||||
load_local_int(class, method, frame, 0)?;
|
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)))?;
|
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
|
// 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
|
// rewind the bytecode offset, I'll need to execute this instruction again
|
||||||
frame.instruction_pointer -= offset as u32;
|
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
|
// rewind the bytecode offset, I'll need to execute this instruction again
|
||||||
frame.instruction_pointer -= offset as u32;
|
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,
|
array_level: 0,
|
||||||
kind: match class_name {
|
kind: match component_class_name {
|
||||||
_ => AbstractTypeKind::Classname(class_name.to_string())
|
_ => AbstractTypeKind::Classname(component_class_name.to_string())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let array_descriptor = AbstractTypeDescription {
|
let array_descriptor = AbstractTypeDescription {
|
||||||
array_level: 1,
|
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) {
|
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
|
// rewind the bytecode offset, I'll need to execute this instruction again
|
||||||
frame.instruction_pointer -= offset as u32;
|
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_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)))?;
|
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)))?;
|
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() => {
|
Instruction::StoreLocalInt0() => {
|
||||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
|
@ -1051,7 +1181,7 @@ enum JVMCallbackOperation {
|
||||||
PushFrame(StackFrame),
|
PushFrame(StackFrame),
|
||||||
LoadClass(String),
|
LoadClass(String),
|
||||||
InitClass(String),
|
InitClass(String),
|
||||||
MakeArrayClass(String),
|
MakeArrayClass(ObjectReference, AbstractTypeDescription),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_local_reference(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {
|
fn load_local_reference(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {
|
||||||
|
|
Loading…
Reference in a new issue