Implemented opcodes, natives, fixed iterators

This commit is contained in:
VegOwOtenks 2024-11-06 23:39:26 +01:00
parent 49916f5564
commit dfb6060df9
6 changed files with 1485 additions and 1585 deletions

View file

@ -88,6 +88,8 @@ impl Bytecode {
0x5A => (Instruction::DuplicateInsertDown(), 1), 0x5A => (Instruction::DuplicateInsertDown(), 1),
0x60 => (Instruction::AddInt(), 1), 0x60 => (Instruction::AddInt(), 1),
0x61 => (Instruction::AddLong(), 1),
0x63 => (Instruction::AddDouble(), 1),
0x64 => (Instruction::SubtractInt(), 1), 0x64 => (Instruction::SubtractInt(), 1),
0x65 => (Instruction::SubtractLong(), 1), 0x65 => (Instruction::SubtractLong(), 1),
0x68 => (Instruction::MultiplyInt(), 1), 0x68 => (Instruction::MultiplyInt(), 1),
@ -95,10 +97,12 @@ impl Bytecode {
0x6A => (Instruction::MultiplyFloat(), 1), 0x6A => (Instruction::MultiplyFloat(), 1),
0x6C => (Instruction::DivideInt(), 1), 0x6C => (Instruction::DivideInt(), 1),
0x6D => (Instruction::DivideLong(), 1), 0x6D => (Instruction::DivideLong(), 1),
0x6E => (Instruction::DivideFloat(), 1),
0x74 => (Instruction::NegateInt(), 1), 0x74 => (Instruction::NegateInt(), 1),
0x75 => (Instruction::NegateLong(), 1), 0x75 => (Instruction::NegateLong(), 1),
0x78 => (Instruction::ArithmeticShiftIntLeft(), 1), 0x78 => (Instruction::ArithmeticShiftIntLeft(), 1),
0x79 => (Instruction::ArithmeticShiftLongLeft(), 1),
0x7A => (Instruction::ArithmeticShiftIntRight(), 1), 0x7A => (Instruction::ArithmeticShiftIntRight(), 1),
0x7C => (Instruction::LogicalShiftIntRight(), 1), 0x7C => (Instruction::LogicalShiftIntRight(), 1),
0x7E => (Instruction::AndInt(), 1), 0x7E => (Instruction::AndInt(), 1),
@ -110,7 +114,10 @@ impl Bytecode {
0x86 => (Instruction::ConvertIntToFloat(), 1), 0x86 => (Instruction::ConvertIntToFloat(), 1),
0x88 => (Instruction::ConvertLongToInt(), 1), 0x88 => (Instruction::ConvertLongToInt(), 1),
0x89 => (Instruction::ConvertLongToFloat(), 1),
0x8B => (Instruction::ConvertFloatToInt(), 1), 0x8B => (Instruction::ConvertFloatToInt(), 1),
0x8D => (Instruction::ConvertFloatToDouble(), 1),
0x8F => (Instruction::ConvertDoubleToLong(), 1),
0x91 => (Instruction::ConvertIntToByte(), 1), 0x91 => (Instruction::ConvertIntToByte(), 1),
0x92 => (Instruction::ConvertIntToChar(), 1), 0x92 => (Instruction::ConvertIntToChar(), 1),
0x94 => (Instruction::CompareLong(), 1), 0x94 => (Instruction::CompareLong(), 1),
@ -361,6 +368,8 @@ pub enum Instruction {
DuplicateInsertDown() = 0x5A, // duplicate top stack value and insert two low DuplicateInsertDown() = 0x5A, // duplicate top stack value and insert two low
AddInt() = 0x60, // int addition AddInt() = 0x60, // int addition
AddLong() = 0x61, // long addition
AddDouble() = 0x63, // double addition
SubtractInt() = 0x64, // int subtraction SubtractInt() = 0x64, // int subtraction
SubtractLong() = 0x65, // long subtraction SubtractLong() = 0x65, // long subtraction
MultiplyInt() = 0x68, // int multiplication MultiplyInt() = 0x68, // int multiplication
@ -368,10 +377,12 @@ pub enum Instruction {
MultiplyFloat() = 0x6A, // float multiplication MultiplyFloat() = 0x6A, // float 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
DivideFloat() = 0x6E, // float division
NegateInt() = 0x74, // arithmetic negation NegateInt() = 0x74, // arithmetic negation
NegateLong() = 0x75, // arithmetic negation NegateLong() = 0x75, // arithmetic negation
ArithmeticShiftIntLeft() = 0x78, // shift int left, preserve sign ArithmeticShiftIntLeft() = 0x78, // shift int left, preserve sign
ArithmeticShiftLongLeft() = 0x79, // shift long left, preserve sign
ArithmeticShiftIntRight() = 0x7A, // shift int right, preserve sign ArithmeticShiftIntRight() = 0x7A, // shift int right, preserve sign
LogicalShiftIntRight() = 0x7C, // shift int right with zero extension LogicalShiftIntRight() = 0x7C, // shift int right with zero extension
AndInt() = 0x7E, // bitwise and AndInt() = 0x7E, // bitwise and
@ -383,7 +394,10 @@ pub enum Instruction {
ConvertIntToFloat() = 0x86, // change data type ConvertIntToFloat() = 0x86, // change data type
ConvertLongToInt() = 0x88, // change data type ConvertLongToInt() = 0x88, // change data type
ConvertLongToFloat() = 0x89, // change data type
ConvertFloatToInt() = 0x8B, // 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 ConvertIntToByte() = 0x91, // truncate int to 8 bits
ConvertIntToChar() = 0x92, // truncate int to 16 bits ConvertIntToChar() = 0x92, // truncate int to 16 bits
CompareLong() = 0x94, // compare long CompareLong() = 0x94, // compare long

View file

@ -710,7 +710,7 @@ pub struct ObjectField {
pub value: FieldValue, pub value: FieldValue,
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum FieldValue { pub enum FieldValue {
Boolean(bool), Boolean(bool),
Byte(i8), Byte(i8),

View file

@ -74,14 +74,15 @@ impl <'i> Iterator for CompatibleTypesIterator<'i>{
Some(class_file.get_super_class_name().unwrap()) Some(class_file.get_super_class_name().unwrap())
} else { } else {
None let recursive_next = self.next();
recursive_next
} }
} else { } else {
let interface_name = class_file.gather_class(class_file.interfaces[interface_index]).unwrap(); 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((class_index, interface_index + 1));
self.class_stack.push((interface_index, 0)); self.class_stack.push((interface_class_index, 0));
Some(interface_name) Some(interface_name)
} }

View file

@ -157,7 +157,7 @@ impl JVM {
fn make_array_class(&mut self, element_class_ref: ObjectReference, element_descriptor: AbstractTypeDescription) { 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 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_class_data_object = self.heap_area.make_object(&self.class_store, 1);
let array_type_description = AbstractTypeDescription { let array_type_description = AbstractTypeDescription {
array_level: 1 + element_descriptor.array_level, 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(entry_class, true)?; // 0
self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1 self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1
self.load_class(&"java/lang/Object".to_string())?; // 2 self.load_class_hierarchy(&"java/lang/Object".to_string())?; // 2
self.load_class(&"java/lang/Number".to_string())?; // 3 self.load_class_hierarchy(&"java/lang/Number".to_string())?; // 3
let byte_class_index = self.load_class(&"java/lang/Byte".to_string())?; // 4 let byte_class_index = self.load_class_hierarchy(&"java/lang/Byte".to_string())?; // 4
let string_class_index = self.load_class(&"java/lang/String".to_string())?; // 5 let string_class_index = self.load_class_hierarchy(&"java/lang/String".to_string())?; // 5
let class_class_index = self.load_class(&"java/lang/Class".to_string())?; // 6 let class_class_index = self.load_class_hierarchy(&"java/lang/Class".to_string())?; // 6
let system_class_index = self.load_class(&"java/lang/System".to_string())?; // 7 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/Byte;");
self.make_class_class("Ljava/lang/String;"); self.make_class_class("Ljava/lang/String;");
@ -466,15 +466,21 @@ impl JVM {
Ok(()) 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(); let mut waiting_queue = VecDeque::new();
waiting_queue.push_back(name.clone()); waiting_queue.push_back(name.clone());
let mut return_class_index = usize::MAX;
while waiting_queue.len() != 0 { while waiting_queue.len() != 0 {
let class_name = waiting_queue.pop_front().unwrap(); let class_name = waiting_queue.pop_front().unwrap();
if ! self.class_store.have_class(&class_name) { if ! self.class_store.have_class(&class_name) {
let new_class_index = self.load_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(); let (file, _) = self.class_store.get_class(&class_name).unwrap();
if file.has_super_class() { if file.has_super_class() {
waiting_queue.push_back(file.get_super_class_name()?.to_string()); 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> { fn init_class_hierarchy(&mut self, name: &String) -> Result<(), Error> {
@ -678,6 +684,13 @@ impl JVM {
match instruction { 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() => { Instruction::AddInt() => {
let value_0 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; 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))?; 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)))?; 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() => { Instruction::ArithmeticShiftIntLeft() => {
let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 & 0b00011111; 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))?; 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)))?; 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() => { Instruction::ArrayLength() => {
let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
@ -884,6 +912,19 @@ impl JVM {
Instruction::CheckCast(classref_index) => { Instruction::CheckCast(classref_index) => {
// TODO: Class loading checks // TODO: Class loading checks
let class_name = class.gather_class(classref_index)?; 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))?; let object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
if object != ObjectReference::NULL { if object != ObjectReference::NULL {
let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store); 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)))?; 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() => { Instruction::ConvertFloatToInt() => {
let float = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?; let float = wrap_stackframe_error(class, method, frame.operand_stack.pop_float(0))?;
let int_value = match float { let int_value = match float {
@ -965,7 +1013,18 @@ impl JVM {
v @ _ => if v.is_nan() { 0 } else { v as i32 } , 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() => { Instruction::ConvertIntToByte() => {
@ -1003,6 +1062,21 @@ impl JVM {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int_value)))?; 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() => { 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))?;
@ -1051,10 +1125,10 @@ impl JVM {
// TODO: Are there any methods callable on arrays? // 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_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 { let this_object_descriptor = AbstractTypeDescription {
array_level: 0, array_level: 0,
kind: AbstractTypeKind::Classname(this_object_class_name.clone()) kind: AbstractTypeKind::Classname(this_object_class_name.to_string())
}; };
let object_descriptor = AbstractTypeDescription { let object_descriptor = AbstractTypeDescription {
array_level: 0, array_level: 0,
@ -1815,6 +1889,9 @@ 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::PushConstDouble1() => {
wrap_stackframe_error(class, method, frame.operand_stack.push_double(1.0))?;
}
Instruction::PushConstFloat0() => { Instruction::PushConstFloat0() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(0.0)))?; wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(0.0)))?;
} }

File diff suppressed because it is too large Load diff

View file

@ -268,14 +268,14 @@ impl OperandStack {
pub fn pop_double(&mut self, index: usize) -> Result<f64, Error> { pub fn pop_double(&mut self, index: usize) -> Result<f64, Error> {
let absolute_index = self.depth as usize - 1 - index; let absolute_index = self.depth as usize - 1 - index;
let higher_bytes = self.stack[absolute_index]; let double1 = self.stack[absolute_index];
let lower_bytes = self.stack[absolute_index + 1]; let double0 = self.stack[absolute_index - 1];
self.depth -= 2; self.depth -= 2;
match (higher_bytes, lower_bytes) { match (double0, double1) {
(StackValue::Double0(double), StackValue::Double1()) => { (StackValue::Double0(double), StackValue::Double1()) => {
Ok(double) 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))))
} }
} }