Char arrays
This commit is contained in:
parent
6610b09c16
commit
c6e4ecec3d
6 changed files with 407 additions and 55 deletions
|
@ -49,6 +49,7 @@ impl Bytecode {
|
|||
0x2D => (Instruction::LoadLocalReference3(), 1),
|
||||
|
||||
0x32 => (Instruction::ArrayElement(), 1),
|
||||
0x33 => (Instruction::LoadFromBArray(), 1),
|
||||
0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2),
|
||||
0x3B => (Instruction::StoreLocalInt0(), 1),
|
||||
0x3C => (Instruction::StoreLocalInt1(), 1),
|
||||
|
@ -66,6 +67,7 @@ impl Bytecode {
|
|||
0x59 => (Instruction::Duplicate(), 1),
|
||||
|
||||
0x60 => (Instruction::AddInt(), 1),
|
||||
0x64 => (Instruction::SubtractInt(), 1),
|
||||
0x68 => (Instruction::MultiplyInt(), 1),
|
||||
0x6C => (Instruction::DivideInt(), 1),
|
||||
0x6D => (Instruction::DivideLong(), 1),
|
||||
|
@ -73,6 +75,7 @@ impl Bytecode {
|
|||
0x7A => (Instruction::ShiftIntRight(), 1),
|
||||
|
||||
0x80 => (Instruction::OrInt(), 1),
|
||||
0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3),
|
||||
|
||||
0x95 => (Instruction::CompareFloatL(), 1),
|
||||
0x96 => (Instruction::CompareFloatG(), 1),
|
||||
|
@ -155,6 +158,7 @@ impl Bytecode {
|
|||
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||
0xBE => (Instruction::ArrayLength(), 1),
|
||||
|
||||
0xC0 => (Instruction::CheckCast((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||
0xC1 => (Instruction::InstanceOf((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||
0xC2 => (Instruction::EnterMonitor(), 1),
|
||||
0xC3 => (Instruction::ExitMonitor(), 1),
|
||||
|
@ -238,6 +242,7 @@ pub enum Instruction {
|
|||
LoadLocalReference3() = 0x2D, // Load local reference variable reference onto stack
|
||||
|
||||
ArrayElement() = 0x32, // load element from array
|
||||
LoadFromBArray() = 0x33, // store into byte array
|
||||
StoreLocalInt(u8) = 0x36, // store into indexed local variable
|
||||
StoreLocalInt0() = 0x3B, // store int into local variable
|
||||
StoreLocalInt1() = 0x3C, // store int into local variable
|
||||
|
@ -254,6 +259,7 @@ pub enum Instruction {
|
|||
Duplicate() = 0x59, // duplicate top stack value
|
||||
|
||||
AddInt() = 0x60, // int addition
|
||||
SubtractInt() = 0x64, // int subtraction
|
||||
MultiplyInt() = 0x68, // int multiplication
|
||||
DivideInt() = 0x6C, // integer division, round toward zero and more rules
|
||||
DivideLong() = 0x6D, // long division
|
||||
|
@ -261,6 +267,7 @@ pub enum Instruction {
|
|||
ShiftIntRight() = 0x7a, // shift int
|
||||
|
||||
OrInt() = 0x80, // value, value => or
|
||||
IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8
|
||||
|
||||
CompareFloatL() = 0x95, // compare float, push -1 if one is NaN
|
||||
CompareFloatG() = 0x96, // compare float, push 1 if one is NaN
|
||||
|
@ -298,7 +305,8 @@ pub enum Instruction {
|
|||
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
|
||||
ArrayLength() = 0xBE, // Get length from array reference
|
||||
|
||||
InstanceOf(u16) = 0xC1, // branch if Null
|
||||
CheckCast(u16) = 0xC0, // throw exception on fail
|
||||
InstanceOf(u16) = 0xC1, // push integer result for success
|
||||
EnterMonitor() = 0xC2, // enter the synchronization monitor of an object
|
||||
ExitMonitor() = 0xC3, // exit the synchronization monitor of an object
|
||||
BranchNull(i16) = 0xC6, // branch if Null
|
||||
|
|
|
@ -33,7 +33,7 @@ pub struct PrimitiveClassStore {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ClassStoreEntry {
|
||||
pub struct ClassStoreEntry {
|
||||
was_init: bool,
|
||||
class_object: ObjectReference,
|
||||
class_file: JavaClassFile,
|
||||
|
@ -133,6 +133,8 @@ impl ClassStore {
|
|||
if path_buf.is_file() {
|
||||
return self.load_class_from_file(&path_buf);
|
||||
}
|
||||
|
||||
path_buf.clear();
|
||||
};
|
||||
|
||||
return Err(Error::ClassNotFoundError(format!("Could not find class '{classname}' in classpath")));
|
||||
|
|
|
@ -76,10 +76,11 @@ impl HeapArea {
|
|||
byte_buffer
|
||||
};
|
||||
|
||||
let byte_object_refs = utf16_bytes.iter().map(|byte| self.object_area.cached_byte_object(*byte)).collect();
|
||||
|
||||
let byte_array_ref = self.make_array(class_store, byte_object_refs);
|
||||
let byte_array_ref = self.make_primitive_byte_array(utf16_bytes.len(), class_store);
|
||||
|
||||
for (index, byte) in utf16_bytes.iter().enumerate() {
|
||||
self.object_area.set_array_element(byte_array_ref, index, FieldValue::Byte(*byte));
|
||||
}
|
||||
|
||||
let string_class_index = class_store.class_idx_from_name(&String::from("java/lang/String")).unwrap();
|
||||
let string_ref = self.make_object(class_store, string_class_index);
|
||||
|
@ -91,6 +92,12 @@ impl HeapArea {
|
|||
string_ref
|
||||
}
|
||||
|
||||
pub fn make_primitive_char_array(&mut self, array_capacity: usize, class_store: &ClassStore) -> ObjectReference {
|
||||
let (array_ref, size) = self.object_area.make_primitive_char_array(array_capacity, class_store);
|
||||
self.memory_used += size;
|
||||
|
||||
array_ref
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
|
@ -214,8 +221,7 @@ impl ObjectArea {
|
|||
return (object_ref, object_size);
|
||||
}
|
||||
|
||||
pub fn get_reference_native_class_name<'a>(&self, reference: ObjectReference, class_store: &'a ClassStore) -> &'a String {
|
||||
let class_ref = self.get_reference_class_ref(reference, class_store);
|
||||
pub fn get_class_ref_native_class_name<'a>(&self, class_ref: ObjectReference, class_store: &'a ClassStore) -> &'a String {
|
||||
let class_data_ref = match self.get_object_field(class_ref, "classData", self.get_object_class_index(class_ref), class_store).unwrap() {
|
||||
FieldValue::Reference(r) => r,
|
||||
_ => unreachable!(),
|
||||
|
@ -228,6 +234,11 @@ impl ObjectArea {
|
|||
return class_store.get_native_class_name(native_name_index as usize);
|
||||
}
|
||||
|
||||
pub fn get_reference_native_class_name<'a>(&self, reference: ObjectReference, class_store: &'a ClassStore) -> &'a String {
|
||||
let class_ref = self.get_reference_class_ref(reference, class_store);
|
||||
self.get_class_ref_native_class_name(class_ref, class_store)
|
||||
}
|
||||
|
||||
pub fn get_object_class_index(&self, reference: ObjectReference) -> usize {
|
||||
match self.get_entry(reference) {
|
||||
CompartmentEntry::Object(o) => o.class_index,
|
||||
|
@ -282,22 +293,26 @@ impl ObjectArea {
|
|||
|
||||
pub fn get_array_length(&self, reference: ObjectReference) -> usize {
|
||||
// TODO: Throw errors
|
||||
let array = match self.get_entry(reference) {
|
||||
CompartmentEntry::ReferenceArray(a) => a,
|
||||
match self.get_entry(reference) {
|
||||
CompartmentEntry::ReferenceArray(a) => a.content.len(),
|
||||
CompartmentEntry::ByteArray(b) => b.content.len(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
array.content.len()
|
||||
}
|
||||
}
|
||||
|
||||
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) -> FieldValue {
|
||||
// TODO: Throw errors
|
||||
let array = match self.get_entry(array_ref) {
|
||||
CompartmentEntry::ReferenceArray(a) => a,
|
||||
match self.get_entry(array_ref) {
|
||||
CompartmentEntry::ReferenceArray(array) => {
|
||||
let element = array.content[element_index as usize];
|
||||
FieldValue::Reference(element)
|
||||
}
|
||||
CompartmentEntry::ByteArray(array) => {
|
||||
let element = array.content[element_index as usize];
|
||||
FieldValue::Byte(element)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
array.content[element_index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_object_field(&self, reference: ObjectReference, field_name: &str, accessing_class_idx: usize, class_store: &ClassStore) -> Result<FieldValue, Error> {
|
||||
|
@ -387,6 +402,27 @@ impl ObjectArea {
|
|||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn make_primitive_char_array(&mut self, array_capacity: usize, class_store: &ClassStore) -> (ObjectReference, usize) {
|
||||
// make new type desc
|
||||
let array_type_desc = AbstractTypeDescription {
|
||||
array_level: 1,
|
||||
kind: AbstractTypeKind::Char(),
|
||||
};
|
||||
|
||||
let array_class_ref = class_store.get_array_class_ref(&array_type_desc).unwrap();
|
||||
|
||||
let array_size = array_capacity * std::mem::size_of::<u8>() + std::mem::size_of::<ByteArray>();
|
||||
|
||||
let array_object = CharArray {
|
||||
class_ref: array_class_ref,
|
||||
content: vec![0; array_capacity].into(),
|
||||
};
|
||||
|
||||
let array_ref = self.store_entry(CompartmentEntry::CharArray(array_object));
|
||||
|
||||
(array_ref, array_size)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ObjectCompartment {
|
||||
|
@ -428,6 +464,7 @@ impl ObjectCompartment {
|
|||
CompartmentEntry::Object(_) => unreachable!(),
|
||||
CompartmentEntry::ReferenceArray(_) => unreachable!(),
|
||||
CompartmentEntry::ByteArray(_) => unreachable!(),
|
||||
CompartmentEntry::CharArray(_) => unreachable!(),
|
||||
}
|
||||
|
||||
*self.objects.get_mut(compartment_index).unwrap() = object;
|
||||
|
@ -457,10 +494,17 @@ pub enum CompartmentEntry {
|
|||
Object(HeapObject),
|
||||
ReferenceArray(ReferenceArray),
|
||||
ByteArray(ByteArray),
|
||||
CharArray(CharArray),
|
||||
EmptyNext(usize),
|
||||
EmptyTail(), // last empty value
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CharArray {
|
||||
class_ref: ObjectReference,
|
||||
content: Box<[u16]>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ByteArray {
|
||||
class_ref: ObjectReference,
|
||||
|
|
142
src/jvm.rs
142
src/jvm.rs
|
@ -193,7 +193,7 @@ impl JVM {
|
|||
);
|
||||
}
|
||||
|
||||
fn make_primitive_class(&mut self, class_name: &str, class_descriptor: &str) -> ObjectReference {
|
||||
fn make_primitive_class(&mut self, class_name: &str, class_descriptor: &str, string_names: bool) -> 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();
|
||||
|
||||
|
@ -209,6 +209,7 @@ impl JVM {
|
|||
&self.class_store,
|
||||
).unwrap();
|
||||
|
||||
if string_names {
|
||||
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(
|
||||
|
@ -218,6 +219,7 @@ impl JVM {
|
|||
class_class_index,
|
||||
&self.class_store,
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
// set native name index on class data
|
||||
self.heap_area.object_area.set_object_field(
|
||||
|
@ -365,22 +367,7 @@ impl JVM {
|
|||
|
||||
self.heap_area.fill_byte_cache(&self.class_store);
|
||||
|
||||
self.class_store.primitive_classes.int_class = self.make_primitive_class("int", "I");
|
||||
self.class_store.primitive_classes.byte_class = self.make_primitive_class("byte", "B");
|
||||
self.class_store.primitive_classes.char_class = self.make_primitive_class("char", "C");
|
||||
self.class_store.primitive_classes.long_class = self.make_primitive_class("long", "J");
|
||||
self.class_store.primitive_classes.float_class = self.make_primitive_class("float", "F");
|
||||
self.class_store.primitive_classes.short_class = self.make_primitive_class("short", "S");
|
||||
self.class_store.primitive_classes.double_class = self.make_primitive_class("double", "D");
|
||||
self.class_store.primitive_classes.boolean_class = self.make_primitive_class("boolean", "Z");
|
||||
|
||||
self.make_array_class(
|
||||
self.class_store.primitive_classes.int_class,
|
||||
AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: AbstractTypeKind::Int(),
|
||||
}
|
||||
);
|
||||
self.class_store.primitive_classes.byte_class = self.make_primitive_class("byte", "B", false);
|
||||
self.make_array_class(
|
||||
self.class_store.primitive_classes.byte_class,
|
||||
AbstractTypeDescription {
|
||||
|
@ -388,6 +375,39 @@ impl JVM {
|
|||
kind: AbstractTypeKind::Byte(),
|
||||
}
|
||||
);
|
||||
{
|
||||
// we can only make a byte class name after the byte array is loaded
|
||||
let string_ref = self.heap_area.make_handmade_string(&String::from("byte"), &self.class_store);
|
||||
self.heap_area.object_area.set_object_field(
|
||||
self.class_store.primitive_classes.byte_class,
|
||||
"name",
|
||||
FieldValue::Reference(string_ref),
|
||||
class_class_index,
|
||||
&self.class_store
|
||||
).unwrap();
|
||||
}
|
||||
self.class_store.primitive_classes.int_class = self.make_primitive_class("int", "I", true);
|
||||
self.class_store.primitive_classes.char_class = self.make_primitive_class("char", "C", true);
|
||||
self.class_store.primitive_classes.long_class = self.make_primitive_class("long", "J", true);
|
||||
self.class_store.primitive_classes.float_class = self.make_primitive_class("float", "F", true);
|
||||
self.class_store.primitive_classes.short_class = self.make_primitive_class("short", "S", true);
|
||||
self.class_store.primitive_classes.double_class = self.make_primitive_class("double", "D", true);
|
||||
self.class_store.primitive_classes.boolean_class = self.make_primitive_class("boolean", "Z", true);
|
||||
|
||||
self.make_array_class(
|
||||
self.class_store.primitive_classes.char_class,
|
||||
AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: AbstractTypeKind::Char(),
|
||||
}
|
||||
);
|
||||
self.make_array_class(
|
||||
self.class_store.primitive_classes.int_class,
|
||||
AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: AbstractTypeKind::Int(),
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
let string_refs = arguments.iter()
|
||||
|
@ -672,7 +692,7 @@ impl JVM {
|
|||
|
||||
let element = self.heap_area.object_area.get_array_element(array_reference, element_index);
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(element)))?;
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(element))?;
|
||||
},
|
||||
|
||||
Instruction::BranchAlways(branch_offset) => {
|
||||
|
@ -690,6 +710,16 @@ impl JVM {
|
|||
}
|
||||
}
|
||||
|
||||
Instruction::BranchIntGreaterEquals(branch_offset) => {
|
||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let value_1 = 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::BranchIntInequality(branch_offset) => {
|
||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
@ -774,6 +804,26 @@ impl JVM {
|
|||
}
|
||||
}
|
||||
|
||||
Instruction::CheckCast(classref_index) => {
|
||||
// TODO: Class loading checks
|
||||
let class_name = class.gather_class(classref_index)?;
|
||||
let class_index = self.class_store.class_idx_from_name(class_name).unwrap();
|
||||
let class_object_ref = self.class_store.get_class_objectref_from_index(class_index);
|
||||
let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store);
|
||||
let class_description = AbstractTypeDescription::parse_full(native_class_description)?;
|
||||
|
||||
let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store);
|
||||
let object_description = AbstractTypeDescription::parse_full(native_class_name)?;
|
||||
|
||||
if ! self.class_store.are_types_compatible(&object_description, &class_description) {
|
||||
// TODO: Throw Exception
|
||||
return Err(Error::RunTimeError(format!("Trying to cast an object of type {native_class_name} to {class_name}")))
|
||||
}
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(object)))?;
|
||||
}
|
||||
|
||||
Instruction::CompareFloatG() => {
|
||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
||||
|
@ -886,8 +936,27 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(fetched_value))?;
|
||||
}
|
||||
|
||||
Instruction::IncrementLocalInt(index, constant) => {
|
||||
let int = wrap_stackframe_error(class, method, frame.load_local_int(index as u16))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(index as u16, StackValue::Int(int + constant as i32)))?;
|
||||
}
|
||||
|
||||
Instruction::InstanceOf(classref_index) => {
|
||||
// TODO: Class loading checks
|
||||
let class_name = class.gather_class(classref_index)?;
|
||||
let class_index = self.class_store.class_idx_from_name(class_name).unwrap();
|
||||
let class_object_ref = self.class_store.get_class_objectref_from_index(class_index);
|
||||
let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store);
|
||||
let class_description = AbstractTypeDescription::parse_full(native_class_description)?;
|
||||
|
||||
let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store);
|
||||
let object_description = AbstractTypeDescription::parse_full(native_class_name)?;
|
||||
|
||||
let instruction_result = if self.class_store.are_types_compatible(&object_description, &class_description) { 1 } else { 0 };
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(instruction_result)))?;
|
||||
}
|
||||
|
||||
Instruction::InvokeSpecial(methodref_index) => {
|
||||
|
@ -1085,6 +1154,15 @@ impl JVM {
|
|||
}
|
||||
}
|
||||
|
||||
Instruction::LoadFromBArray() => {
|
||||
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let array = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
let element = self.heap_area.object_area.get_array_element(array, index);
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(element))?;
|
||||
}
|
||||
|
||||
Instruction::LoadConstant(index) => {
|
||||
// TODO: Handle error instead of unwrap
|
||||
match class.pool_entry(index as u16).unwrap() {
|
||||
|
@ -1283,6 +1361,7 @@ impl JVM {
|
|||
Instruction::NewPrimitiveArray(array_type) => {
|
||||
let array_capacity = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
const CHAR: u8 = 5;
|
||||
const BYTE: u8 = 8;
|
||||
let array_ref = match array_type {
|
||||
BYTE => {
|
||||
|
@ -1291,6 +1370,12 @@ impl JVM {
|
|||
array_ref
|
||||
}
|
||||
|
||||
CHAR => {
|
||||
let array_ref = self.heap_area.make_primitive_char_array(array_capacity as usize, &self.class_store);
|
||||
|
||||
array_ref
|
||||
}
|
||||
|
||||
_ => todo!()
|
||||
};
|
||||
|
||||
|
@ -1333,6 +1418,9 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(2.0)))?;
|
||||
}
|
||||
|
||||
Instruction::PushConstIntM1() => {
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(-1)))?;
|
||||
}
|
||||
Instruction::PushConstInt0() => {
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?;
|
||||
}
|
||||
|
@ -1364,6 +1452,7 @@ impl JVM {
|
|||
_ => match wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))? {
|
||||
StackValue::Int(i) => FieldValue::Int(i),
|
||||
StackValue::Reference(r) => FieldValue::Reference(r),
|
||||
StackValue::Float(f) => FieldValue::Float(f),
|
||||
stack_value @ _ => {
|
||||
println!("{stack_value:?}");
|
||||
todo!()
|
||||
|
@ -1511,31 +1600,38 @@ impl JVM {
|
|||
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Reference(value));
|
||||
}
|
||||
|
||||
Instruction::SubtractInt() => {
|
||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 - value_2)))?;
|
||||
}
|
||||
|
||||
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))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Int(int)))?;
|
||||
},
|
||||
}
|
||||
Instruction::StoreLocalInt1() => {
|
||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Int(int)))?;
|
||||
},
|
||||
}
|
||||
Instruction::StoreLocalInt2() => {
|
||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Int(int)))?;
|
||||
},
|
||||
}
|
||||
Instruction::StoreLocalInt3() => {
|
||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Int(int)))?;
|
||||
},
|
||||
}
|
||||
|
||||
Instruction::StoreReference0() => {
|
||||
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
|
|
@ -15,11 +15,13 @@ mod native_methods;
|
|||
//use crate::accessmasks::FieldAccessFlag;
|
||||
//use crate::stackframe::StackValue;
|
||||
//use crate::classfile::JavaClassFile;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
//println!("{:#?}", JavaClassFile::new(&mut File::open("java/lang/System.class").unwrap()).unwrap());
|
||||
|
||||
let mut jvm = jvm::JVM::new();
|
||||
jvm.class_store.class_path_fragments.push(PathBuf::from("./classpath"));
|
||||
|
||||
match jvm.entrypoint(
|
||||
&"Main".to_string(),
|
||||
|
|
|
@ -49,6 +49,8 @@ impl JavaLangClass {
|
|||
};
|
||||
// max_locals: 1
|
||||
// max_stack: 1
|
||||
let class = jvm.class_store.class_file_from_idx(frame.class_index).unwrap();
|
||||
let method = &class.methods[frame.method_index as usize];
|
||||
let class_class_index = jvm.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap();
|
||||
let (string_class_file, string_class_index) = jvm.class_store.get_class(&String::from("java/lang/String")).unwrap();
|
||||
let string_equals_index = string_class_file.find_method_index(&String::from("equals")).unwrap();
|
||||
|
@ -57,7 +59,9 @@ impl JavaLangClass {
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
match frame.instruction_pointer {
|
||||
frame.instruction_pointer += 1;
|
||||
|
||||
match frame.instruction_pointer - 1 {
|
||||
0 => {
|
||||
let boolean_class_ref = jvm.class_store.primitive_classes.boolean_class;
|
||||
let boolean_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||
|
@ -77,10 +81,206 @@ impl JavaLangClass {
|
|||
&[StackValue::Reference(boolean_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||
);
|
||||
|
||||
frame.instruction_pointer += 1;
|
||||
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||
}
|
||||
|
||||
1 => {
|
||||
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||
let boolean_class_ref = jvm.class_store.primitive_classes.boolean_class;
|
||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(boolean_class_ref)))
|
||||
} else {
|
||||
let byte_class_ref = jvm.class_store.primitive_classes.byte_class;
|
||||
let byte_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||
byte_class_ref,
|
||||
"name",
|
||||
class_class_index,
|
||||
&jvm.class_store
|
||||
).unwrap() {
|
||||
FieldValue::Reference(r) => r,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let string_compare_frame = StackFrame::new(
|
||||
string_class_file,
|
||||
string_class_index,
|
||||
string_equals_index as u16,
|
||||
&[StackValue::Reference(byte_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||
);
|
||||
|
||||
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
2 => {
|
||||
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||
let char_class_ref = jvm.class_store.primitive_classes.char_class;
|
||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(char_class_ref)))
|
||||
} else {
|
||||
let char_class_ref = jvm.class_store.primitive_classes.char_class;
|
||||
let char_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||
char_class_ref,
|
||||
"name",
|
||||
class_class_index,
|
||||
&jvm.class_store
|
||||
).unwrap() {
|
||||
FieldValue::Reference(r) => r,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let string_compare_frame = StackFrame::new(
|
||||
string_class_file,
|
||||
string_class_index,
|
||||
string_equals_index as u16,
|
||||
&[StackValue::Reference(char_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||
);
|
||||
|
||||
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||
}
|
||||
}
|
||||
|
||||
3 => {
|
||||
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||
let short_class_ref = jvm.class_store.primitive_classes.short_class;
|
||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(short_class_ref)))
|
||||
} else {
|
||||
let short_class_ref = jvm.class_store.primitive_classes.short_class;
|
||||
let short_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||
short_class_ref,
|
||||
"name",
|
||||
class_class_index,
|
||||
&jvm.class_store
|
||||
).unwrap() {
|
||||
FieldValue::Reference(r) => r,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let string_compare_frame = StackFrame::new(
|
||||
string_class_file,
|
||||
string_class_index,
|
||||
string_equals_index as u16,
|
||||
&[StackValue::Reference(short_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||
);
|
||||
|
||||
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||
}
|
||||
}
|
||||
|
||||
4 => {
|
||||
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||
let int_class_ref = jvm.class_store.primitive_classes.int_class;
|
||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(int_class_ref)))
|
||||
} else {
|
||||
let int_class_ref = jvm.class_store.primitive_classes.int_class;
|
||||
let int_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||
int_class_ref,
|
||||
"name",
|
||||
class_class_index,
|
||||
&jvm.class_store
|
||||
).unwrap() {
|
||||
FieldValue::Reference(r) => r,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let string_compare_frame = StackFrame::new(
|
||||
string_class_file,
|
||||
string_class_index,
|
||||
string_equals_index as u16,
|
||||
&[StackValue::Reference(int_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||
);
|
||||
|
||||
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||
}
|
||||
}
|
||||
|
||||
5 => {
|
||||
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||
let float_class_ref = jvm.class_store.primitive_classes.float_class;
|
||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(float_class_ref)))
|
||||
} else {
|
||||
let float_class_ref = jvm.class_store.primitive_classes.float_class;
|
||||
let float_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||
float_class_ref,
|
||||
"name",
|
||||
class_class_index,
|
||||
&jvm.class_store
|
||||
).unwrap() {
|
||||
FieldValue::Reference(r) => r,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let string_compare_frame = StackFrame::new(
|
||||
string_class_file,
|
||||
string_class_index,
|
||||
string_equals_index as u16,
|
||||
&[StackValue::Reference(float_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||
);
|
||||
|
||||
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||
}
|
||||
}
|
||||
|
||||
6 => {
|
||||
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||
let double_class_ref = jvm.class_store.primitive_classes.double_class;
|
||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(double_class_ref)))
|
||||
} else {
|
||||
let double_class_ref = jvm.class_store.primitive_classes.double_class;
|
||||
let double_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||
double_class_ref,
|
||||
"name",
|
||||
class_class_index,
|
||||
&jvm.class_store
|
||||
).unwrap() {
|
||||
FieldValue::Reference(r) => r,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let string_compare_frame = StackFrame::new(
|
||||
string_class_file,
|
||||
string_class_index,
|
||||
string_equals_index as u16,
|
||||
&[StackValue::Reference(double_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||
);
|
||||
|
||||
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||
}
|
||||
}
|
||||
|
||||
7 => {
|
||||
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||
let long_class_ref = jvm.class_store.primitive_classes.long_class;
|
||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(long_class_ref)))
|
||||
} else {
|
||||
let long_class_ref = jvm.class_store.primitive_classes.long_class;
|
||||
let long_class_name_ref = match jvm.heap_area.object_area.get_object_field(
|
||||
long_class_ref,
|
||||
"name",
|
||||
class_class_index,
|
||||
&jvm.class_store
|
||||
).unwrap() {
|
||||
FieldValue::Reference(r) => r,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let string_compare_frame = StackFrame::new(
|
||||
string_class_file,
|
||||
string_class_index,
|
||||
string_equals_index as u16,
|
||||
&[StackValue::Reference(long_class_name_ref), StackValue::Reference(passed_wanted_string)],
|
||||
);
|
||||
|
||||
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
|
||||
}
|
||||
}
|
||||
|
||||
8 => {
|
||||
if wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? == 1 {
|
||||
let long_class_ref = jvm.class_store.primitive_classes.long_class;
|
||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(long_class_ref)))
|
||||
} else {
|
||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ObjectReference::NULL)))
|
||||
}
|
||||
}
|
||||
_ => Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ObjectReference::NULL)))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue