jvm/src/jvm.rs

1216 lines
58 KiB
Rust
Raw Normal View History

2024-08-30 15:33:54 +02:00
use core::fmt::{Display, Formatter};
2024-09-02 11:28:00 +02:00
2024-09-02 15:42:42 +02:00
use std::collections::VecDeque;
2024-08-30 15:33:54 +02:00
use std::error::Error as ErrorTrait;
2024-09-05 00:33:14 +02:00
use crate::accessmasks::{ ClassAccessFlagMask, ClassAccessFlag, MethodAccessFlagMask, MethodAccessFlag, FieldAccessFlag, FieldAccessFlagMask };
2024-09-02 11:28:00 +02:00
use crate::bytecode::{ Bytecode, Instruction };
use crate::classfile;
2024-09-05 00:33:14 +02:00
use crate::classfile::{ JavaClassFile, FieldInfo, MethodInfo, MethodDescriptor, AbstractTypeDescription, AbstractTypeKind, AttributeInfo, AttributeData, CodeAttributeData, ConstantValueAttributeData };
2024-08-30 15:33:54 +02:00
use crate::classstore;
use crate::classstore::ClassStore;
2024-09-02 11:28:00 +02:00
use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo};
2024-09-03 00:49:28 +02:00
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference };
2024-09-05 00:33:14 +02:00
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator, CompatibleTypesIterator };
2024-09-02 15:42:42 +02:00
use crate::stackframe;
2024-09-02 17:46:00 +02:00
use crate::stackframe::{ StackFrame, StackValue, OperandStack };
2024-08-30 15:33:54 +02:00
#[derive(Debug)]
pub enum Error {
ClassStoreError(classstore::Error),
2024-09-02 11:28:00 +02:00
ClassFileError(classfile::Error),
2024-09-02 15:42:42 +02:00
StackFrameError(stackframe::Error, String),
2024-08-30 15:33:54 +02:00
BadNameError(String),
2024-09-02 11:28:00 +02:00
RunTimeError(String),
2024-09-02 12:02:19 +02:00
OpcodeError(String),
2024-09-02 11:28:00 +02:00
}
impl From<classfile::Error> for Error {
fn from(value: classfile::Error) -> Self {
return Error::ClassFileError(value);
}
2024-08-30 15:33:54 +02:00
}
impl From<classstore::Error> for Error {
fn from(value: classstore::Error) -> Self {
return Error::ClassStoreError(value);
}
}
impl ErrorTrait for Error {}
impl Display for Error {
fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
writeln!(formatter, "{self}")?;
if let Some(e) = self.source() {
writeln!(formatter, "\tCaused by: {e:?}")?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct JVM {
2024-09-02 15:42:42 +02:00
pub class_store: ClassStore,
pub stack_frames: Vec<StackFrame>,
pub heap_area: HeapArea,
2024-08-30 15:33:54 +02:00
}
impl JVM {
pub fn new() -> Self {
return JVM {
class_store: ClassStore::new(),
stack_frames: Vec::new(),
2024-09-02 15:42:42 +02:00
heap_area: HeapArea::new(usize::MAX),
2024-08-30 15:33:54 +02:00
}
}
2024-09-05 00:33:14 +02:00
fn class_native_class_data() -> JavaClassFile {
JavaClassFile {
minor_version: 0,
major_version: 0,
constant_pool: Box::new([
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 2 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "::NativeClassData".to_string() }),
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 4 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/Object".to_string() }),
]
),
access_flags: ClassAccessFlagMask { mask: ClassAccessFlag::Super.discriminant() },
this_class: 1,
super_class: 3,
interfaces: Box::new([]),
fields: Box::new([
FieldInfo {
access_flags: FieldAccessFlagMask {
mask: FieldAccessFlag::Public.discriminant()
},
name: "native_class_descriptor_index".to_string(),
descriptor: AbstractTypeDescription {
array_level: 0,
kind: AbstractTypeKind::Int(),
},
attributes: Box::new([]),
},
]),
methods: Box::new([]),
attributes: Box::new([]),
}
}
fn make_class_class(&mut self, class_name: &str) {
let class_object = self.heap_area.make_object(&self.class_store, self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap());
let class_data_object = self.heap_area.make_object(&self.class_store, self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap());
self.heap_area.object_area.set_object_field(
class_object,
"classData",
FieldValue::Reference(class_data_object),
self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap(),
&self.class_store,
).unwrap();
// set native name index on class data
self.heap_area.object_area.set_object_field(
class_data_object,
"native_class_descriptor_index",
2024-09-06 15:04:21 +02:00
FieldValue::Int(self.class_store.add_native_class_descriptor(class_name.to_string()) as i32),
2024-09-05 00:33:14 +02:00
self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap(),
&self.class_store,
).unwrap();
let parsed_class_name = match AbstractTypeDescription::parse_first(class_name).unwrap() {
(_, desc) => {
assert!(desc.array_level == 0);
match desc.kind {
AbstractTypeKind::Classname(name) => name,
_ => unreachable!(),
}
}
};
self.class_store.set_class_objectref_by_index(self.class_store.class_idx_from_name(&parsed_class_name).unwrap(), class_object);
}
fn make_array_class(&mut self, element_descriptor_string: &str) {
let (chars_consumed, element_descriptor) = AbstractTypeDescription::parse_first(element_descriptor_string).unwrap();
assert!(chars_consumed == element_descriptor_string.len());
let element_class_ref = if element_descriptor.array_level == 0 {
match element_descriptor.kind {
AbstractTypeKind::Classname(ref name) => {
self.class_store.get_class_objectref_from_index(
self.class_store.class_idx_from_name(&name).unwrap()
)
}
_ => unreachable!(),
}
} else {
self.class_store.get_array_class_ref(&element_descriptor).unwrap()
};
let array_class_object = self.heap_area.make_object(&self.class_store, 6);
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,
kind: element_descriptor.kind,
};
// set component type
self.heap_area.object_area.set_object_field(
array_class_object,
"componentType",
FieldValue::Reference(element_class_ref),
self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap(),
&self.class_store,
).unwrap();
// set classdata object
self.heap_area.object_area.set_object_field(
array_class_object,
"classData",
FieldValue::Reference(array_class_data_object),
self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap(),
&self.class_store,
).unwrap();
// set native name index on class data
self.heap_area.object_area.set_object_field(
array_class_data_object,
"native_class_descriptor_index",
2024-09-06 15:04:21 +02:00
FieldValue::Int(self.class_store.add_native_class_descriptor((&array_type_description).into()) as i32),
2024-09-05 00:33:14 +02:00
self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap(),
&self.class_store,
).unwrap();
self.class_store.put_array_class_ref(
array_type_description,
array_class_object,
);
}
pub fn entrypoint(&mut self, class_name: &String, method_name: &String, arguments: &[&str]) -> Result<(), Error> {
2024-09-02 11:28:00 +02:00
let entry_class = JavaClassFile {
minor_version: 0,
major_version: 0,
constant_pool: Box::new([
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 2 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "::EntryPoint".to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "Code".to_string() }),
ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 5, name_and_type_index: 6}),
2024-09-05 00:33:14 +02:00
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 7 }), // 5
2024-09-02 11:28:00 +02:00
ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 8, descriptor_index: 9 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: class_name.to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: method_name.to_string() }),
2024-09-06 21:11:03 +02:00
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "([Ljava/lang/String;)V".to_string() }),
2024-09-05 00:33:14 +02:00
ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 11, name_and_type_index: 13}), // 10
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 12 } ),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/String".to_string() }),
ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 14, descriptor_index: 15 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "<init>".to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "([B)V".to_string() }), // 15
2024-09-02 11:28:00 +02:00
]
),
access_flags: ClassAccessFlagMask { mask: ClassAccessFlag::Super.discriminant() },
this_class: 1,
super_class: 0,
interfaces: Box::new([]),
fields: Box::new([]),
methods: Box::new([
MethodInfo {
access_flags: MethodAccessFlagMask {
mask: MethodAccessFlag::Public.discriminant() | MethodAccessFlag::Static.discriminant()
},
name: "call_main".to_string(),
descriptor: MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription {
array_level: 0,
kind: AbstractTypeKind::Void(),
}
},
code_attribute_index: 0,
attributes: Box::new([
AttributeInfo {
attribute_name_index: 3,
data: AttributeData::Code(
CodeAttributeData {
2024-09-06 21:11:03 +02:00
max_stack: 1,
2024-09-05 00:33:14 +02:00
max_locals: 1,
2024-09-02 11:28:00 +02:00
code: Bytecode {
bytes: Box::new([
2024-09-06 21:11:03 +02:00
0x2A_u8.to_be(), // aload_0
2024-09-02 11:28:00 +02:00
0xB8_u8.to_be(), // invokestatic
0x04_u16.to_be_bytes()[0], // index 4 into the constant
0x04_u16.to_be_bytes()[1], // pool
]),
},
exception_table: Box::new([]),
attributes: Box::new([]),
}
)
}
])
2024-09-05 00:33:14 +02:00
},
2024-09-02 11:28:00 +02:00
]),
attributes: Box::new([]),
};
2024-09-06 15:04:21 +02:00
2024-09-05 00:33:14 +02:00
self.class_store.add_class(entry_class, true)?; // 0
2024-09-06 21:11:03 +02:00
self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1
2024-09-05 00:33:14 +02:00
self.class_store.load_class(&"java/lang/Object".to_string())?; // 2
self.class_store.load_class(&"java/lang/Number".to_string())?; // 3
self.class_store.load_class(&"java/lang/Byte".to_string())?; // 4
self.class_store.load_class(&"java/lang/String".to_string())?; // 5
self.class_store.load_class(&"java/lang/Class".to_string())?; // 6
self.make_class_class("Ljava/lang/Byte;");
self.make_class_class("Ljava/lang/String;");
self.make_array_class("Ljava/lang/Byte;");
self.make_array_class("Ljava/lang/String;");
2024-09-06 15:04:21 +02:00
self.heap_area.fill_byte_cache(&self.class_store);
let string_refs = arguments.iter()
.map(|s| self.heap_area.make_handmade_string(&s.to_string(), &self.class_store))
.collect();
let argument_array_ref = self.heap_area.make_array(&self.class_store, string_refs);
2024-09-02 11:28:00 +02:00
2024-09-03 00:49:28 +02:00
2024-09-05 00:33:14 +02:00
// push the entry frame which will call main
2024-09-06 15:04:21 +02:00
let entry_frame = StackFrame::new(self.class_store.get_class(&String::from("::EntryPoint")).unwrap().0, 0, 0, &[StackValue::Reference(argument_array_ref)]);
2024-09-05 00:33:14 +02:00
self.stack_frames.push(entry_frame);
2024-09-02 11:28:00 +02:00
Ok(())
}
pub fn run(&mut self) -> Result<(), Error> {
while self.stack_frames.len() != 0 {
2024-09-05 00:33:14 +02:00
println!("Enter bytecode loop:");
2024-09-02 11:28:00 +02:00
let jvm_op = self.bytecode_loop()?;
match jvm_op {
2024-09-02 15:42:42 +02:00
JVMCallbackOperation::PopFrame() => {
self.stack_frames.truncate(self.stack_frames.len() - 1)
},
JVMCallbackOperation::ReturnFrame(value) => {
// Pop returning frame
self.stack_frames.truncate(self.stack_frames.len() - 1);
let frame = {
let frame_index = self.stack_frames.len() - 1;
&mut self.stack_frames[frame_index]
};
let class = self.class_store.class_file_from_idx(frame.class_index).unwrap();
let method = & class.methods[frame.method_index as usize];
wrap_stackframe_error(class, method, self.stack_frames.last_mut().unwrap().operand_stack.push(value))?;
}
2024-09-02 11:28:00 +02:00
JVMCallbackOperation::PushFrame(frame) => self.stack_frames.push(frame),
2024-09-02 15:42:42 +02:00
2024-09-02 11:28:00 +02:00
JVMCallbackOperation::LoadClass(name) => {
2024-09-03 00:49:28 +02:00
// TODO: throw exception
self.load_class_hierarchy(&name)?;
2024-09-02 11:28:00 +02:00
},
2024-09-02 15:42:42 +02:00
2024-09-02 11:28:00 +02:00
JVMCallbackOperation::InitClass(name) => {
2024-09-03 00:49:28 +02:00
// TODO: throw exception
self.init_class_hierarchy(&name)?;
2024-09-05 00:33:14 +02:00
},
JVMCallbackOperation::MakeArrayClass(component_descriptor_string) => {
self.make_array_class(&component_descriptor_string);
2024-09-02 11:28:00 +02:00
}
}
}
Ok(())
}
2024-09-03 00:49:28 +02:00
fn load_class_hierarchy(&mut self, name: &String) -> Result<(), Error> {
2024-09-05 00:33:14 +02:00
let mut waiting_queue = VecDeque::new();
waiting_queue.push_back(name.clone());
while waiting_queue.len() != 0 {
let class_name = waiting_queue.pop_front().unwrap();
if ! self.class_store.have_class(&class_name) {
println!("Loading Class {class_name}");
self.class_store.load_class(&class_name)?;
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());
}
2024-09-03 00:49:28 +02:00
2024-09-05 00:33:14 +02:00
for interface_index in &file.interfaces {
let interface_name = file.gather_class(*interface_index)?;
waiting_queue.push_back(interface_name.to_string());
2024-09-03 00:49:28 +02:00
}
}
}
Ok(())
}
fn init_class_hierarchy(&mut self, name: &String) -> Result<(), Error> {
let mut class_stack = vec![name.to_string()];
while class_stack.len() != 0 {
let current_name = class_stack.pop().unwrap();
let was_super_init = {
let (file, _) = self.class_store.get_class(&current_name)?;
if ! file.has_super_class() {
true
} else {
let super_name = file.get_super_class_name()?;
self.class_store.was_init(super_name).unwrap()
}
};
if was_super_init {
let class_idx = self.class_store.class_idx_from_name(&current_name).unwrap();
self.init_class(class_idx)?;
} else {
let super_name = {
let (file, _) = self.class_store.get_class(&current_name)?;
file.get_super_class_name()?
};
class_stack.push(current_name);
class_stack.push(super_name.to_string());
}
}
Ok(())
}
fn init_class(&mut self, class_idx: usize) -> Result<(), Error> {
2024-09-05 00:33:14 +02:00
{
let class_file = self.class_store.class_file_from_idx(class_idx).unwrap();
self.heap_area.make_static(class_file, class_idx);
for field in &class_file.fields {
if field.access_flags & FieldAccessFlag::Static {
let cvalue_attrs: Vec<&ConstantValueAttributeData> = (&field.attributes).iter()
.filter(|a| match a.data { AttributeData::ConstantValue(_) => true, _ => false })
.map(|a| match &a.data { AttributeData::ConstantValue(c) => c, _ => unreachable!() })
.collect();
assert!(cvalue_attrs.len() < 2);
// TODO: Throw error
if cvalue_attrs.len() == 1 {
let constant_value_info = cvalue_attrs[0];
assert!(field.descriptor.array_level == 0);
// TODO: Throw Error
let field_value = match field.descriptor.kind {
AbstractTypeKind::Boolean() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
FieldValue::Boolean(int_entry.value != 0)
},
AbstractTypeKind::Byte() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
FieldValue::Byte(int_entry.value as u8)
},
AbstractTypeKind::Char() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
FieldValue::Char(int_entry.value as u16)
},
AbstractTypeKind::Int() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
FieldValue::Int(int_entry.value)
},
AbstractTypeKind::Short() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
FieldValue::Short(int_entry.value as i16)
},
AbstractTypeKind::Long() => {
let long_entry = class_file.pool_long_entry(constant_value_info.constant_value_index)?;
FieldValue::Long(long_entry.value)
},
AbstractTypeKind::Classname(ref name) => {
if name == "java/lang/String" {
let string_entry = class_file.gather_string(constant_value_info.constant_value_index)?;
2024-09-06 15:04:21 +02:00
let string_object = self.heap_area.make_handmade_string(string_entry, &self.class_store);
2024-09-05 00:33:14 +02:00
FieldValue::Reference(string_object)
} else {
todo!()
}
},
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
_ => {
println!("{:?}", field.descriptor.kind);
todo!()
},
};
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
self.heap_area.static_area.set(class_file.get_classname()?, &field.name, field_value)?;
}
}
}
}
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
// class object
self.make_class_class(&("L".to_owned() + &self.class_store.class_file_from_idx(class_idx).unwrap().get_classname()?.clone() + ";"));
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
// Push clinit function
let class_file = self.class_store.class_file_from_idx(class_idx).unwrap();
let clinit_idx = class_file.find_method_index(&"<clinit>".to_string());
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
if let Some(method_index) = clinit_idx {
let clinit_frame = StackFrame::new(
class_file,
class_idx,
method_index as u16,
&[],
);
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
self.stack_frames.push(clinit_frame);
2024-09-02 19:28:22 +02:00
}
2024-09-05 00:33:14 +02:00
// finish
2024-09-02 12:02:19 +02:00
self.class_store.set_init(class_idx, true);
2024-09-02 17:44:59 +02:00
Ok(())
2024-08-30 15:33:54 +02:00
}
2024-09-02 11:28:00 +02:00
fn bytecode_loop(&mut self) -> Result<JVMCallbackOperation, Error> {
let frame = {
let frame_index = self.stack_frames.len() - 1;
&mut self.stack_frames[frame_index]
};
let class = self.class_store.class_file_from_idx(frame.class_index).unwrap();
let method = & class.methods[frame.method_index as usize];
let code_attr = method.get_code_attribute().unwrap();
let bytecode = & code_attr.code;
while frame.instruction_pointer as usize != bytecode.bytes.len() {
let (instruction, offset) = bytecode.next_instruction(frame.instruction_pointer as usize);
frame.instruction_pointer += offset as u32;
2024-09-05 00:33:14 +02:00
println!("{:25}.{:15}:{:<10}{instruction:?}", class.get_classname().unwrap(), method.name, frame.instruction_pointer);
2024-09-02 11:28:00 +02:00
match instruction {
2024-09-05 00:33:14 +02:00
2024-09-06 21:11:03 +02:00
Instruction::ArrayLength() => {
let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
let array_length = self.heap_area.object_area.get_array_length(array_reference);
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(array_length as i32)))?;
},
Instruction::ArrayElement() => {
let element_index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
let element = self.heap_area.object_area.get_array_element(array_reference, element_index);
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(element)))?;
},
Instruction::BranchAlways(branch_offset) => {
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::BranchZero(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};
}
}
2024-09-05 00:33:14 +02:00
Instruction::Duplicate() => {
let popped_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(popped_value))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(popped_value))?;
}
2024-09-06 21:11:03 +02:00
Instruction::GetField(fieldref_index) => {
let (class_name, field_name, field_descriptor) = class.gather_fieldref(fieldref_index).unwrap();
let this_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
// 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_descriptor = AbstractTypeDescription {
array_level: 0,
kind: AbstractTypeKind::Classname(this_object_class_name.clone())
};
let object_descriptor = AbstractTypeDescription {
array_level: 0,
kind: AbstractTypeKind::Classname(class_name.to_string())
};
if ! self.class_store.are_types_compatible(&this_object_descriptor, &object_descriptor) {
return Err(Error::RunTimeError(format!(
"GetField: Cannot fetch '{field_name}' from class '{class_name}' on instance from class '{}: Types are incompatible'",
this_object_class_name
)))
}
let fetched_value = self.heap_area.object_area.get_object_field(this_object, field_name, frame.class_index, &self.class_store).unwrap();
// println!("{fetched_value:?} {field_descriptor}");
// TODO: Check field and value compatability
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(fetched_value))?;
}
Instruction::GetStatic(fieldref_index) => {
let (class_name, field_name, field_descriptor) = class.gather_fieldref(fieldref_index).unwrap();
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()));
}
// TODO: Throw error
let parsed_field_descriptor = AbstractTypeDescription::parse_full(field_descriptor).unwrap();
// TODO: Throw error
let fetched_value = self.heap_area.static_area.get(class_name, field_name, parsed_field_descriptor).unwrap();
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(fetched_value))?;
}
2024-09-05 00:33:14 +02:00
Instruction::InvokeSpecial(methodref_index) => {
2024-09-06 21:11:03 +02:00
// No instance-based dispatch
2024-09-05 00:33:14 +02:00
let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref(methodref_index)?;
if ! self.class_store.have_class(supplied_class_name) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(supplied_class_name.to_string()));
}
if ! self.class_store.was_init(supplied_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(supplied_class_name.to_string()));
}
let target_class_index = self.class_store.class_idx_from_name(supplied_class_name).unwrap();
let parsed_expected_descriptor: MethodDescriptor = MethodDescriptor::try_from(supplied_descriptor_string)?;
let (class_index, method_index, method_info) = match ClassMethodIterator::new(target_class_index, &self.class_store)
.filter(|(_cid, _mid, minfo)| minfo.name == *supplied_method_name)
.filter(|(_cid, _mid, minfo)| minfo.descriptor == parsed_expected_descriptor)
.next() {
Some(m) => m,
None => {
// TODO: Throw exception
return Err(Error::RunTimeError(format!("InvokeSpecial: Failed to find requested method '{}' with descriptor '{}' in the class '{}'", supplied_method_name, supplied_descriptor_string, supplied_class_name)));
}
};
let mut arguments = VecDeque::new();
fill_arguments(class, method, &mut arguments, &method_info.descriptor.argument_types, &mut frame.operand_stack)?;
// this
arguments.push_front(
StackValue::Reference(
wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?
)
);
let new_frame = StackFrame::new(
self.class_store.class_file_from_idx(class_index).unwrap(),
class_index,
method_index as u16,
&arguments.make_contiguous(),
);
return Ok(JVMCallbackOperation::PushFrame(new_frame));
},
2024-09-02 11:28:00 +02:00
Instruction::InvokeStatic(methodref_index) => {
let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref(methodref_index)?;
if ! self.class_store.have_class(supplied_class_name) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(supplied_class_name.to_string()));
}
if ! self.class_store.was_init(supplied_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(supplied_class_name.to_string()));
}
let (callee_class_file, callee_class_index) = self.class_store.get_class(supplied_class_name)?;
// TODO: Throw exception on fail
let callee_method_index = callee_class_file.find_method_index(supplied_method_name).unwrap();
// TODO: Throw exception on fail
let callee_method_info = &callee_class_file.methods[callee_method_index];
2024-09-02 12:02:19 +02:00
if ! (callee_method_info.access_flags & MethodAccessFlag::Static) {
// TODO: Throw IncompatibleClassChangeError
return Err(Error::RunTimeError(format!(
"Invoked method '{}' in class '{}' does not have Access::Static (from invokestatic from '{}' in class '{}')",
method.name,
class.get_classname().unwrap(),
supplied_method_name,
supplied_class_name,
)));
}
2024-09-02 11:28:00 +02:00
let supplied_descriptor: MethodDescriptor = supplied_descriptor_string.try_into()?;
// TODO: Throw exception on fail
if supplied_descriptor != callee_method_info.descriptor {
// TODO: Throw exception on fail
return Err(Error::RunTimeError(format!(
"Mismatched method descriptors between caller and callee: Caller ({}) wanted '{}' but found '{}' on Callee ({})",
class.get_classname().unwrap(),
supplied_descriptor_string,
callee_method_info.descriptor.source_string(),
supplied_class_name,
)));
}
2024-09-02 15:42:42 +02:00
let mut arguments = VecDeque::new();
fill_arguments(class, method, &mut arguments, &callee_method_info.descriptor.argument_types, &mut frame.operand_stack)?;
2024-09-02 11:28:00 +02:00
let new_frame = StackFrame::new(
callee_class_file,
callee_class_index,
callee_method_index as u16,
2024-09-02 15:42:42 +02:00
&arguments.make_contiguous(),
2024-09-02 11:28:00 +02:00
);
return Ok(JVMCallbackOperation::PushFrame(new_frame));
},
2024-09-06 21:11:03 +02:00
Instruction::InvokeVirtual(methodref_index) => {
let (base_class_name, base_method_name, base_descriptor_string) = class.gather_methodref(methodref_index)?;
if ! self.class_store.have_class(base_class_name) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(base_class_name.to_string()));
}
if ! self.class_store.was_init(base_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(base_class_name.to_string()));
}
let base_descriptor = MethodDescriptor::try_from(base_descriptor_string).unwrap();
// extract arguments, they are on top of the stack
let mut arguments = VecDeque::new();
fill_arguments(class, method, &mut arguments, &base_descriptor.argument_types, &mut frame.operand_stack)?;
let this_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
arguments.push_front(StackValue::Reference(this_object));
// 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_descriptor = AbstractTypeDescription {
array_level: 0,
kind: AbstractTypeKind::Classname(this_object_class_name.clone())
};
let base_object_descriptor = AbstractTypeDescription {
array_level: 0,
kind: AbstractTypeKind::Classname(base_class_name.to_string())
};
// TODO: Throw error
if ! self.class_store.are_types_compatible(&this_object_descriptor, &base_object_descriptor) {
return Err(Error::RunTimeError(format!(
"InvokeVirtual: Cannot call '{base_method_name}' from class '{base_class_name}' on instance from class '{}: Types are incompatible'",
this_object_class_name
)))
}
let (invoked_class_index, invoked_method_index, _invoked_method_info) = match ClassMethodIterator::new(this_object_class_index, &self.class_store)
.filter(|(_, _, method_info)| method_info.name == *base_method_name)
.filter(|(_, _, method_info)| method_info.descriptor == base_descriptor)
.next()
{
Some(t) => t,
None => {
return Err(Error::RunTimeError(format!(
"InvokeVirtual: Failed to find requested method '{}' with descriptor '{}' in the type hierarchy of '{}'",
base_method_name,
base_descriptor_string,
this_object_class_name,
)));
},
};
let invoked_class_file = self.class_store.class_file_from_idx(invoked_class_index).unwrap();
let new_frame = StackFrame::new(
invoked_class_file,
invoked_class_index,
invoked_method_index as u16,
arguments.make_contiguous()
);
return Ok(JVMCallbackOperation::PushFrame(new_frame));
},
2024-09-02 15:42:42 +02:00
Instruction::LoadByteImmediate(byte) => {
// sign extend into int
let i8_int = i8::from_be_bytes([byte]);
2024-09-02 17:46:00 +02:00
let frame_result = frame.operand_stack.push(StackValue::Int(i8_int as i32));
2024-09-02 15:42:42 +02:00
match frame_result {
Ok(_) => (),
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),
}
},
Instruction::LoadLocalInt0() => {
load_local_int(class, method, frame, 0)?;
}
Instruction::LoadLocalInt1() => {
load_local_int(class, method, frame, 1)?;
}
Instruction::LoadLocalInt2() => {
load_local_int(class, method, frame, 2)?;
}
Instruction::LoadLocalInt3() => {
load_local_int(class, method, frame, 3)?;
}
2024-09-05 00:33:14 +02:00
Instruction::LoadLocalReference0() => {
load_local_reference(class, method, frame, 0)?;
}
2024-09-06 21:11:03 +02:00
Instruction::LoadLocalReference1() => {
load_local_reference(class, method, frame, 1)?;
}
Instruction::LoadLocalReference2() => {
load_local_reference(class, method, frame, 2)?;
}
Instruction::LoadLocalReference3() => {
load_local_reference(class, method, frame, 3)?;
}
2024-09-05 00:33:14 +02:00
2024-09-02 15:42:42 +02:00
Instruction::MultiplyInt() => {
let factor_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let factor_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
2024-09-02 17:46:00 +02:00
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(factor_1 * factor_2)))?;
2024-09-02 15:42:42 +02:00
}
2024-09-05 00:33:14 +02:00
Instruction::NewArray(class_index) => {
// construct single level array
let class_name = class.gather_class(class_index)?;
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 class_descriptor = AbstractTypeDescription {
array_level: 0,
kind: match class_name {
_ => AbstractTypeKind::Classname(class_name.to_string())
}
};
let array_descriptor = AbstractTypeDescription {
array_level: 1,
kind: class_descriptor.kind.clone(),
};
if let None = self.class_store.get_array_class_ref(&array_descriptor) {
let complete_type_descriptor = format!("L{};", class_name);
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::MakeArrayClass(complete_type_descriptor));
}
let array_capacity = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let array_ref = self.heap_area.make_empty_array(&self.class_store, class_descriptor, array_capacity as usize);
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(array_ref)))?;
}
Instruction::NewObject(class_index) => {
let class_name = class.gather_class(class_index)?;
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 class_index = self.class_store.class_idx_from_name(class_name).unwrap();
let new_object = self.heap_area.make_object(&self.class_store, class_index);
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(new_object)))?;
},
Instruction::PushConstInt0() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?;
}
Instruction::PushConstInt1() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(1)))?;
}
Instruction::PushConstInt2() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(2)))?;
}
Instruction::PushConstInt3() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(3)))?;
}
Instruction::PushConstInt4() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(4)))?;
}
2024-09-02 15:42:42 +02:00
Instruction::PushConstInt5() => {
2024-09-05 00:33:14 +02:00
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(5)))?;
}
Instruction::PutStatic(fieldref_index) => {
let (target_class_name, target_field_name, expected_field_descriptor) = class.gather_fieldref(fieldref_index)?;
if ! self.class_store.have_class(target_class_name) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(target_class_name.to_string()));
}
if ! self.class_store.was_init(target_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(target_class_name.to_string()));
}
let matched_field = match ClassFieldIterator::new(self.class_store.class_idx_from_name(target_class_name).unwrap(), &self.class_store)
.filter(|f| f.name == *target_field_name)
.filter(|f| f.access_flags & FieldAccessFlag::Static)
.next() {
Some(f) => f,
None => return Err(Error::RunTimeError(format!("PutStatic: Trying to set field '{}' on class '{}' but there is no such static field", target_field_name, target_class_name)))
};
let (consumed_chars, expected_descriptor) = AbstractTypeDescription::parse_first(expected_field_descriptor)?;
assert!(expected_field_descriptor.len() == consumed_chars);
// TODO: Throw exception on fail
if matched_field.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("PutStatic: Field descriptor mismatch: '{expected_descriptor:?}' but found '{:?}'", matched_field.descriptor)))
2024-09-02 15:42:42 +02:00
}
2024-09-05 00:33:14 +02:00
let set_value = match (matched_field.descriptor.array_level, &matched_field.descriptor.kind) {
(0, AbstractTypeKind::Boolean()) => {
let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
FieldValue::Boolean((int_value & 1) != 0)
},
(0..=255, AbstractTypeKind::Classname(_field_type_name)) => {
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
let value_native_name = self.heap_area.object_area.get_reference_native_class_name(ref_value, &self.class_store);
let parsed_native_name = AbstractTypeDescription::parse_first(value_native_name).unwrap().1;
if ! self.class_store.are_types_compatible(&matched_field.descriptor, &parsed_native_name) {
return Err(Error::RunTimeError(format!("PutStatic: Trying to set a value with type '{parsed_native_name:?}' on a field with type '{:?}'", matched_field.descriptor)));
}
FieldValue::Reference(ref_value)
}
_ => {
println!("{:?}", matched_field);
todo!()
},
};
self.heap_area.static_area.set(target_class_name, target_field_name, set_value)?;
2024-09-02 15:42:42 +02:00
}
Instruction::ReturnInt() => {
2024-09-06 21:11:03 +02:00
match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) {
(_, AbstractTypeKind::Byte() | AbstractTypeKind::Boolean()| AbstractTypeKind::Int() | AbstractTypeKind::Char() | AbstractTypeKind::Short()) => (),
_ => return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type)))
2024-09-02 15:42:42 +02:00
}
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
2024-09-02 17:46:00 +02:00
return Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(int)));
2024-09-02 15:42:42 +02:00
}
2024-09-02 12:02:19 +02:00
Instruction::ReturnVoid() => {
let expected_type = AbstractTypeDescription {
array_level: 0,
kind: AbstractTypeKind::Void(),
};
if method.descriptor.return_type != expected_type {
return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type)))
}
return Ok(JVMCallbackOperation::PopFrame());
},
2024-09-06 21:11:03 +02:00
Instruction::ShiftIntRight() => {
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))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int >> shift)))?;
},
2024-09-02 15:42:42 +02:00
Instruction::StoreLocalInt0() => {
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
2024-09-02 17:46:00 +02:00
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Int(int)))?;
2024-09-02 15:42:42 +02:00
},
Instruction::StoreLocalInt1() => {
2024-09-05 00:33:14 +02:00
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
2024-09-02 15:42:42 +02:00
2024-09-05 00:33:14 +02:00
wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Int(int)))?;
2024-09-02 15:42:42 +02:00
},
Instruction::StoreLocalInt2() => {
2024-09-05 00:33:14 +02:00
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
2024-09-02 15:42:42 +02:00
2024-09-05 00:33:14 +02:00
wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Int(int)))?;
2024-09-02 15:42:42 +02:00
},
Instruction::StoreLocalInt3() => {
2024-09-05 00:33:14 +02:00
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
2024-09-02 15:42:42 +02:00
2024-09-05 00:33:14 +02:00
wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Int(int)))?;
2024-09-02 15:42:42 +02:00
},
2024-09-06 21:11:03 +02:00
Instruction::StoreReference0() => {
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Reference(reference)))?;
},
Instruction::StoreReference1() => {
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Reference(reference)))?;
},
Instruction::StoreReference2() => {
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Reference(reference)))?;
},
Instruction::StoreReference3() => {
let reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Reference(reference)))?;
},
2024-09-02 11:28:00 +02:00
_ => {
return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction)))
},
}
}
2024-09-02 15:42:42 +02:00
// TODO: Review this, maybe crash when there is no return?
2024-09-02 11:28:00 +02:00
Ok(JVMCallbackOperation::PopFrame())
}
}
enum JVMCallbackOperation {
PopFrame(),
2024-09-02 17:46:00 +02:00
ReturnFrame(StackValue),
2024-09-02 11:28:00 +02:00
PushFrame(StackFrame),
LoadClass(String),
InitClass(String),
2024-09-05 00:33:14 +02:00
MakeArrayClass(String),
}
fn load_local_reference(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {
let loaded_value = wrap_stackframe_error(class, method, frame.load_local_reference(index as u16))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(loaded_value)))?;
Ok(())
2024-08-30 15:33:54 +02:00
}
2024-09-02 15:42:42 +02:00
fn load_local_int(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {
2024-09-05 00:33:14 +02:00
let loaded_value = wrap_stackframe_error(class, method, frame.load_local_int(index as u16))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(loaded_value)))?;
Ok(())
2024-09-02 15:42:42 +02:00
}
2024-09-02 17:46:00 +02:00
fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut VecDeque<StackValue>, argument_types: &Box<[AbstractTypeDescription]>, stack: &mut OperandStack) -> Result<(), Error> {
2024-09-02 15:42:42 +02:00
for argument_type in argument_types {
if argument_type.array_level != 0 {
// TODO: Type checking
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Reference(wrap_stackframe_error(class, method, stack.pop_reference(0))?),
2024-09-02 15:42:42 +02:00
)
} else {
match argument_type.kind {
AbstractTypeKind::Void() => return Err(Error::RunTimeError("Functions cannot take arguments of type void".to_string())),
// TODO: Add better description
AbstractTypeKind::Byte() => {
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Byte(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_byte(0)
)?
)
)
},
AbstractTypeKind::Char() => {
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Char(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_char(0)
)?
)
)
},
AbstractTypeKind::Double() => {
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Double1(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_double1(0)
)?
)
);
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Double0(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_double0(0)
)?
)
);
},
AbstractTypeKind::Float() => {
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Float(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_float(0)
)?
)
)
},
AbstractTypeKind::Int() => {
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Int(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_int(0)
)?
)
)
},
AbstractTypeKind::Long() => {
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Long1(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_long1(0)
)?
)
);
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Long0(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_long0(0)
)?
)
);
},
AbstractTypeKind::Classname(ref name) => {
// TODO: Type checking
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Reference(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_reference(0)
)?
)
)
},
AbstractTypeKind::Short() => {
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Short(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_short(0)
)?
)
)
},
AbstractTypeKind::Boolean() => {
arguments.push_front(
2024-09-02 17:46:00 +02:00
StackValue::Boolean(
2024-09-02 15:42:42 +02:00
wrap_stackframe_error(
class,
method,
stack.pop_boolean(0)
)?
)
)
},
}
}
}
Ok(())
}
fn wrap_stackframe_error<T>(class: &JavaClassFile, method: &MethodInfo, frame_result: Result<T, stackframe::Error>) -> Result<T, Error> {
match frame_result {
Ok(t) => Ok(t),
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),
}
}