Implemented Exception Throwing fith specific catchers

This commit is contained in:
VegOwOtenks 2024-11-13 12:14:42 +01:00
parent 796e52241d
commit fc0d11c1e1
8 changed files with 351 additions and 12 deletions

View file

@ -39,6 +39,7 @@ impl Bytecode {
0x15 => (Instruction::LoadLocalInt(self.bytes[offset+1]), 2), 0x15 => (Instruction::LoadLocalInt(self.bytes[offset+1]), 2),
0x16 => (Instruction::LoadLocalLong(self.bytes[offset+1]), 2), 0x16 => (Instruction::LoadLocalLong(self.bytes[offset+1]), 2),
0x17 => (Instruction::LoadLocalFloat(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), 0x19 => (Instruction::LoadLocalReference(self.bytes[offset+1]), 2),
0x1A => (Instruction::LoadLocalInt0(), 1), 0x1A => (Instruction::LoadLocalInt0(), 1),
0x1B => (Instruction::LoadLocalInt1(), 1), 0x1B => (Instruction::LoadLocalInt1(), 1),
@ -66,6 +67,7 @@ impl Bytecode {
0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2), 0x36 => (Instruction::StoreLocalInt(self.bytes[offset+1]), 2),
0x37 => (Instruction::StoreLocalLong(self.bytes[offset+1]), 2), 0x37 => (Instruction::StoreLocalLong(self.bytes[offset+1]), 2),
0x38 => (Instruction::StoreLocalFloat(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), 0x3A => (Instruction::StoreLocalReference(self.bytes[offset+1]), 2),
0x3B => (Instruction::StoreLocalInt0(), 1), 0x3B => (Instruction::StoreLocalInt0(), 1),
0x3C => (Instruction::StoreLocalInt1(), 1), 0x3C => (Instruction::StoreLocalInt1(), 1),
@ -101,6 +103,7 @@ impl Bytecode {
0x6C => (Instruction::DivideInt(), 1), 0x6C => (Instruction::DivideInt(), 1),
0x6D => (Instruction::DivideLong(), 1), 0x6D => (Instruction::DivideLong(), 1),
0x6E => (Instruction::DivideFloat(), 1), 0x6E => (Instruction::DivideFloat(), 1),
0x6F => (Instruction::DivideDouble(), 1),
0x70 => (Instruction::ModuloInt(), 1), 0x70 => (Instruction::ModuloInt(), 1),
0x74 => (Instruction::NegateInt(), 1), 0x74 => (Instruction::NegateInt(), 1),
@ -110,6 +113,7 @@ impl Bytecode {
0x7A => (Instruction::ArithmeticShiftIntRight(), 1), 0x7A => (Instruction::ArithmeticShiftIntRight(), 1),
0x7B => (Instruction::ArithmeticShiftLongRight(), 1), 0x7B => (Instruction::ArithmeticShiftLongRight(), 1),
0x7C => (Instruction::LogicalShiftIntRight(), 1), 0x7C => (Instruction::LogicalShiftIntRight(), 1),
0x7D => (Instruction::LogicalShiftLongRight(), 1),
0x7E => (Instruction::AndInt(), 1), 0x7E => (Instruction::AndInt(), 1),
0x7F => (Instruction::AndLong(), 1), 0x7F => (Instruction::AndLong(), 1),
@ -119,16 +123,20 @@ impl Bytecode {
0x85 => (Instruction::ConvertIntToLong(), 1), 0x85 => (Instruction::ConvertIntToLong(), 1),
0x86 => (Instruction::ConvertIntToFloat(), 1), 0x86 => (Instruction::ConvertIntToFloat(), 1),
0x87 => (Instruction::ConvertIntToDouble(), 1),
0x88 => (Instruction::ConvertLongToInt(), 1), 0x88 => (Instruction::ConvertLongToInt(), 1),
0x89 => (Instruction::ConvertLongToFloat(), 1), 0x89 => (Instruction::ConvertLongToFloat(), 1),
0x8B => (Instruction::ConvertFloatToInt(), 1), 0x8B => (Instruction::ConvertFloatToInt(), 1),
0x8D => (Instruction::ConvertFloatToDouble(), 1), 0x8D => (Instruction::ConvertFloatToDouble(), 1),
0x8E => (Instruction::ConvertDoubleToInt(), 1),
0x8F => (Instruction::ConvertDoubleToLong(), 1), 0x8F => (Instruction::ConvertDoubleToLong(), 1),
0x91 => (Instruction::ConvertIntToByte(), 1), 0x91 => (Instruction::ConvertIntToByte(), 1),
0x92 => (Instruction::ConvertIntToChar(), 1), 0x92 => (Instruction::ConvertIntToChar(), 1),
0x94 => (Instruction::CompareLong(), 1), 0x94 => (Instruction::CompareLong(), 1),
0x95 => (Instruction::CompareFloatL(), 1), 0x95 => (Instruction::CompareFloatL(), 1),
0x96 => (Instruction::CompareFloatG(), 1), 0x96 => (Instruction::CompareFloatG(), 1),
0x97 => (Instruction::CompareDoubleL(), 1),
0x98 => (Instruction::CompareDoubleG(), 1),
0x99 => { 0x99 => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchZero(i16::from_be_bytes(bytes)), 3) (Instruction::BranchZero(i16::from_be_bytes(bytes)), 3)
@ -238,6 +246,7 @@ impl Bytecode {
} }
0xAC => (Instruction::ReturnInt(), 1), 0xAC => (Instruction::ReturnInt(), 1),
0xAD => (Instruction::ReturnLong(), 1), 0xAD => (Instruction::ReturnLong(), 1),
0xAF => (Instruction::ReturnDouble(), 1),
0xB0 => (Instruction::ReturnReference(), 1), 0xB0 => (Instruction::ReturnReference(), 1),
0xB1 => (Instruction::ReturnVoid(), 1), 0xB1 => (Instruction::ReturnVoid(), 1),
@ -326,6 +335,7 @@ pub enum Instruction {
LoadLocalInt(u8) = 0x15, // Load int from indexed local variable LoadLocalInt(u8) = 0x15, // Load int from indexed local variable
LoadLocalLong(u8) = 0x16, // Load long from indexed local variable LoadLocalLong(u8) = 0x16, // Load long from indexed local variable
LoadLocalFloat(u8) = 0x17, // Load float 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 LoadLocalReference(u8) = 0x19, // Load reference from indexed local variable
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
@ -354,6 +364,7 @@ pub enum Instruction {
StoreLocalInt(u8) = 0x36, // store into indexed local variable StoreLocalInt(u8) = 0x36, // store into indexed local variable
StoreLocalLong(u8) = 0x37, // store into indexed local variable StoreLocalLong(u8) = 0x37, // store into indexed local variable
StoreLocalFloat(u8) = 0x38, // 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 StoreLocalReference(u8) = 0x3A, // 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
@ -388,6 +399,7 @@ pub enum Instruction {
DivideInt() = 0x6C, // integer division, round toward zero and more rules DivideInt() = 0x6C, // integer division, round toward zero and more rules
DivideLong() = 0x6D, // long division DivideLong() = 0x6D, // long division
DivideFloat() = 0x6E, // float division DivideFloat() = 0x6E, // float division
DivideDouble() = 0x6F, // double division
ModuloInt() = 0x70, // modulo ModuloInt() = 0x70, // modulo
NegateInt() = 0x74, // arithmetic negation NegateInt() = 0x74, // arithmetic negation
@ -397,6 +409,7 @@ pub enum Instruction {
ArithmeticShiftIntRight() = 0x7A, // shift int right, preserve sign ArithmeticShiftIntRight() = 0x7A, // shift int right, preserve sign
ArithmeticShiftLongRight() = 0x7B, // shift long right, preserve sign ArithmeticShiftLongRight() = 0x7B, // shift long right, preserve sign
LogicalShiftIntRight() = 0x7C, // shift int right with zero extension LogicalShiftIntRight() = 0x7C, // shift int right with zero extension
LogicalShiftLongRight() = 0x7D, // shift long right with zero extension
AndInt() = 0x7E, // bitwise and AndInt() = 0x7E, // bitwise and
AndLong() = 0x7F, // bitwise and AndLong() = 0x7F, // bitwise and
@ -406,16 +419,20 @@ pub enum Instruction {
ConvertIntToLong() = 0x85, // convert int on stack to long ConvertIntToLong() = 0x85, // convert int on stack to long
ConvertIntToFloat() = 0x86, // change data type ConvertIntToFloat() = 0x86, // change data type
ConvertIntToDouble() = 0x87, // change data type
ConvertLongToInt() = 0x88, // change data type ConvertLongToInt() = 0x88, // change data type
ConvertLongToFloat() = 0x89, // change data type ConvertLongToFloat() = 0x89, // change data type
ConvertFloatToInt() = 0x8B, // change data type ConvertFloatToInt() = 0x8B, // change data type
ConvertFloatToDouble() = 0x8D, // change data type ConvertFloatToDouble() = 0x8D, // change data type
ConvertDoubleToInt() = 0x8E, // change data type
ConvertDoubleToLong() = 0x8F, // change data type ConvertDoubleToLong() = 0x8F, // change data type
ConvertIntToByte() = 0x91, // truncate int to 8 bits ConvertIntToByte() = 0x91, // truncate int to 8 bits
ConvertIntToChar() = 0x92, // truncate int to 16 bits ConvertIntToChar() = 0x92, // truncate int to 16 bits
CompareLong() = 0x94, // compare long CompareLong() = 0x94, // compare long
CompareFloatL() = 0x95, // compare float, push -1 if one is NaN CompareFloatL() = 0x95, // compare float, push -1 if one is NaN
CompareFloatG() = 0x96, // 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 BranchZero(i16) = 0x99, // branch if value == 0
BranchNonZero(i16) = 0x9A, // branch if value != 0 BranchNonZero(i16) = 0x9A, // branch if value != 0
BranchNegative(i16) = 0x9B, // 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 LookupSwitch(i32, Box<[(i32, i32)]>) = 0xAB, // jump based on switch value
ReturnInt() = 0xAC, // return integer from function ReturnInt() = 0xAC, // return integer from function
ReturnLong() = 0xAD, // return long from function ReturnLong() = 0xAD, // return long from function
ReturnDouble() = 0xAF, // return double from function
ReturnReference() = 0xB0, // return top-ref from current function ReturnReference() = 0xB0, // return top-ref from current function
ReturnVoid() = 0xB1, // return void from function ReturnVoid() = 0xB1, // return void from function

View file

@ -5,8 +5,10 @@ use core::str::Utf8Error;
use crate::accessmasks::*; use crate::accessmasks::*;
use crate::bytecode::Bytecode; 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::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantInterfaceMethodRefInfo, ConstantStringInfo, ConstantMethodRefInfo, ConstantFloatInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo };
use crate::constantpool::ConstantDoubleInfo; use crate::constantpool::ConstantDoubleInfo;
use crate::heap_area::ObjectReference;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -191,6 +193,15 @@ impl JavaClassFile {
return Ok(&name_entry.utf8); 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> { 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(); let code_attribute = method.get_code_attribute().unwrap();
for exception_entry in &code_attribute.exception_table { for exception_entry in &code_attribute.exception_table {
if exception_entry.start_pc <= instruction_pointer && exception_entry.end_pc > instruction_pointer { if exception_entry.start_pc <= instruction_pointer && exception_entry.end_pc > instruction_pointer {
if exception_entry.catch_type == 0 { if exception_entry.catch_type == 0 {
return true; return Ok(true);
} else { } else {
// Check catch-type // 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)
} }
} }

View file

@ -140,6 +140,13 @@ impl ClassStore {
return Err(Error::ClassNotFoundError(format!("Could not find class '{classname}' in classpath"))); 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 { pub fn are_types_compatible(&self, my_type: &AbstractTypeDescription, other_type: &AbstractTypeDescription) -> bool {
if my_type == other_type { return true; } if my_type == other_type { return true; }
if my_type.array_level != other_type.array_level { return false; } if my_type.array_level != other_type.array_level { return false; }

View file

@ -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 { pub 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),
@ -336,8 +350,8 @@ impl ObjectArea {
CompartmentEntry::ByteArray(_) => true, CompartmentEntry::ByteArray(_) => true,
CompartmentEntry::CharArray(_) => true, CompartmentEntry::CharArray(_) => true,
CompartmentEntry::IntArray(_) => true, CompartmentEntry::IntArray(_) => true,
CompartmentEntry::EmptyNext(_) => true, CompartmentEntry::EmptyNext(_) => unreachable!(),
CompartmentEntry::EmptyTail() => true, CompartmentEntry::EmptyTail() => unreachable!(),
} }
} }
@ -720,7 +734,7 @@ pub struct StaticField {
pub value: FieldValue, pub value: FieldValue,
} }
#[derive(Debug)] #[derive(Debug, Copy, Clone)]
pub struct ObjectField { pub struct ObjectField {
pub value: FieldValue, pub value: FieldValue,
} }

View file

@ -58,7 +58,7 @@ impl <'i>CompatibleTypesIterator<'i> {
} }
impl <'i> Iterator for 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> { fn next(&mut self) -> Option<Self::Item> {
let (class_index, interface_index) = match self.class_stack.pop() { let (class_index, interface_index) = match self.class_stack.pop() {

View file

@ -495,7 +495,8 @@ impl JVM {
if method.is_native() { if method.is_native() {
false false
} else { } 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() => { Instruction::CompareFloatG() => {
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; 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))?; 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)))?; 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() => { Instruction::ConvertDoubleToLong() => {
let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?; let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
let long = match double { let long = match double {
@ -1114,6 +1160,13 @@ impl JVM {
frame.operand_stack.push(StackValue::Int(char_value)).unwrap(); 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() => { Instruction::ConvertIntToFloat() => {
let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let float_value = int_value as f32; 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)))?; 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() => { Instruction::DivideFloat() => {
// TODO: Obey all the rules // TODO: Obey all the rules
let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; 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) => { Instruction::LoadLocalFloat(index) => {
load_local_float(class, method, frame, index as usize)?; 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)))?; 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) => { Instruction::LookupSwitch(default_offset, pairs) => {
let key = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; 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)) { 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)?; 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() => { Instruction::ReturnInt() => {
match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) { match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) {
(_, AbstractTypeKind::Byte() | AbstractTypeKind::Boolean()| AbstractTypeKind::Int() | AbstractTypeKind::Char() | AbstractTypeKind::Short()) => (), (_, 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))?; 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) => { Instruction::StoreLocalFloat(index) => {
let float = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; 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(()) 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> { 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))?; let loaded_value = wrap_stackframe_error(class, method, frame.load_local_float(index as u16))?;

View file

@ -44,6 +44,24 @@ impl EntryPoint {
struct JavaLangClass {} struct JavaLangClass {}
impl 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> { pub fn get_primitive_class(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
let frame = { let frame = {
let frame_index = jvm.stack_frames.len() - 1; 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 {} struct JavaLangRuntime {}
impl JavaLangRuntime { impl JavaLangRuntime {
@ -1136,7 +1229,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
argument_types: Box::new([]), argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()}, 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([]), argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Class"))}, 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([]), argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int()}, 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 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 { for (classname, methodname, methoddescriptor, binding) in native_mappings {

View file

@ -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) -> () { pub fn clear(&mut self) -> () {
self.depth = 0 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> { pub fn load_local_int(&self, index: u16) -> Result<i32, Error> {
let local = self.locals[index as usize]; let local = self.locals[index as usize];
match local { match local {