Implemented catchall in ::EntryPoint

This commit is contained in:
VegOwOtenks 2024-11-12 13:29:01 +01:00
parent 6b03cab14d
commit f5428c79b2
3 changed files with 109 additions and 8 deletions

View file

@ -391,6 +391,23 @@ impl JavaClassFile {
},
}
}
pub fn is_method_bytecode_protected(&self, method: &MethodInfo, instruction_pointer: u16, exception: crate::heap_area::ObjectReference) -> bool {
let code_attribute = method.get_code_attribute().unwrap();
for exception_entry in &code_attribute.exception_table {
if exception_entry.start_pc <= instruction_pointer && exception_entry.end_pc > instruction_pointer {
if exception_entry.catch_type == 0 {
return true;
} else {
// Check catch-type
todo!()
}
}
}
false
}
}
#[derive(Debug)]
@ -500,10 +517,10 @@ impl LineNumberTableAttributeData {
#[derive(Debug)]
pub struct ExceptionTableEntry {
start_pc: u16,
end_pc: u16,
handler_pc: u16,
catch_type: u16,
pub start_pc: u16,
pub end_pc: u16,
pub handler_pc: u16,
pub catch_type: u16,
}
impl ExceptionTableEntry {
@ -517,6 +534,10 @@ impl ExceptionTableEntry {
}
)
}
fn catches_in(&self, instruction_pointer: u16) -> bool {
return self.start_pc <= instruction_pointer && self.end_pc > instruction_pointer
}
}
#[derive(Debug)]
@ -1128,6 +1149,20 @@ impl MethodInfo {
None
};
}
pub fn is_native(&self) -> bool {
return self.access_flags & MethodAccessFlag::Native;
}
pub fn get_protected_handler_pc(&self, instruction_pointer: u16) -> Option<u16> {
for exception_entry in &self.get_code_attribute()?.exception_table {
if exception_entry.catches_in(instruction_pointer) {
return Some(exception_entry.handler_pc)
}
}
None
}
}

View file

@ -1,3 +1,4 @@
use crate::classfile::ExceptionTableEntry;
use core::fmt::{Display, Formatter};
use std::collections::VecDeque;
@ -9,7 +10,7 @@ use crate::classfile;
use crate::classfile::{ JavaClassFile, FieldInfo, MethodInfo, MethodDescriptor, AbstractTypeDescription, AbstractTypeKind, AttributeInfo, AttributeData, CodeAttributeData, ConstantValueAttributeData };
use crate::classstore;
use crate::classstore::ClassStore;
use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo};
use crate::constantpool::{ ConstantClassInfo, ConstantInterfaceMethodRefInfo, ConstantMethodRefInfo, ConstantNameAndTypeInfo, ConstantPoolInfo, ConstantUtf8Info};
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference, CompartmentEntry };
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator };
use crate::native_methods;
@ -259,7 +260,12 @@ impl JVM {
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 18 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/System".to_string() }),
ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 20, descriptor_index: 13 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "initPhase1".to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "initPhase1".to_string() }), // 20
ConstantPoolInfo::InterfaceMethodRef(ConstantInterfaceMethodRefInfo { class_index: 22, name_and_type_index: 24}),
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 23 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/Throwable".to_string() }),
ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 25, descriptor_index: 13 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "printStackTrace".to_string() }), // 25
]
),
access_flags: ClassAccessFlagMask { mask: ClassAccessFlag::Super.discriminant() },
@ -309,9 +315,24 @@ impl JVM {
0xB8_u8.to_be(), // invokestatic
0x04_u16.to_be_bytes()[0], // index 4 into the constant
0x04_u16.to_be_bytes()[1], // pool
0xB1_u8.to_be(), // returnvoid
// index 14
0xB9_u8.to_be(), // invokeinterface
21_u16.to_be_bytes()[0], // index 21 constant
21_u16.to_be_bytes()[1], // index 21 constant
0x00_u8.to_be(), // constant 0
]),
},
exception_table: Box::new([]),
exception_table: Box::new([
ExceptionTableEntry {
start_pc: 0,
end_pc: u16::MAX,
handler_pc: 14,
catch_type: 0, // Catchall
}
]),
attributes: Box::new([]),
}
)
@ -460,6 +481,43 @@ impl JVM {
JVMCallbackOperation::MakeArrayClass(component_class_ref, component_descriptor) => {
self.make_array_class(component_class_ref, component_descriptor);
}
JVMCallbackOperation::ThrowException(exception) => {
let mut is_handler_found = false;
while ! is_handler_found {
is_handler_found = {
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];
if method.is_native() {
false
} else {
class.is_method_bytecode_protected(method, frame.instruction_pointer as u16, exception)
}
};
if ! is_handler_found {
self.stack_frames.pop();
}
}
if is_handler_found {
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];
frame.operand_stack.clear();
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(exception)))?;
frame.instruction_pointer = method.get_protected_handler_pc(frame.instruction_pointer as u16).unwrap() as u32;
} else {
unreachable!()
}
}
}
}
@ -2281,7 +2339,10 @@ impl JVM {
Instruction::ThrowException() => {
let exception = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
if exception == ObjectReference::NULL {
// TODO: Throw NullPointerException
} else {
// TODO: Check throwable instance
return Ok(JVMCallbackOperation::ThrowException(exception));
}
}
@ -2312,6 +2373,7 @@ pub enum JVMCallbackOperation {
LoadClass(String),
InitClass(String),
MakeArrayClass(ObjectReference, AbstractTypeDescription),
ThrowException(ObjectReference),
}
fn load_local_reference(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {

View file

@ -47,6 +47,10 @@ impl OperandStack {
}
}
pub fn clear(&mut self) -> () {
self.depth = 0
}
pub fn push(&mut self, value: StackValue) -> Result<(), Error> {
if self.depth as usize == self.stack.len() {
return Err(Error::PushError(format!("Trying to push onto full operand stack, capacity: {}, value: {:?}", self.depth, value)))