Int Branching instructions
This commit is contained in:
parent
ede316cec3
commit
6610b09c16
4 changed files with 283 additions and 82 deletions
192
src/bytecode.rs
192
src/bytecode.rs
|
@ -19,6 +19,9 @@ impl Bytecode {
|
||||||
0x06 => (Instruction::PushConstInt3(), 1),
|
0x06 => (Instruction::PushConstInt3(), 1),
|
||||||
0x07 => (Instruction::PushConstInt4(), 1),
|
0x07 => (Instruction::PushConstInt4(), 1),
|
||||||
0x08 => (Instruction::PushConstInt5(), 1),
|
0x08 => (Instruction::PushConstInt5(), 1),
|
||||||
|
0x0B => (Instruction::PushConstFloat0(), 1),
|
||||||
|
0x0C => (Instruction::PushConstFloat1(), 1),
|
||||||
|
0x0D => (Instruction::PushConstFloat2(), 1),
|
||||||
0x0E => (Instruction::PushConstDouble0(), 1),
|
0x0E => (Instruction::PushConstDouble0(), 1),
|
||||||
0x0F => (Instruction::PushConstDouble1(), 1),
|
0x0F => (Instruction::PushConstDouble1(), 1),
|
||||||
|
|
||||||
|
@ -32,6 +35,10 @@ impl Bytecode {
|
||||||
0x1B => (Instruction::LoadLocalInt1(), 1),
|
0x1B => (Instruction::LoadLocalInt1(), 1),
|
||||||
0x1C => (Instruction::LoadLocalInt2(), 1),
|
0x1C => (Instruction::LoadLocalInt2(), 1),
|
||||||
0x1D => (Instruction::LoadLocalInt3(), 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),
|
0x26 => (Instruction::LoadLocalDouble0(), 1),
|
||||||
0x27 => (Instruction::LoadLocalDouble1(), 1),
|
0x27 => (Instruction::LoadLocalDouble1(), 1),
|
||||||
0x28 => (Instruction::LoadLocalDouble2(), 1),
|
0x28 => (Instruction::LoadLocalDouble2(), 1),
|
||||||
|
@ -67,6 +74,8 @@ impl Bytecode {
|
||||||
|
|
||||||
0x80 => (Instruction::OrInt(), 1),
|
0x80 => (Instruction::OrInt(), 1),
|
||||||
|
|
||||||
|
0x95 => (Instruction::CompareFloatL(), 1),
|
||||||
|
0x96 => (Instruction::CompareFloatG(), 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)
|
||||||
|
@ -116,6 +125,14 @@ impl Bytecode {
|
||||||
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
|
||||||
(Instruction::BranchIntLessEquals(i16::from_be_bytes(bytes)), 3)
|
(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),
|
0xAC => (Instruction::ReturnInt(), 1),
|
||||||
0xA7 => {
|
0xA7 => {
|
||||||
|
@ -138,6 +155,7 @@ impl Bytecode {
|
||||||
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
|
||||||
0xBE => (Instruction::ArrayLength(), 1),
|
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),
|
0xC2 => (Instruction::EnterMonitor(), 1),
|
||||||
0xC3 => (Instruction::ExitMonitor(), 1),
|
0xC3 => (Instruction::ExitMonitor(), 1),
|
||||||
|
|
||||||
|
@ -180,99 +198,111 @@ impl Debug for Bytecode {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
NoOperation() = 0x00, // No-Operation
|
NoOperation() = 0x00, // No-Operation
|
||||||
PushNull() = 0x01, // ..., arrayref, index, value
|
PushNull() = 0x01, // ..., arrayref, index, value
|
||||||
PushConstIntM1() = 0x02, // Push -1
|
PushConstIntM1() = 0x02, // Push -1
|
||||||
PushConstInt0() = 0x03, // Push 0
|
PushConstInt0() = 0x03, // Push 0
|
||||||
PushConstInt1() = 0x04, // Push 1
|
PushConstInt1() = 0x04, // Push 1
|
||||||
PushConstInt2() = 0x05, // Push 2
|
PushConstInt2() = 0x05, // Push 2
|
||||||
PushConstInt3() = 0x06, // Push 3
|
PushConstInt3() = 0x06, // Push 3
|
||||||
PushConstInt4() = 0x07, // Push 4
|
PushConstInt4() = 0x07, // Push 4
|
||||||
PushConstInt5() = 0x08, // Push 5
|
PushConstInt5() = 0x08, // Push 5
|
||||||
PushConstDouble0() = 0x0E, // Push 0.0
|
PushConstFloat0() = 0x0B, // Push 0.0f
|
||||||
PushConstDouble1() = 0x0F, // Push 1.0
|
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
|
LoadByteImmediate(u8) = 0x10, // push immediate short
|
||||||
LoadShortImmediate(u16) = 0x11, // push immediate short
|
LoadShortImmediate(u16) = 0x11, // push immediate short
|
||||||
LoadConstant(u8) = 0x12, // Push from constant pool
|
LoadConstant(u8) = 0x12, // Push from constant pool
|
||||||
LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load
|
LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load
|
||||||
// double or long or whatever
|
// double or long or whatever
|
||||||
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
|
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
|
||||||
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
|
||||||
LoadLocalInt2() = 0x1C, // Load int from local variable
|
LoadLocalInt2() = 0x1C, // Load int from local variable
|
||||||
LoadLocalInt3() = 0x1D, // Load int from local variable
|
LoadLocalInt3() = 0x1D, // Load int from local variable
|
||||||
|
|
||||||
LoadLocalDouble0() = 0x26, // Load local double variable reference onto stack
|
LoadLocalFloat0() = 0x22, // Load local double variable reference onto stack
|
||||||
LoadLocalDouble1() = 0x27, // Load local double variable reference onto stack
|
LoadLocalFloat1() = 0x23, // Load local double variable reference onto stack
|
||||||
LoadLocalDouble2() = 0x28, // Load local double variable reference onto stack
|
LoadLocalFloat2() = 0x24, // Load local double variable reference onto stack
|
||||||
LoadLocalDouble3() = 0x29, // Load local double variable reference onto stack
|
LoadLocalFloat3() = 0x25, // Load local double variable reference onto stack
|
||||||
LoadLocalReference0() = 0x2A, // Load local reference variable reference onto stack
|
LoadLocalDouble0() = 0x26, // Load local double variable reference onto stack
|
||||||
LoadLocalReference1() = 0x2B, // Load local reference variable reference onto stack
|
LoadLocalDouble1() = 0x27, // Load local double variable reference onto stack
|
||||||
LoadLocalReference2() = 0x2C, // Load local reference variable reference onto stack
|
LoadLocalDouble2() = 0x28, // Load local double variable reference onto stack
|
||||||
LoadLocalReference3() = 0x2D, // Load local reference 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
|
ArrayElement() = 0x32, // load element from array
|
||||||
StoreLocalInt(u8) = 0x36, // store into indexed local variable
|
StoreLocalInt(u8) = 0x36, // 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
|
||||||
StoreLocalInt2() = 0x3D, // store int into local variable
|
StoreLocalInt2() = 0x3D, // store int into local variable
|
||||||
StoreLocalInt3() = 0x3E, // store int into local variable
|
StoreLocalInt3() = 0x3E, // store int into local variable
|
||||||
StoreReference0() = 0x4B, // store reference into local variable
|
StoreReference0() = 0x4B, // store reference into local variable
|
||||||
StoreReference1() = 0x4C, // store reference into local variable
|
StoreReference1() = 0x4C, // store reference into local variable
|
||||||
StoreReference2() = 0x4D, // store reference into local variable
|
StoreReference2() = 0x4D, // store reference into local variable
|
||||||
StoreReference3() = 0x4E, // store reference into local variable
|
StoreReference3() = 0x4E, // store reference into local variable
|
||||||
|
|
||||||
StoreIntoRArray() = 0x53, // store value into reference array
|
StoreIntoRArray() = 0x53, // store value into reference array
|
||||||
StoreIntoBArray() = 0x54, // store value into byte or boolean array
|
StoreIntoBArray() = 0x54, // store value into byte or boolean array
|
||||||
Pop() = 0x57, // Pop top stack value
|
Pop() = 0x57, // Pop top stack value
|
||||||
Duplicate() = 0x59, // duplicate top stack value
|
Duplicate() = 0x59, // duplicate top stack value
|
||||||
|
|
||||||
AddInt() = 0x60, // int addition
|
AddInt() = 0x60, // int addition
|
||||||
MultiplyInt() = 0x68, // int multiplication
|
MultiplyInt() = 0x68, // int multiplication
|
||||||
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
|
||||||
|
|
||||||
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
|
CompareFloatL() = 0x95, // compare float, push -1 if one is NaN
|
||||||
BranchNonZero(i16) = 0x9A, // branch if value != 0
|
CompareFloatG() = 0x96, // compare float, push 1 if one is NaN
|
||||||
BranchNegative(i16) = 0x9B, // branch if value < 0
|
BranchZero(i16) = 0x99, // branch if value == 0
|
||||||
BranchNonNegative(i16) = 0x9C, // branch if value <= 0
|
BranchNonZero(i16) = 0x9A, // branch if value != 0
|
||||||
BranchPositive(i16) = 0x9D, // branch if value > 0
|
BranchNegative(i16) = 0x9B, // branch if value < 0
|
||||||
BranchNonPositive(i16) = 0x9E, // 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,
|
BranchIntEquality(i16) = 0x9F,
|
||||||
BranchIntInequality(i16) = 0xA0,
|
BranchIntInequality(i16) = 0xA0,
|
||||||
BranchIntLessThan(i16) = 0xA1,
|
BranchIntLessThan(i16) = 0xA1,
|
||||||
BranchIntGreaterEquals(i16) = 0xA2,
|
BranchIntGreaterEquals(i16) = 0xA2,
|
||||||
BranchIntGreaterThan(i16) = 0xA3,
|
BranchIntGreaterThan(i16) = 0xA3,
|
||||||
BranchIntLessEquals(i16) = 0xA4,
|
BranchIntLessEquals(i16) = 0xA4,
|
||||||
|
BranchReferenceEquality(i16) = 0xA5,
|
||||||
|
BranchReferenceInequality(i16) = 0xA6,
|
||||||
|
|
||||||
BranchAlways(i16) = 0xA7, // branch if true
|
BranchAlways(i16) = 0xA7, // branch if true
|
||||||
ReturnInt() = 0xAC, // return integer from function
|
ReturnInt() = 0xAC, // return integer 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
|
||||||
GetStatic(u16) = 0xB2, // get static field from class
|
GetStatic(u16) = 0xB2, // get static field from class
|
||||||
PutStatic(u16) = 0xB3, // set static field on class
|
PutStatic(u16) = 0xB3, // set static field on class
|
||||||
GetField(u16) = 0xB4, // get field from class
|
GetField(u16) = 0xB4, // get field from class
|
||||||
PutField(u16) = 0xB5, // set field to a value
|
PutField(u16) = 0xB5, // set field to a value
|
||||||
InvokeVirtual(u16) = 0xB6, // invoke function on a class
|
InvokeVirtual(u16) = 0xB6, // invoke function on a class
|
||||||
InvokeSpecial(u16) = 0xB7, // invoke instance method
|
InvokeSpecial(u16) = 0xB7, // invoke instance method
|
||||||
InvokeStatic(u16) = 0xB8, // invoke static function
|
InvokeStatic(u16) = 0xB8, // invoke static function
|
||||||
InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function
|
InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function
|
||||||
NewObject(u16) = 0xBB, // Create a new object from a constant-pool class reference
|
NewObject(u16) = 0xBB, // Create a new object from a constant-pool class reference
|
||||||
NewPrimitiveArray(u8) = 0xBC, // make a primitive array
|
NewPrimitiveArray(u8) = 0xBC, // make a primitive array
|
||||||
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
|
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
|
||||||
ArrayLength() = 0xBE, // Get length from array reference
|
ArrayLength() = 0xBE, // Get length from array reference
|
||||||
|
|
||||||
EnterMonitor() = 0xC2, // enter the synchronization monitor of an object
|
InstanceOf(u16) = 0xC1, // branch if Null
|
||||||
ExitMonitor() = 0xC3, // exit the synchronization monitor of an object
|
EnterMonitor() = 0xC2, // enter the synchronization monitor of an object
|
||||||
BranchNull(i16) = 0xC6, // branch if Null
|
ExitMonitor() = 0xC3, // exit the synchronization monitor of an object
|
||||||
BranchNonNull(i16) = 0xC7, // branch if Null
|
BranchNull(i16) = 0xC6, // branch if Null
|
||||||
|
BranchNonNull(i16) = 0xC7, // branch if Null
|
||||||
|
|
||||||
Unknown(u8),
|
Unknown(u8),
|
||||||
}
|
}
|
||||||
|
|
88
src/jvm.rs
88
src/jvm.rs
|
@ -728,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) => {
|
Instruction::BranchNonZero(branch_offset) => {
|
||||||
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
|
||||||
|
@ -755,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() => {
|
Instruction::DivideInt() => {
|
||||||
// TODO: Obey all the rules
|
// TODO: Obey all the rules
|
||||||
let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||||
|
@ -833,6 +886,10 @@ impl JVM {
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(fetched_value))?;
|
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) => {
|
Instruction::InvokeSpecial(methodref_index) => {
|
||||||
// No instance-based dispatch
|
// No instance-based dispatch
|
||||||
let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref(methodref_index)?;
|
let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref(methodref_index)?;
|
||||||
|
@ -1136,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() => {
|
Instruction::LoadLocalInt0() => {
|
||||||
load_local_int(class, method, frame, 0)?;
|
load_local_int(class, method, frame, 0)?;
|
||||||
}
|
}
|
||||||
|
@ -1253,6 +1323,16 @@ impl JVM {
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?;
|
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() => {
|
Instruction::PushConstInt0() => {
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?;
|
||||||
}
|
}
|
||||||
|
@ -1508,6 +1588,14 @@ fn load_local_reference(class: &JavaClassFile, method: &MethodInfo, frame: &mut
|
||||||
Ok(())
|
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> {
|
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))?;
|
let loaded_value = wrap_stackframe_error(class, method, frame.load_local_int(index as u16))?;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
|
use crate::stackframe::StackFrame;
|
||||||
|
use crate::heap_area::ObjectReference;
|
||||||
use crate::heap_area::FieldValue;
|
use crate::heap_area::FieldValue;
|
||||||
use crate::jvm::wrap_stackframe_error;
|
use crate::jvm::wrap_stackframe_error;
|
||||||
use crate::stackframe::StackValue;
|
use crate::stackframe::StackValue;
|
||||||
|
@ -40,6 +42,49 @@ impl EntryPoint {
|
||||||
struct JavaLangClass {}
|
struct JavaLangClass {}
|
||||||
|
|
||||||
impl 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> {
|
pub fn desired_assertion_status_0(_: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(1)))
|
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())));
|
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") => {
|
("java/lang/Class", "getProtectionDomain0") => {
|
||||||
|
@ -608,6 +653,36 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
Ok(todo_call)
|
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") => {
|
("java/lang/String", "intern") => {
|
||||||
let expected_descriptor = MethodDescriptor {
|
let expected_descriptor = MethodDescriptor {
|
||||||
argument_types: Box::new([]),
|
argument_types: Box::new([]),
|
||||||
|
|
|
@ -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> {
|
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