Compare commits

...

2 commits

Author SHA1 Message Date
6610b09c16 Int Branching instructions 2024-09-10 01:33:35 +02:00
ede316cec3 Int Branching instructions 2024-09-10 00:23:53 +02:00
4 changed files with 304 additions and 87 deletions

View file

@ -19,6 +19,9 @@ impl Bytecode {
0x06 => (Instruction::PushConstInt3(), 1),
0x07 => (Instruction::PushConstInt4(), 1),
0x08 => (Instruction::PushConstInt5(), 1),
0x0B => (Instruction::PushConstFloat0(), 1),
0x0C => (Instruction::PushConstFloat1(), 1),
0x0D => (Instruction::PushConstFloat2(), 1),
0x0E => (Instruction::PushConstDouble0(), 1),
0x0F => (Instruction::PushConstDouble1(), 1),
@ -32,6 +35,10 @@ impl Bytecode {
0x1B => (Instruction::LoadLocalInt1(), 1),
0x1C => (Instruction::LoadLocalInt2(), 1),
0x1D => (Instruction::LoadLocalInt3(), 1),
0x22 => (Instruction::LoadLocalFloat0(), 1),
0x23 => (Instruction::LoadLocalFloat1(), 1),
0x24 => (Instruction::LoadLocalFloat2(), 1),
0x25 => (Instruction::LoadLocalFloat3(), 1),
0x26 => (Instruction::LoadLocalDouble0(), 1),
0x27 => (Instruction::LoadLocalDouble1(), 1),
0x28 => (Instruction::LoadLocalDouble2(), 1),
@ -67,6 +74,8 @@ impl Bytecode {
0x80 => (Instruction::OrInt(), 1),
0x95 => (Instruction::CompareFloatL(), 1),
0x96 => (Instruction::CompareFloatG(), 1),
0x99 => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchZero(i16::from_be_bytes(bytes)), 3)
@ -116,6 +125,14 @@ impl Bytecode {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchIntLessEquals(i16::from_be_bytes(bytes)), 3)
}
0xA5 => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchReferenceEquality(i16::from_be_bytes(bytes)), 3)
}
0xA6 => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchReferenceInequality(i16::from_be_bytes(bytes)), 3)
}
0xAC => (Instruction::ReturnInt(), 1),
0xA7 => {
@ -138,6 +155,7 @@ impl Bytecode {
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0xBE => (Instruction::ArrayLength(), 1),
0xC1 => (Instruction::InstanceOf((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0xC2 => (Instruction::EnterMonitor(), 1),
0xC3 => (Instruction::ExitMonitor(), 1),
@ -180,99 +198,111 @@ impl Debug for Bytecode {
#[derive(Debug)]
#[repr(u8)]
pub enum Instruction {
NoOperation() = 0x00, // No-Operation
PushNull() = 0x01, // ..., arrayref, index, value
PushConstIntM1() = 0x02, // Push -1
PushConstInt0() = 0x03, // Push 0
PushConstInt1() = 0x04, // Push 1
PushConstInt2() = 0x05, // Push 2
PushConstInt3() = 0x06, // Push 3
PushConstInt4() = 0x07, // Push 4
PushConstInt5() = 0x08, // Push 5
PushConstDouble0() = 0x0E, // Push 0.0
PushConstDouble1() = 0x0F, // Push 1.0
NoOperation() = 0x00, // No-Operation
PushNull() = 0x01, // ..., arrayref, index, value
PushConstIntM1() = 0x02, // Push -1
PushConstInt0() = 0x03, // Push 0
PushConstInt1() = 0x04, // Push 1
PushConstInt2() = 0x05, // Push 2
PushConstInt3() = 0x06, // Push 3
PushConstInt4() = 0x07, // Push 4
PushConstInt5() = 0x08, // Push 5
PushConstFloat0() = 0x0B, // Push 0.0f
PushConstFloat1() = 0x0C, // Push 1.0f
PushConstFloat2() = 0x0D, // Push 2.0f
PushConstDouble0() = 0x0E, // Push 0.0
PushConstDouble1() = 0x0F, // Push 1.0
LoadByteImmediate(u8) = 0x10, // push immediate short
LoadShortImmediate(u16) = 0x11, // push immediate short
LoadConstant(u8) = 0x12, // Push from constant pool
LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load
// double or long or whatever
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
LoadLocalInt0() = 0x1A, // Load int from local variable
LoadLocalInt1() = 0x1B, // Load int from local variable
LoadLocalInt2() = 0x1C, // Load int from local variable
LoadLocalInt3() = 0x1D, // Load int from local variable
LoadByteImmediate(u8) = 0x10, // push immediate short
LoadShortImmediate(u16) = 0x11, // push immediate short
LoadConstant(u8) = 0x12, // Push from constant pool
LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load
// double or long or whatever
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
LoadLocalInt0() = 0x1A, // Load int from local variable
LoadLocalInt1() = 0x1B, // Load int from local variable
LoadLocalInt2() = 0x1C, // Load int from local variable
LoadLocalInt3() = 0x1D, // Load int from local variable
LoadLocalDouble0() = 0x26, // Load local double variable reference onto stack
LoadLocalDouble1() = 0x27, // Load local double variable reference onto stack
LoadLocalDouble2() = 0x28, // Load local double variable reference onto stack
LoadLocalDouble3() = 0x29, // Load local double variable reference onto stack
LoadLocalReference0() = 0x2A, // Load local reference variable reference onto stack
LoadLocalReference1() = 0x2B, // Load local reference variable reference onto stack
LoadLocalReference2() = 0x2C, // Load local reference variable reference onto stack
LoadLocalReference3() = 0x2D, // Load local reference variable reference onto stack
LoadLocalFloat0() = 0x22, // Load local double variable reference onto stack
LoadLocalFloat1() = 0x23, // Load local double variable reference onto stack
LoadLocalFloat2() = 0x24, // Load local double variable reference onto stack
LoadLocalFloat3() = 0x25, // Load local double variable reference onto stack
LoadLocalDouble0() = 0x26, // Load local double variable reference onto stack
LoadLocalDouble1() = 0x27, // Load local double variable reference onto stack
LoadLocalDouble2() = 0x28, // Load local double variable reference onto stack
LoadLocalDouble3() = 0x29, // Load local double variable reference onto stack
LoadLocalReference0() = 0x2A, // Load local reference variable reference onto stack
LoadLocalReference1() = 0x2B, // Load local reference variable reference onto stack
LoadLocalReference2() = 0x2C, // Load local reference variable reference onto stack
LoadLocalReference3() = 0x2D, // Load local reference variable reference onto stack
ArrayElement() = 0x32, // load element from array
StoreLocalInt(u8) = 0x36, // store into indexed local variable
StoreLocalInt0() = 0x3B, // store int into local variable
StoreLocalInt1() = 0x3C, // store int into local variable
StoreLocalInt2() = 0x3D, // store int into local variable
StoreLocalInt3() = 0x3E, // store int into local variable
StoreReference0() = 0x4B, // store reference into local variable
StoreReference1() = 0x4C, // store reference into local variable
StoreReference2() = 0x4D, // store reference into local variable
StoreReference3() = 0x4E, // store reference into local variable
ArrayElement() = 0x32, // load element from array
StoreLocalInt(u8) = 0x36, // store into indexed local variable
StoreLocalInt0() = 0x3B, // store int into local variable
StoreLocalInt1() = 0x3C, // store int into local variable
StoreLocalInt2() = 0x3D, // store int into local variable
StoreLocalInt3() = 0x3E, // store int into local variable
StoreReference0() = 0x4B, // store reference into local variable
StoreReference1() = 0x4C, // store reference into local variable
StoreReference2() = 0x4D, // store reference into local variable
StoreReference3() = 0x4E, // store reference into local variable
StoreIntoRArray() = 0x53, // store value into reference array
StoreIntoBArray() = 0x54, // store value into byte or boolean array
Pop() = 0x57, // Pop top stack value
Duplicate() = 0x59, // duplicate top stack value
StoreIntoRArray() = 0x53, // store value into reference array
StoreIntoBArray() = 0x54, // store value into byte or boolean array
Pop() = 0x57, // Pop top stack value
Duplicate() = 0x59, // duplicate top stack value
AddInt() = 0x60, // int addition
MultiplyInt() = 0x68, // int multiplication
DivideInt() = 0x6C, // integer division, round toward zero and more rules
DivideLong() = 0x6D, // long division
AddInt() = 0x60, // int addition
MultiplyInt() = 0x68, // int multiplication
DivideInt() = 0x6C, // integer division, round toward zero and more rules
DivideLong() = 0x6D, // long division
ShiftIntRight() = 0x7a, // shift int
ShiftIntRight() = 0x7a, // shift int
OrInt() = 0x80, // value, value => or
OrInt() = 0x80, // value, value => or
BranchZero(i16) = 0x99, // branch if value == 0
BranchNonZero(i16) = 0x9A, // branch if value != 0
BranchNegative(i16) = 0x9B, // branch if value < 0
BranchNonNegative(i16) = 0x9C, // branch if value <= 0
BranchPositive(i16) = 0x9D, // branch if value > 0
BranchNonPositive(i16) = 0x9E, // branch if value >= 0
CompareFloatL() = 0x95, // compare float, push -1 if one is NaN
CompareFloatG() = 0x96, // 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
BranchNonNegative(i16) = 0x9C, // branch if value <= 0
BranchPositive(i16) = 0x9D, // branch if value > 0
BranchNonPositive(i16) = 0x9E, // branch if value >= 0
BranchIntEquality(i16) = 0x9F,
BranchIntInequality(i16) = 0xA0,
BranchIntLessThan(i16) = 0xA1,
BranchIntGreaterEquals(i16) = 0xA2,
BranchIntGreaterThan(i16) = 0xA3,
BranchIntLessEquals(i16) = 0xA4,
BranchIntEquality(i16) = 0x9F,
BranchIntInequality(i16) = 0xA0,
BranchIntLessThan(i16) = 0xA1,
BranchIntGreaterEquals(i16) = 0xA2,
BranchIntGreaterThan(i16) = 0xA3,
BranchIntLessEquals(i16) = 0xA4,
BranchReferenceEquality(i16) = 0xA5,
BranchReferenceInequality(i16) = 0xA6,
BranchAlways(i16) = 0xA7, // branch if true
ReturnInt() = 0xAC, // return integer from function
BranchAlways(i16) = 0xA7, // branch if true
ReturnInt() = 0xAC, // return integer from function
ReturnReference() = 0xB0, // return top-ref from current function
ReturnVoid() = 0xB1, // return void from function
GetStatic(u16) = 0xB2, // get static field from class
PutStatic(u16) = 0xB3, // set static field on class
GetField(u16) = 0xB4, // get field from class
PutField(u16) = 0xB5, // set field to a value
InvokeVirtual(u16) = 0xB6, // invoke function on a class
InvokeSpecial(u16) = 0xB7, // invoke instance method
InvokeStatic(u16) = 0xB8, // invoke static function
InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function
NewObject(u16) = 0xBB, // Create a new object from a constant-pool class reference
NewPrimitiveArray(u8) = 0xBC, // make a primitive array
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
ArrayLength() = 0xBE, // Get length from array reference
ReturnReference() = 0xB0, // return top-ref from current function
ReturnVoid() = 0xB1, // return void from function
GetStatic(u16) = 0xB2, // get static field from class
PutStatic(u16) = 0xB3, // set static field on class
GetField(u16) = 0xB4, // get field from class
PutField(u16) = 0xB5, // set field to a value
InvokeVirtual(u16) = 0xB6, // invoke function on a class
InvokeSpecial(u16) = 0xB7, // invoke instance method
InvokeStatic(u16) = 0xB8, // invoke static function
InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function
NewObject(u16) = 0xBB, // Create a new object from a constant-pool class reference
NewPrimitiveArray(u8) = 0xBC, // make a primitive array
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
ArrayLength() = 0xBE, // Get length from array reference
EnterMonitor() = 0xC2, // enter the synchronization monitor of an object
ExitMonitor() = 0xC3, // exit the synchronization monitor of an object
BranchNull(i16) = 0xC6, // branch if Null
BranchNonNull(i16) = 0xC7, // branch if Null
InstanceOf(u16) = 0xC1, // branch if Null
EnterMonitor() = 0xC2, // enter the synchronization monitor of an object
ExitMonitor() = 0xC3, // exit the synchronization monitor of an object
BranchNull(i16) = 0xC6, // branch if Null
BranchNonNull(i16) = 0xC7, // branch if Null
Unknown(u8),
}

View file

@ -13,7 +13,7 @@ use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference, CompartmentEntry };
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator };
use crate::native_methods;
use crate::native_methods::{ EntryPoint, ignore_call };
use crate::native_methods::EntryPoint;
use crate::native_registry::NativeRegistry;
use crate::stackframe;
use crate::stackframe::{ StackFrame, StackValue, OperandStack };
@ -681,8 +681,8 @@ impl JVM {
}
Instruction::BranchIntEquality(branch_offset) => {
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
if value_1 == value_2 {
frame.instruction_pointer -= offset as u32;
@ -691,8 +691,8 @@ impl JVM {
}
Instruction::BranchIntInequality(branch_offset) => {
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
if value_1 != value_2 {
frame.instruction_pointer -= offset as u32;
@ -700,6 +700,16 @@ impl JVM {
}
}
Instruction::BranchIntLessEquals(branch_offset) => {
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
if value_1 <= value_2 {
frame.instruction_pointer -= offset as u32;
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
}
}
Instruction::BranchNonNull(branch_offset) => {
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
@ -718,6 +728,15 @@ impl JVM {
}
}
Instruction::BranchNonPositive(branch_offset) => {
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
if test_value <= 0 {
frame.instruction_pointer -= offset as u32;
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
}
}
Instruction::BranchNonZero(branch_offset) => {
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
@ -745,6 +764,50 @@ impl JVM {
}
}
Instruction::BranchReferenceInequality(branch_offset) => {
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
if value_1 != value_2 {
frame.instruction_pointer -= offset as u32;
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
}
}
Instruction::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))?;
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::CompareFloatL() => {
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 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::DivideInt() => {
// TODO: Obey all the rules
let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
@ -823,6 +886,10 @@ impl JVM {
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(fetched_value))?;
}
Instruction::InstanceOf(classref_index) => {
let class_name = class.gather_class(classref_index)?;
}
Instruction::InvokeSpecial(methodref_index) => {
// No instance-based dispatch
let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref(methodref_index)?;
@ -1046,13 +1113,19 @@ impl JVM {
let string_obj_ref = self.heap_area.make_handmade_string(string_constant, &self.class_store);
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?;
},
}
ConstantPoolInfo::Float(_) => {
// TODO: Handle error instead of unwrap
let float_constant = class.gather_float(index as u16).unwrap();
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(float_constant)))?;
},
}
ConstantPoolInfo::Integer(int_data) => {
// TODO: Handle error instead of unwrap
let int_constant = int_data.value;
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_constant)))?;
}
_ => {
println!("{:?}", class.pool_entry(index as u16).unwrap());
todo!()
@ -1120,6 +1193,19 @@ impl JVM {
}
},
Instruction::LoadLocalFloat0() => {
load_local_float(class, method, frame, 0)?;
}
Instruction::LoadLocalFloat1() => {
load_local_float(class, method, frame, 1)?;
}
Instruction::LoadLocalFloat2() => {
load_local_float(class, method, frame, 2)?;
}
Instruction::LoadLocalFloat3() => {
load_local_float(class, method, frame, 3)?;
}
Instruction::LoadLocalInt0() => {
load_local_int(class, method, frame, 0)?;
}
@ -1237,6 +1323,16 @@ impl JVM {
wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?;
}
Instruction::PushConstFloat0() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(0.0)))?;
}
Instruction::PushConstFloat1() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(1.0)))?;
}
Instruction::PushConstFloat2() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(2.0)))?;
}
Instruction::PushConstInt0() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?;
}
@ -1492,6 +1588,14 @@ fn load_local_reference(class: &JavaClassFile, method: &MethodInfo, frame: &mut
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))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(loaded_value)))?;
Ok(())
}
fn load_local_int(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {
let loaded_value = wrap_stackframe_error(class, method, frame.load_local_int(index as u16))?;

View file

@ -1,4 +1,6 @@
use crate::stackframe::StackFrame;
use crate::heap_area::ObjectReference;
use crate::heap_area::FieldValue;
use crate::jvm::wrap_stackframe_error;
use crate::stackframe::StackValue;
@ -40,6 +42,49 @@ impl EntryPoint {
struct JavaLangClass {}
impl JavaLangClass {
pub fn get_primitive_class(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
let frame = {
let frame_index = jvm.stack_frames.len() - 1;
&mut jvm.stack_frames[frame_index]
};
// max_locals: 1
// max_stack: 1
let class_class_index = jvm.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap();
let (string_class_file, string_class_index) = jvm.class_store.get_class(&String::from("java/lang/String")).unwrap();
let string_equals_index = string_class_file.find_method_index(&String::from("equals")).unwrap();
let passed_wanted_string = match frame.locals[0] {
StackValue::Reference(r) => r,
_ => unreachable!(),
};
match frame.instruction_pointer {
0 => {
let boolean_class_ref = jvm.class_store.primitive_classes.boolean_class;
let boolean_class_name_ref = match jvm.heap_area.object_area.get_object_field(
boolean_class_ref,
"name",
class_class_index,
&jvm.class_store
).unwrap() {
FieldValue::Reference(r) => r,
_ => unreachable!(),
};
let string_compare_frame = StackFrame::new(
string_class_file,
string_class_index,
string_equals_index as u16,
&[StackValue::Reference(boolean_class_name_ref), StackValue::Reference(passed_wanted_string)],
);
frame.instruction_pointer += 1;
Ok(JVMCallbackOperation::PushFrame(string_compare_frame))
},
_ => Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ObjectReference::NULL)))
}
}
pub fn desired_assertion_status_0(_: &mut JVM) -> Result<JVMCallbackOperation, Error> {
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(1)))
}
@ -375,7 +420,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
Ok(JavaLangClass::get_primitive_class)
}
("java/lang/Class", "getProtectionDomain0") => {
@ -608,6 +653,36 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
Ok(todo_call)
}
("java/lang/Float", "intBitsToFloat") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() }
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Float() },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Float", "floatToRawIntBits") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Float() }
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/String", "intern") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),

View file

@ -304,6 +304,14 @@ impl StackFrame {
}
}
pub fn load_local_float(&self, index: u16) -> Result<f32, Error> {
let local = self.locals[index as usize];
match local {
StackValue::Float(f) => Ok(f),
_ => Err(Error::LocalError(format!("Mismatched type at index {} of the function locals, expected Float but found '{:?}'", index, local)))
}
}
pub fn load_local_int(&self, index: u16) -> Result<i32, Error> {
let local = self.locals[index as usize];
match local {