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),
|
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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
106
src/jvm.rs
106
src/jvm.rs
|
@ -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))?;
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue