Int Branching instructions

This commit is contained in:
VegOwOtenks 2024-09-10 01:33:35 +02:00
parent ede316cec3
commit 6610b09c16
4 changed files with 283 additions and 82 deletions

View file

@ -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),
@ -189,6 +207,9 @@ pub enum Instruction {
PushConstInt3() = 0x06, // Push 3 PushConstInt3() = 0x06, // Push 3
PushConstInt4() = 0x07, // Push 4 PushConstInt4() = 0x07, // Push 4
PushConstInt5() = 0x08, // Push 5 PushConstInt5() = 0x08, // Push 5
PushConstFloat0() = 0x0B, // Push 0.0f
PushConstFloat1() = 0x0C, // Push 1.0f
PushConstFloat2() = 0x0D, // Push 2.0f
PushConstDouble0() = 0x0E, // Push 0.0 PushConstDouble0() = 0x0E, // Push 0.0
PushConstDouble1() = 0x0F, // Push 1.0 PushConstDouble1() = 0x0F, // Push 1.0
@ -203,6 +224,10 @@ pub enum Instruction {
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
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 LoadLocalDouble0() = 0x26, // Load local double variable reference onto stack
LoadLocalDouble1() = 0x27, // 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 LoadLocalDouble2() = 0x28, // Load local double variable reference onto stack
@ -237,6 +262,8 @@ pub enum Instruction {
OrInt() = 0x80, // value, value => or OrInt() = 0x80, // value, value => or
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 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
@ -250,6 +277,8 @@ pub enum Instruction {
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
@ -269,6 +298,7 @@ pub enum Instruction {
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
InstanceOf(u16) = 0xC1, // branch if Null
EnterMonitor() = 0xC2, // enter the synchronization monitor of an object EnterMonitor() = 0xC2, // enter the synchronization monitor of an object
ExitMonitor() = 0xC3, // exit the synchronization monitor of an object ExitMonitor() = 0xC3, // exit the synchronization monitor of an object
BranchNull(i16) = 0xC6, // branch if Null BranchNull(i16) = 0xC6, // branch if Null

View file

@ -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))?;

View file

@ -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([]),

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> { 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 {