Implemented opcodes, natives, fixed iterators
This commit is contained in:
parent
49916f5564
commit
dfb6060df9
6 changed files with 1485 additions and 1585 deletions
|
@ -88,6 +88,8 @@ impl Bytecode {
|
|||
0x5A => (Instruction::DuplicateInsertDown(), 1),
|
||||
|
||||
0x60 => (Instruction::AddInt(), 1),
|
||||
0x61 => (Instruction::AddLong(), 1),
|
||||
0x63 => (Instruction::AddDouble(), 1),
|
||||
0x64 => (Instruction::SubtractInt(), 1),
|
||||
0x65 => (Instruction::SubtractLong(), 1),
|
||||
0x68 => (Instruction::MultiplyInt(), 1),
|
||||
|
@ -95,10 +97,12 @@ impl Bytecode {
|
|||
0x6A => (Instruction::MultiplyFloat(), 1),
|
||||
0x6C => (Instruction::DivideInt(), 1),
|
||||
0x6D => (Instruction::DivideLong(), 1),
|
||||
0x6E => (Instruction::DivideFloat(), 1),
|
||||
|
||||
0x74 => (Instruction::NegateInt(), 1),
|
||||
0x75 => (Instruction::NegateLong(), 1),
|
||||
0x78 => (Instruction::ArithmeticShiftIntLeft(), 1),
|
||||
0x79 => (Instruction::ArithmeticShiftLongLeft(), 1),
|
||||
0x7A => (Instruction::ArithmeticShiftIntRight(), 1),
|
||||
0x7C => (Instruction::LogicalShiftIntRight(), 1),
|
||||
0x7E => (Instruction::AndInt(), 1),
|
||||
|
@ -110,7 +114,10 @@ impl Bytecode {
|
|||
|
||||
0x86 => (Instruction::ConvertIntToFloat(), 1),
|
||||
0x88 => (Instruction::ConvertLongToInt(), 1),
|
||||
0x89 => (Instruction::ConvertLongToFloat(), 1),
|
||||
0x8B => (Instruction::ConvertFloatToInt(), 1),
|
||||
0x8D => (Instruction::ConvertFloatToDouble(), 1),
|
||||
0x8F => (Instruction::ConvertDoubleToLong(), 1),
|
||||
0x91 => (Instruction::ConvertIntToByte(), 1),
|
||||
0x92 => (Instruction::ConvertIntToChar(), 1),
|
||||
0x94 => (Instruction::CompareLong(), 1),
|
||||
|
@ -361,6 +368,8 @@ pub enum Instruction {
|
|||
DuplicateInsertDown() = 0x5A, // duplicate top stack value and insert two low
|
||||
|
||||
AddInt() = 0x60, // int addition
|
||||
AddLong() = 0x61, // long addition
|
||||
AddDouble() = 0x63, // double addition
|
||||
SubtractInt() = 0x64, // int subtraction
|
||||
SubtractLong() = 0x65, // long subtraction
|
||||
MultiplyInt() = 0x68, // int multiplication
|
||||
|
@ -368,10 +377,12 @@ pub enum Instruction {
|
|||
MultiplyFloat() = 0x6A, // float multiplication
|
||||
DivideInt() = 0x6C, // integer division, round toward zero and more rules
|
||||
DivideLong() = 0x6D, // long division
|
||||
DivideFloat() = 0x6E, // float division
|
||||
|
||||
NegateInt() = 0x74, // arithmetic negation
|
||||
NegateLong() = 0x75, // arithmetic negation
|
||||
ArithmeticShiftIntLeft() = 0x78, // shift int left, preserve sign
|
||||
ArithmeticShiftLongLeft() = 0x79, // shift long left, preserve sign
|
||||
ArithmeticShiftIntRight() = 0x7A, // shift int right, preserve sign
|
||||
LogicalShiftIntRight() = 0x7C, // shift int right with zero extension
|
||||
AndInt() = 0x7E, // bitwise and
|
||||
|
@ -383,7 +394,10 @@ pub enum Instruction {
|
|||
|
||||
ConvertIntToFloat() = 0x86, // change data type
|
||||
ConvertLongToInt() = 0x88, // change data type
|
||||
ConvertLongToFloat() = 0x89, // change data type
|
||||
ConvertFloatToInt() = 0x8B, // change data type
|
||||
ConvertFloatToDouble() = 0x8D, // change data type
|
||||
ConvertDoubleToLong() = 0x8F, // change data type
|
||||
ConvertIntToByte() = 0x91, // truncate int to 8 bits
|
||||
ConvertIntToChar() = 0x92, // truncate int to 16 bits
|
||||
CompareLong() = 0x94, // compare long
|
||||
|
|
|
@ -710,7 +710,7 @@ pub struct ObjectField {
|
|||
pub value: FieldValue,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum FieldValue {
|
||||
Boolean(bool),
|
||||
Byte(i8),
|
||||
|
|
|
@ -74,14 +74,15 @@ impl <'i> Iterator for CompatibleTypesIterator<'i>{
|
|||
|
||||
Some(class_file.get_super_class_name().unwrap())
|
||||
} else {
|
||||
None
|
||||
let recursive_next = self.next();
|
||||
recursive_next
|
||||
}
|
||||
} else {
|
||||
let interface_name = class_file.gather_class(class_file.interfaces[interface_index]).unwrap();
|
||||
let interface_index = self.class_store.class_idx_from_name(interface_name).unwrap();
|
||||
let interface_class_index = self.class_store.class_idx_from_name(interface_name).unwrap();
|
||||
|
||||
self.class_stack.push((class_index, interface_index + 1));
|
||||
self.class_stack.push((interface_index, 0));
|
||||
self.class_stack.push((interface_class_index, 0));
|
||||
|
||||
Some(interface_name)
|
||||
}
|
||||
|
|
101
src/jvm.rs
101
src/jvm.rs
|
@ -157,7 +157,7 @@ impl JVM {
|
|||
fn make_array_class(&mut self, element_class_ref: ObjectReference, element_descriptor: AbstractTypeDescription) {
|
||||
let class_class_index = self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap();
|
||||
|
||||
let array_class_object = self.heap_area.make_object(&self.class_store, 6);
|
||||
let array_class_object = self.heap_area.make_object(&self.class_store, class_class_index);
|
||||
let array_class_data_object = self.heap_area.make_object(&self.class_store, 1);
|
||||
let array_type_description = AbstractTypeDescription {
|
||||
array_level: 1 + element_descriptor.array_level,
|
||||
|
@ -341,12 +341,12 @@ impl JVM {
|
|||
|
||||
self.class_store.add_class(entry_class, true)?; // 0
|
||||
self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1
|
||||
self.load_class(&"java/lang/Object".to_string())?; // 2
|
||||
self.load_class(&"java/lang/Number".to_string())?; // 3
|
||||
let byte_class_index = self.load_class(&"java/lang/Byte".to_string())?; // 4
|
||||
let string_class_index = self.load_class(&"java/lang/String".to_string())?; // 5
|
||||
let class_class_index = self.load_class(&"java/lang/Class".to_string())?; // 6
|
||||
let system_class_index = self.load_class(&"java/lang/System".to_string())?; // 7
|
||||
self.load_class_hierarchy(&"java/lang/Object".to_string())?; // 2
|
||||
self.load_class_hierarchy(&"java/lang/Number".to_string())?; // 3
|
||||
let byte_class_index = self.load_class_hierarchy(&"java/lang/Byte".to_string())?; // 4
|
||||
let string_class_index = self.load_class_hierarchy(&"java/lang/String".to_string())?; // 5
|
||||
let class_class_index = self.load_class_hierarchy(&"java/lang/Class".to_string())?; // 6
|
||||
let system_class_index = self.load_class_hierarchy(&"java/lang/System".to_string())?; // 7
|
||||
|
||||
self.make_class_class("Ljava/lang/Byte;");
|
||||
self.make_class_class("Ljava/lang/String;");
|
||||
|
@ -466,15 +466,21 @@ impl JVM {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn load_class_hierarchy(&mut self, name: &String) -> Result<(), Error> {
|
||||
fn load_class_hierarchy(&mut self, name: &String) -> Result<usize, Error> {
|
||||
let mut waiting_queue = VecDeque::new();
|
||||
waiting_queue.push_back(name.clone());
|
||||
let mut return_class_index = usize::MAX;
|
||||
|
||||
while waiting_queue.len() != 0 {
|
||||
let class_name = waiting_queue.pop_front().unwrap();
|
||||
|
||||
if ! self.class_store.have_class(&class_name) {
|
||||
let new_class_index = self.load_class(&class_name)?;
|
||||
|
||||
if class_name == *name {
|
||||
return_class_index = new_class_index;
|
||||
}
|
||||
|
||||
let (file, _) = self.class_store.get_class(&class_name).unwrap();
|
||||
if file.has_super_class() {
|
||||
waiting_queue.push_back(file.get_super_class_name()?.to_string());
|
||||
|
@ -488,7 +494,7 @@ impl JVM {
|
|||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(return_class_index)
|
||||
}
|
||||
|
||||
fn init_class_hierarchy(&mut self, name: &String) -> Result<(), Error> {
|
||||
|
@ -678,6 +684,13 @@ impl JVM {
|
|||
|
||||
match instruction {
|
||||
|
||||
Instruction::AddDouble() => {
|
||||
let value_0 = 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))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_double(value_0 + value_1))?;
|
||||
}
|
||||
|
||||
Instruction::AddInt() => {
|
||||
let value_0 = 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))?;
|
||||
|
@ -685,6 +698,13 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_0 + value_1)))?;
|
||||
}
|
||||
|
||||
Instruction::AddLong() => {
|
||||
let value_0 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?;
|
||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_long(value_0 + value_1))?;
|
||||
}
|
||||
|
||||
Instruction::ArithmeticShiftIntLeft() => {
|
||||
let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 & 0b00011111;
|
||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
@ -700,6 +720,14 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int >> shift)))?;
|
||||
}
|
||||
|
||||
Instruction::ArithmeticShiftLongLeft() => {
|
||||
let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 % 64;
|
||||
let long = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?;
|
||||
|
||||
// rust does arithmetic shift on signed values
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_long(long << shift))?;
|
||||
}
|
||||
|
||||
Instruction::ArrayLength() => {
|
||||
let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
|
@ -884,6 +912,19 @@ impl JVM {
|
|||
Instruction::CheckCast(classref_index) => {
|
||||
// TODO: Class loading checks
|
||||
let class_name = class.gather_class(classref_index)?;
|
||||
if ! class_name.starts_with("[") { // don't load array classes
|
||||
if ! self.class_store.have_class(class_name) {
|
||||
// rewind the bytecode offset, I'll need to execute this instruction again
|
||||
frame.instruction_pointer -= offset as u32;
|
||||
return Ok(JVMCallbackOperation::LoadClass(class_name.to_string()));
|
||||
}
|
||||
if ! self.class_store.was_init(class_name).unwrap() {
|
||||
// rewind the bytecode offset, I'll need to execute this instruction again
|
||||
frame.instruction_pointer -= offset as u32;
|
||||
return Ok(JVMCallbackOperation::InitClass(class_name.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
if object != ObjectReference::NULL {
|
||||
let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store);
|
||||
|
@ -957,6 +998,13 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(comparison_result)))?;
|
||||
}
|
||||
|
||||
Instruction::ConvertFloatToDouble() => {
|
||||
let float = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
||||
let double = float as f64;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_double(double))?;
|
||||
}
|
||||
|
||||
Instruction::ConvertFloatToInt() => {
|
||||
let float = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
||||
let int_value = match float {
|
||||
|
@ -965,7 +1013,18 @@ impl JVM {
|
|||
v @ _ => if v.is_nan() { 0 } else { v as i32 } ,
|
||||
};
|
||||
|
||||
frame.operand_stack.push(StackValue::Int(int_value)).unwrap();
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?;
|
||||
}
|
||||
|
||||
Instruction::ConvertDoubleToLong() => {
|
||||
let double = wrap_stackframe_error(class, method, frame.operand_stack.pop_double(0))?;
|
||||
let long = match double {
|
||||
f64::INFINITY => i64::MAX,
|
||||
f64::NEG_INFINITY => i64::MIN,
|
||||
v @ _ => if v.is_nan() { 0 } else { v as i64 }
|
||||
};
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_long(long))?;
|
||||
}
|
||||
|
||||
Instruction::ConvertIntToByte() => {
|
||||
|
@ -1003,6 +1062,21 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?;
|
||||
}
|
||||
|
||||
Instruction::ConvertLongToFloat() => {
|
||||
let long_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?;
|
||||
let float_value = long_value as f32;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(float_value)))?;
|
||||
}
|
||||
|
||||
Instruction::DivideFloat() => {
|
||||
// TODO: Obey all the rules
|
||||
let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
||||
let divident = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
|
||||
|
||||
frame.operand_stack.push(StackValue::Float(divident / quotient)).unwrap();
|
||||
}
|
||||
|
||||
Instruction::DivideInt() => {
|
||||
// TODO: Obey all the rules
|
||||
let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
||||
|
@ -1051,10 +1125,10 @@ impl JVM {
|
|||
|
||||
// TODO: Are there any methods callable on arrays?
|
||||
let this_object_class_index = self.heap_area.object_area.get_object_class_index(this_object);
|
||||
let this_object_class_name = self.class_store.class_name_from_index(this_object_class_index).unwrap().to_string();
|
||||
let this_object_class_name = self.class_store.class_name_from_index(this_object_class_index).unwrap();
|
||||
let this_object_descriptor = AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: AbstractTypeKind::Classname(this_object_class_name.clone())
|
||||
kind: AbstractTypeKind::Classname(this_object_class_name.to_string())
|
||||
};
|
||||
let object_descriptor = AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
|
@ -1815,6 +1889,9 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?;
|
||||
}
|
||||
|
||||
Instruction::PushConstDouble1() => {
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_double(1.0))?;
|
||||
}
|
||||
Instruction::PushConstFloat0() => {
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(0.0)))?;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -268,14 +268,14 @@ impl OperandStack {
|
|||
|
||||
pub fn pop_double(&mut self, index: usize) -> Result<f64, Error> {
|
||||
let absolute_index = self.depth as usize - 1 - index;
|
||||
let higher_bytes = self.stack[absolute_index];
|
||||
let lower_bytes = self.stack[absolute_index + 1];
|
||||
let double1 = self.stack[absolute_index];
|
||||
let double0 = self.stack[absolute_index - 1];
|
||||
self.depth -= 2;
|
||||
match (higher_bytes, lower_bytes) {
|
||||
match (double0, double1) {
|
||||
(StackValue::Double0(double), StackValue::Double1()) => {
|
||||
Ok(double)
|
||||
},
|
||||
_ => Err(Error::LocalError(format!("Mismatched types at index {} of the function operand stack, expected (Double0, Double1) but found '{:?}'", index, (higher_bytes, lower_bytes))))
|
||||
_ => Err(Error::LocalError(format!("Mismatched types at index {} of the function operand stack, expected (Double0, Double1) but found '{:?}'", index, (double1, double0))))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue