Compare commits
2 commits
0c54a1d7e1
...
6610b09c16
Author | SHA1 | Date | |
---|---|---|---|
6610b09c16 | |||
ede316cec3 |
4 changed files with 304 additions and 87 deletions
|
@ -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),
|
||||
|
||||
|
@ -189,6 +207,9 @@ pub enum Instruction {
|
|||
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
|
||||
|
||||
|
@ -203,6 +224,10 @@ pub enum Instruction {
|
|||
LoadLocalInt2() = 0x1C, // 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
|
||||
LoadLocalDouble1() = 0x27, // 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
|
||||
|
||||
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
|
||||
|
@ -250,6 +277,8 @@ pub enum Instruction {
|
|||
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
|
||||
|
@ -269,6 +298,7 @@ pub enum Instruction {
|
|||
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
|
||||
ArrayLength() = 0xBE, // Get length from array reference
|
||||
|
||||
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
|
||||
|
|
114
src/jvm.rs
114
src/jvm.rs
|
@ -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))?;
|
||||
|
||||
|
|
|
@ -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([]),
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue