Implemented Exception Throwing fith specific catchers
This commit is contained in:
parent
796e52241d
commit
fc0d11c1e1
8 changed files with 351 additions and 12 deletions
|
@ -39,6 +39,7 @@ impl Bytecode {
|
|||
0x15 => (Instruction::LoadLocalInt(self.bytes[offset+1]), 2),
|
||||
0x16 => (Instruction::LoadLocalLong(self.bytes[offset+1]), 2),
|
||||
0x17 => (Instruction::LoadLocalFloat(self.bytes[offset+1]), 2),
|
||||
0x18 => (Instruction::LoadLocalDouble(self.bytes[offset+1]), 2),
|
||||
0x19 => (Instruction::LoadLocalReference(self.bytes[offset+1]), 2),
|
||||
0x1A => (Instruction::LoadLocalInt0(), 1),
|
||||
0x1B => (Instruction::LoadLocalInt1(), 1),
|
||||
|
@ -66,6 +67,7 @@ impl Bytecode {
|
|||
0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2),
|
||||
0x37 => (Instruction::StoreLocalLong(self.bytes[offset+1]), 2),
|
||||
0x38 => (Instruction::StoreLocalFloat(self.bytes[offset+1]), 2),
|
||||
0x39 => (Instruction::StoreLocalDouble(self.bytes[offset+1]), 2),
|
||||
0x3A => (Instruction::StoreLocalReference(self.bytes[offset+1]), 2),
|
||||
0x3B => (Instruction::StoreLocalInt0(), 1),
|
||||
0x3C => (Instruction::StoreLocalInt1(), 1),
|
||||
|
@ -101,6 +103,7 @@ impl Bytecode {
|
|||
0x6C => (Instruction::DivideInt(), 1),
|
||||
0x6D => (Instruction::DivideLong(), 1),
|
||||
0x6E => (Instruction::DivideFloat(), 1),
|
||||
0x6F => (Instruction::DivideDouble(), 1),
|
||||
|
||||
0x70 => (Instruction::ModuloInt(), 1),
|
||||
0x74 => (Instruction::NegateInt(), 1),
|
||||
|
@ -110,6 +113,7 @@ impl Bytecode {
|
|||
0x7A => (Instruction::ArithmeticShiftIntRight(), 1),
|
||||
0x7B => (Instruction::ArithmeticShiftLongRight(), 1),
|
||||
0x7C => (Instruction::LogicalShiftIntRight(), 1),
|
||||
0x7D => (Instruction::LogicalShiftLongRight(), 1),
|
||||
0x7E => (Instruction::AndInt(), 1),
|
||||
0x7F => (Instruction::AndLong(), 1),
|
||||
|
||||
|
@ -119,16 +123,20 @@ impl Bytecode {
|
|||
0x85 => (Instruction::ConvertIntToLong(), 1),
|
||||
|
||||
0x86 => (Instruction::ConvertIntToFloat(), 1),
|
||||
0x87 => (Instruction::ConvertIntToDouble(), 1),
|
||||
0x88 => (Instruction::ConvertLongToInt(), 1),
|
||||
0x89 => (Instruction::ConvertLongToFloat(), 1),
|
||||
0x8B => (Instruction::ConvertFloatToInt(), 1),
|
||||
0x8D => (Instruction::ConvertFloatToDouble(), 1),
|
||||
0x8E => (Instruction::ConvertDoubleToInt(), 1),
|
||||
0x8F => (Instruction::ConvertDoubleToLong(), 1),
|
||||
0x91 => (Instruction::ConvertIntToByte(), 1),
|
||||
0x92 => (Instruction::ConvertIntToChar(), 1),
|
||||
0x94 => (Instruction::CompareLong(), 1),
|
||||
0x95 => (Instruction::CompareFloatL(), 1),
|
||||
0x96 => (Instruction::CompareFloatG(), 1),
|
||||
0x97 => (Instruction::CompareDoubleL(), 1),
|
||||
0x98 => (Instruction::CompareDoubleG(), 1),
|
||||
0x99 => {
|
||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||
(Instruction::BranchZero(i16::from_be_bytes(bytes)), 3)
|
||||
|
@ -238,6 +246,7 @@ impl Bytecode {
|
|||
}
|
||||
0xAC => (Instruction::ReturnInt(), 1),
|
||||
0xAD => (Instruction::ReturnLong(), 1),
|
||||
0xAF => (Instruction::ReturnDouble(), 1),
|
||||
|
||||
0xB0 => (Instruction::ReturnReference(), 1),
|
||||
0xB1 => (Instruction::ReturnVoid(), 1),
|
||||
|
@ -326,6 +335,7 @@ pub enum Instruction {
|
|||
LoadLocalInt(u8) = 0x15, // Load int from indexed local variable
|
||||
LoadLocalLong(u8) = 0x16, // Load long from indexed local variable
|
||||
LoadLocalFloat(u8) = 0x17, // Load float from indexed local variable
|
||||
LoadLocalDouble(u8) = 0x18, // Load double from indexed local variable
|
||||
LoadLocalReference(u8) = 0x19, // Load reference from indexed local variable
|
||||
LoadLocalInt0() = 0x1A, // Load int from local variable
|
||||
LoadLocalInt1() = 0x1B, // Load int from local variable
|
||||
|
@ -354,6 +364,7 @@ pub enum Instruction {
|
|||
StoreLocalInt(u8) = 0x36, // store into indexed local variable
|
||||
StoreLocalLong(u8) = 0x37, // store into indexed local variable
|
||||
StoreLocalFloat(u8) = 0x38, // store into indexed local variable
|
||||
StoreLocalDouble(u8) = 0x39, // store into indexed local variable
|
||||
StoreLocalReference(u8) = 0x3A, // store into indexed local variable
|
||||
StoreLocalInt0() = 0x3B, // store int into local variable
|
||||
StoreLocalInt1() = 0x3C, // store int into local variable
|
||||
|
@ -388,6 +399,7 @@ pub enum Instruction {
|
|||
DivideInt() = 0x6C, // integer division, round toward zero and more rules
|
||||
DivideLong() = 0x6D, // long division
|
||||
DivideFloat() = 0x6E, // float division
|
||||
DivideDouble() = 0x6F, // double division
|
||||
|
||||
ModuloInt() = 0x70, // modulo
|
||||
NegateInt() = 0x74, // arithmetic negation
|
||||
|
@ -397,6 +409,7 @@ pub enum Instruction {
|
|||
ArithmeticShiftIntRight() = 0x7A, // shift int right, preserve sign
|
||||
ArithmeticShiftLongRight() = 0x7B, // shift long right, preserve sign
|
||||
LogicalShiftIntRight() = 0x7C, // shift int right with zero extension
|
||||
LogicalShiftLongRight() = 0x7D, // shift long right with zero extension
|
||||
AndInt() = 0x7E, // bitwise and
|
||||
AndLong() = 0x7F, // bitwise and
|
||||
|
||||
|
@ -406,16 +419,20 @@ pub enum Instruction {
|
|||
ConvertIntToLong() = 0x85, // convert int on stack to long
|
||||
|
||||
ConvertIntToFloat() = 0x86, // change data type
|
||||
ConvertIntToDouble() = 0x87, // change data type
|
||||
ConvertLongToInt() = 0x88, // change data type
|
||||
ConvertLongToFloat() = 0x89, // change data type
|
||||
ConvertFloatToInt() = 0x8B, // change data type
|
||||
ConvertFloatToDouble() = 0x8D, // change data type
|
||||
ConvertDoubleToInt() = 0x8E, // change data type
|
||||
ConvertDoubleToLong() = 0x8F, // change data type
|
||||
ConvertIntToByte() = 0x91, // truncate int to 8 bits
|
||||
ConvertIntToChar() = 0x92, // truncate int to 16 bits
|
||||
CompareLong() = 0x94, // compare long
|
||||
CompareFloatL() = 0x95, // compare float, push -1 if one is NaN
|
||||
CompareFloatG() = 0x96, // compare float, push 1 if one is NaN
|
||||
CompareDoubleL() = 0x97, // compare float, push -1 if one is NaN
|
||||
CompareDoubleG() = 0x98, // compare float, push 1 if one is NaN
|
||||
BranchZero(i16) = 0x99, // branch if value == 0
|
||||
BranchNonZero(i16) = 0x9A, // branch if value != 0
|
||||
BranchNegative(i16) = 0x9B, // branch if value < 0
|
||||
|
@ -437,6 +454,7 @@ pub enum Instruction {
|
|||
LookupSwitch(i32, Box<[(i32, i32)]>) = 0xAB, // jump based on switch value
|
||||
ReturnInt() = 0xAC, // return integer from function
|
||||
ReturnLong() = 0xAD, // return long from function
|
||||
ReturnDouble() = 0xAF, // return double from function
|
||||
|
||||
ReturnReference() = 0xB0, // return top-ref from current function
|
||||
ReturnVoid() = 0xB1, // return void from function
|
||||
|
|
|
@ -5,8 +5,10 @@ use core::str::Utf8Error;
|
|||
|
||||
use crate::accessmasks::*;
|
||||
use crate::bytecode::Bytecode;
|
||||
use crate::classstore::ClassStore;
|
||||
use crate::constantpool::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantInterfaceMethodRefInfo, ConstantStringInfo, ConstantMethodRefInfo, ConstantFloatInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo };
|
||||
use crate::constantpool::ConstantDoubleInfo;
|
||||
use crate::heap_area::ObjectReference;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
@ -191,6 +193,15 @@ impl JavaClassFile {
|
|||
return Ok(&name_entry.utf8);
|
||||
}
|
||||
|
||||
pub fn resolve_method_index(&self, name: &str, descriptor: &str) -> Option<u16> {
|
||||
for (index, method_info) in (&self.methods).into_iter().enumerate() {
|
||||
if method_info.name == *name && method_info.descriptor == (&descriptor.to_string()).try_into().unwrap() {
|
||||
return Some(index as u16);
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn find_method_index(&self, name: &String) -> Option<usize> {
|
||||
|
||||
|
@ -401,21 +412,22 @@ impl JavaClassFile {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_method_bytecode_protected(&self, method: &MethodInfo, instruction_pointer: u16, exception: crate::heap_area::ObjectReference) -> bool {
|
||||
pub fn is_method_bytecode_protected(&self, method: &MethodInfo, instruction_pointer: u16, exception_class_index: usize, class_store: &ClassStore) -> Result<bool, Error> {
|
||||
let code_attribute = method.get_code_attribute().unwrap();
|
||||
|
||||
for exception_entry in &code_attribute.exception_table {
|
||||
if exception_entry.start_pc <= instruction_pointer && exception_entry.end_pc > instruction_pointer {
|
||||
if exception_entry.catch_type == 0 {
|
||||
return true;
|
||||
return Ok(true);
|
||||
} else {
|
||||
// Check catch-type
|
||||
todo!()
|
||||
let catch_type_name = self.gather_class(exception_entry.catch_type);
|
||||
return Ok(class_store.are_types_compatible_0(exception_class_index, catch_type_name?));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,13 @@ impl ClassStore {
|
|||
return Err(Error::ClassNotFoundError(format!("Could not find class '{classname}' in classpath")));
|
||||
}
|
||||
|
||||
pub fn are_types_compatible_0(&self, my_index: usize, other_name: &str) -> bool {
|
||||
CompatibleTypesIterator::new(my_index, self)
|
||||
.filter(|type_name| *type_name == other_name)
|
||||
.next()
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn are_types_compatible(&self, my_type: &AbstractTypeDescription, other_type: &AbstractTypeDescription) -> bool {
|
||||
if my_type == other_type { return true; }
|
||||
if my_type.array_level != other_type.array_level { return false; }
|
||||
|
|
|
@ -280,6 +280,20 @@ impl ObjectArea {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_object_field_count(&self, reference: ObjectReference) -> usize {
|
||||
match self.get_entry(reference) {
|
||||
CompartmentEntry::Object(o) => o.fields.len(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_object_field_at(&self, reference: ObjectReference, index: usize) -> ObjectField {
|
||||
match self.get_entry(reference) {
|
||||
CompartmentEntry::Object(o) => o.fields[index],
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub 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),
|
||||
|
@ -336,8 +350,8 @@ impl ObjectArea {
|
|||
CompartmentEntry::ByteArray(_) => true,
|
||||
CompartmentEntry::CharArray(_) => true,
|
||||
CompartmentEntry::IntArray(_) => true,
|
||||
CompartmentEntry::EmptyNext(_) => true,
|
||||
CompartmentEntry::EmptyTail() => true,
|
||||
CompartmentEntry::EmptyNext(_) => unreachable!(),
|
||||
CompartmentEntry::EmptyTail() => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -720,7 +734,7 @@ pub struct StaticField {
|
|||
pub value: FieldValue,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ObjectField {
|
||||
pub value: FieldValue,
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ impl <'i>CompatibleTypesIterator<'i> {
|
|||
}
|
||||
|
||||
impl <'i> Iterator for CompatibleTypesIterator<'i>{
|
||||
type Item = &'i String; // class index, method index, method info
|
||||
type Item = &'i String;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let (class_index, interface_index) = match self.class_stack.pop() {
|
||||
|
|
106
src/jvm.rs
106
src/jvm.rs
|
@ -495,7 +495,8 @@ impl JVM {
|
|||
if method.is_native() {
|
||||
false
|
||||
} else {
|
||||
class.is_method_bytecode_protected(method, frame.instruction_pointer as u16, exception)
|
||||
let exception_type_index = self.heap_area.object_area.get_object_class_index(exception);
|
||||
class.is_method_bytecode_protected(method, frame.instruction_pointer as u16, exception_type_index, &self.class_store)?
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1023,6 +1024,40 @@ impl JVM {
|
|||
|
||||
}
|
||||
|
||||
Instruction::CompareDoubleG() => {
|
||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
|
||||
let comparison_result = if value_1.is_nan() || value_2.is_nan() {
|
||||
1
|
||||
} else if value_1 == value_2 {
|
||||
0
|
||||
} else if value_1 < value_2 {
|
||||
-1
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(comparison_result)))?;
|
||||
}
|
||||
|
||||
Instruction::CompareDoubleL() => {
|
||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
|
||||
let comparison_result = if value_1.is_nan() || value_2.is_nan() {
|
||||
-1
|
||||
} else if value_1 == value_2 {
|
||||
0
|
||||
} else if value_1 < value_2 {
|
||||
-1
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(comparison_result)))?;
|
||||
}
|
||||
|
||||
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))?;
|
||||
|
@ -1089,6 +1124,17 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?;
|
||||
}
|
||||
|
||||
Instruction::ConvertDoubleToInt() => {
|
||||
let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
let int_value = match double {
|
||||
f64::INFINITY => i32::MAX,
|
||||
f64::NEG_INFINITY => i32::MIN,
|
||||
v @ _ => if v.is_nan() { 0 } else { v as i32 } ,
|
||||
};
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?;
|
||||
}
|
||||
|
||||
Instruction::ConvertDoubleToLong() => {
|
||||
let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
let long = match double {
|
||||
|
@ -1114,6 +1160,13 @@ impl JVM {
|
|||
frame.operand_stack.push(StackValue::Int(char_value)).unwrap();
|
||||
}
|
||||
|
||||
Instruction::ConvertIntToDouble() => {
|
||||
let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let double_value = int_value as f64;
|
||||
|
||||
frame.operand_stack.push_double(double_value).unwrap();
|
||||
}
|
||||
|
||||
Instruction::ConvertIntToFloat() => {
|
||||
let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let float_value = int_value as f32;
|
||||
|
@ -1142,6 +1195,14 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(float_value)))?;
|
||||
}
|
||||
|
||||
Instruction::DivideDouble() => {
|
||||
// TODO: Obey all the rules
|
||||
let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
let divident = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
|
||||
frame.operand_stack.push_double(divident / quotient).unwrap();
|
||||
}
|
||||
|
||||
Instruction::DivideFloat() => {
|
||||
// TODO: Obey all the rules
|
||||
let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
||||
|
@ -1733,6 +1794,14 @@ impl JVM {
|
|||
}
|
||||
}
|
||||
|
||||
Instruction::LoadLocalDouble(index) => {
|
||||
load_local_double(class, method, frame, index as usize)?;
|
||||
}
|
||||
|
||||
Instruction::LoadLocalDouble0() => {
|
||||
load_local_double(class, method, frame, 0)?;
|
||||
}
|
||||
|
||||
Instruction::LoadLocalFloat(index) => {
|
||||
load_local_float(class, method, frame, index as usize)?;
|
||||
}
|
||||
|
@ -1813,6 +1882,16 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(i_result)))?;
|
||||
}
|
||||
|
||||
Instruction::LogicalShiftLongRight() => {
|
||||
let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 & 0b00111111;
|
||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?;
|
||||
let uint = u64::from_ne_bytes(int.to_ne_bytes());
|
||||
let u_result = uint >> shift;
|
||||
let i_result = i64::from_ne_bytes(u_result.to_ne_bytes());
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_long(i_result))?;
|
||||
}
|
||||
|
||||
Instruction::LookupSwitch(default_offset, pairs) => {
|
||||
let key = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
let jump_offset = match pairs.binary_search_by(|(match_key, _offset)| match_key.cmp(&key)) {
|
||||
|
@ -2156,6 +2235,17 @@ impl JVM {
|
|||
self.heap_area.static_area.set(target_class_name, target_field_name, set_value)?;
|
||||
}
|
||||
|
||||
Instruction::ReturnDouble() => {
|
||||
match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) {
|
||||
(0, AbstractTypeKind::Double()) => (),
|
||||
_ => return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type)))
|
||||
}
|
||||
|
||||
let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
|
||||
return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Double(double)));
|
||||
}
|
||||
|
||||
Instruction::ReturnInt() => {
|
||||
match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) {
|
||||
(_, AbstractTypeKind::Byte() | AbstractTypeKind::Boolean()| AbstractTypeKind::Int() | AbstractTypeKind::Char() | AbstractTypeKind::Short()) => (),
|
||||
|
@ -2265,6 +2355,12 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push_long(value_1 - value_2))?;
|
||||
}
|
||||
|
||||
Instruction::StoreLocalDouble(index) => {
|
||||
let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.store_local_double(index as u16, double))?;
|
||||
}
|
||||
|
||||
Instruction::StoreLocalFloat(index) => {
|
||||
let float = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
||||
|
||||
|
@ -2420,6 +2516,14 @@ fn load_local_reference(class: &JavaClassFile, method: &MethodInfo, frame: &mut
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn load_local_double(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {
|
||||
let loaded_value = wrap_stackframe_error(class, method, frame.load_local_double(index as u16))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_double(loaded_value))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_local_float(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {
|
||||
let loaded_value = wrap_stackframe_error(class, method, frame.load_local_float(index as u16))?;
|
||||
|
||||
|
|
|
@ -44,6 +44,24 @@ impl EntryPoint {
|
|||
struct JavaLangClass {}
|
||||
|
||||
impl JavaLangClass {
|
||||
|
||||
fn is_array(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
let frame = {
|
||||
let frame_index = jvm.stack_frames.len() - 1;
|
||||
&mut jvm.stack_frames[frame_index]
|
||||
};
|
||||
let this = frame.load_local_reference(0).unwrap();
|
||||
let class_class_index = jvm.heap_area.object_area.get_object_class_index(this);
|
||||
|
||||
let component_type = jvm.heap_area.object_area.get_object_field(
|
||||
this,
|
||||
"componentType",
|
||||
class_class_index,
|
||||
&jvm.class_store,
|
||||
)?;
|
||||
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Boolean(component_type.expect_reference() == ObjectReference::NULL)))
|
||||
}
|
||||
|
||||
pub fn get_primitive_class(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
let frame = {
|
||||
let frame_index = jvm.stack_frames.len() - 1;
|
||||
|
@ -330,6 +348,81 @@ impl JavaLangDouble {
|
|||
}
|
||||
}
|
||||
|
||||
struct JavaLangObject {}
|
||||
|
||||
impl JavaLangObject {
|
||||
|
||||
fn get_class(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
let frame = {
|
||||
let frame_index = jvm.stack_frames.len() - 1;
|
||||
&mut jvm.stack_frames[frame_index]
|
||||
};
|
||||
let this = frame.load_local_reference(0).unwrap();
|
||||
|
||||
let class_reference = jvm.heap_area.object_area.get_reference_class_ref(this, &jvm.class_store);
|
||||
|
||||
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Reference(class_reference)))
|
||||
}
|
||||
|
||||
fn hashcode(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
let frame = {
|
||||
let frame_index = jvm.stack_frames.len() - 1;
|
||||
&mut jvm.stack_frames[frame_index]
|
||||
};
|
||||
if frame.operand_stack.capacity() == 1 {
|
||||
frame.operand_stack.grow(2);
|
||||
frame.operand_stack.push(StackValue::Int(91)).unwrap();
|
||||
} else {
|
||||
let new_hashcode_part = frame.operand_stack.pop_int(0).unwrap();
|
||||
let old_hashcode_part = frame.operand_stack.pop_int(0).unwrap();
|
||||
let combined_hashcode = old_hashcode_part.wrapping_mul(37).wrapping_add(new_hashcode_part);
|
||||
frame.operand_stack.push(StackValue::Int(combined_hashcode)).unwrap();
|
||||
}
|
||||
|
||||
let this = frame.load_local_reference(0).unwrap();
|
||||
let this_pointer = &this as *const _;
|
||||
|
||||
return Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(this_pointer as i32)))
|
||||
|
||||
//let this_field_count = jvm.heap_area.object_area.get_object_field_count(this);
|
||||
|
||||
//Ok(if this_field_count > frame.instruction_pointer as usize {
|
||||
// let current_field = jvm.heap_area.object_area.get_object_field_at(this, frame.instruction_pointer as usize);
|
||||
// let caller_frame = match current_field.value {
|
||||
// FieldValue::Boolean(b) => {
|
||||
// // TODO: Maybe load the class
|
||||
// let (boolean_class_file, boolean_class_index) = jvm.class_store.get_class(&String::from("java/lang/Boolean")).unwrap();
|
||||
// StackFrame::new(
|
||||
// boolean_class_file,
|
||||
// boolean_class_index,
|
||||
// boolean_class_file.resolve_method_index("hashCode", "(Z)I").unwrap(),
|
||||
// &[StackValue::Boolean(b)]
|
||||
// )
|
||||
// },
|
||||
// FieldValue::Byte(_) => todo!(),
|
||||
// FieldValue::Char(_) => todo!(),
|
||||
// FieldValue::Short(_) => todo!(),
|
||||
// FieldValue::Int(_) => todo!(),
|
||||
// FieldValue::Float(_) => todo!(),
|
||||
// FieldValue::Reference(r) => {
|
||||
// if jvm.heap_area.object_area.is_array_reference(r) {
|
||||
|
||||
// } else {
|
||||
|
||||
// }
|
||||
// },
|
||||
// FieldValue::Double(_) => todo!(),
|
||||
// FieldValue::Long(_) => todo!(),
|
||||
// };
|
||||
|
||||
// JVMCallbackOperation::PushFrame(caller_frame)
|
||||
//} else {
|
||||
// let hashcode = frame.operand_stack.pop_int(0).unwrap();
|
||||
// JVMCallbackOperation::ReturnFrame(FieldValue::Int(hashcode))
|
||||
//})
|
||||
}
|
||||
}
|
||||
|
||||
struct JavaLangRuntime {}
|
||||
|
||||
impl JavaLangRuntime {
|
||||
|
@ -1136,7 +1229,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
|||
argument_types: Box::new([]),
|
||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()},
|
||||
},
|
||||
todo_call
|
||||
JavaLangClass::is_array
|
||||
),
|
||||
|
||||
(
|
||||
|
@ -1299,7 +1392,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
|||
argument_types: Box::new([]),
|
||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Class"))},
|
||||
},
|
||||
todo_call
|
||||
JavaLangObject::get_class
|
||||
),
|
||||
|
||||
(
|
||||
|
@ -1309,7 +1402,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
|||
argument_types: Box::new([]),
|
||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int()},
|
||||
},
|
||||
todo_call
|
||||
JavaLangObject::hashcode
|
||||
),
|
||||
|
||||
(
|
||||
|
@ -3435,6 +3528,75 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
|||
},
|
||||
todo_call
|
||||
),
|
||||
|
||||
(
|
||||
"java/lang/Module",
|
||||
"defineModule0",
|
||||
MethodDescriptor {
|
||||
argument_types: Box::new([
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())},
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()},
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())},
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())},
|
||||
AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string())},
|
||||
]),
|
||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
||||
},
|
||||
todo_call
|
||||
),
|
||||
|
||||
(
|
||||
"java/lang/Module",
|
||||
"addReads0",
|
||||
MethodDescriptor {
|
||||
argument_types: Box::new([
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())},
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())},
|
||||
]),
|
||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
||||
},
|
||||
todo_call
|
||||
),
|
||||
|
||||
(
|
||||
"java/lang/Module",
|
||||
"addExports0",
|
||||
MethodDescriptor {
|
||||
argument_types: Box::new([
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())},
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())},
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())},
|
||||
]),
|
||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
||||
},
|
||||
todo_call
|
||||
),
|
||||
|
||||
(
|
||||
"java/lang/Module",
|
||||
"addExportsToAll0",
|
||||
MethodDescriptor {
|
||||
argument_types: Box::new([
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())},
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())},
|
||||
]),
|
||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
||||
},
|
||||
todo_call
|
||||
),
|
||||
|
||||
(
|
||||
"java/lang/Module",
|
||||
"addExportsToAllUnnamed0",
|
||||
MethodDescriptor {
|
||||
argument_types: Box::new([
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Module".to_string())},
|
||||
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string())},
|
||||
]),
|
||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
||||
},
|
||||
todo_call
|
||||
),
|
||||
];
|
||||
|
||||
for (classname, methodname, methoddescriptor, binding) in native_mappings {
|
||||
|
|
|
@ -47,6 +47,14 @@ impl OperandStack {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.stack.len()
|
||||
}
|
||||
|
||||
pub fn grow(&mut self, new_size: usize) {
|
||||
self.stack = vec![StackValue::Empty(); new_size].into_boxed_slice()
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) -> () {
|
||||
self.depth = 0
|
||||
}
|
||||
|
@ -408,6 +416,20 @@ impl StackFrame {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn store_local_double(&mut self, index: u16, double: f64) -> Result<(), Error> {
|
||||
let field0 = self.locals.get(index as usize);
|
||||
let field1 = self.locals.get((index + 1) as usize);
|
||||
|
||||
match (field0, field1) {
|
||||
(Some(_), Some(_)) => {
|
||||
self.locals[index as usize] = StackValue::Double0(double);
|
||||
self.locals[(index + 1) as usize] = StackValue::Double1();
|
||||
Ok(())
|
||||
},
|
||||
_ => Err(Error::LocalError(format!("Tried to set local at indices {} and {} when max_locals is {}.", index, index+1, self.locals.len())))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_local_int(&self, index: u16) -> Result<i32, Error> {
|
||||
let local = self.locals[index as usize];
|
||||
match local {
|
||||
|
|
Loading…
Reference in a new issue