Implemented opcodes, natives, fixed iterators
This commit is contained in:
parent
49916f5564
commit
dfb6060df9
6 changed files with 1485 additions and 1585 deletions
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)))?;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue