Native method registry java.lang.Class wtf

This commit is contained in:
vegowotenks 2024-09-09 15:43:26 +02:00
parent 3282694b32
commit b4c428685f
9 changed files with 987 additions and 40 deletions

View file

@ -12,6 +12,9 @@ use crate::classstore::ClassStore;
use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo};
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference, CompartmentEntry };
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator };
use crate::native_methods;
use crate::native_methods::ignore_call;
use crate::native_registry::{ NativeRegistry };
use crate::stackframe;
use crate::stackframe::{ StackFrame, StackValue, OperandStack };
@ -53,6 +56,7 @@ pub struct JVM {
pub class_store: ClassStore,
pub stack_frames: Vec<StackFrame>,
pub heap_area: HeapArea,
pub native_registry: NativeRegistry,
}
impl JVM {
@ -61,9 +65,30 @@ impl JVM {
class_store: ClassStore::new(),
stack_frames: Vec::new(),
heap_area: HeapArea::new(usize::MAX),
native_registry: NativeRegistry::default(),
}
}
fn load_class(&mut self, class_name: &String) -> Result<usize, Error> {
let class_index = self.class_store.load_class(class_name)?;
let class_file = self.class_store.class_file_from_idx(class_index).unwrap();
for (method_name, method_implementation) in class_file.methods.iter()
.filter(|m| m.access_flags & MethodAccessFlag::Native)
.map(| m | (&m.name, native_methods::function_for(class_name, m))) {
let method_implementation = match method_implementation {
Ok(m) => m,
Err(e) => return Err(e)
};
self.native_registry.register(class_name, method_name, method_implementation);
}
Ok(class_index)
}
fn class_native_class_data() -> JavaClassFile {
JavaClassFile {
minor_version: 0,
@ -208,6 +233,10 @@ impl JVM {
primitive_class_object
}
fn register_native(&mut self, class_name: &str, method_name: &str, method_descriptor: &MethodDescriptor) {
self.native_registry.register("java/lang/System", "registerNatives", ignore_call);
}
pub fn entrypoint(&mut self, class_name: &String, method_name: &String, arguments: &[&str]) -> Result<(), Error> {
let entry_class = JavaClassFile {
minor_version: 0,
@ -278,11 +307,11 @@ impl JVM {
self.class_store.add_class(entry_class, true)?; // 0
self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1
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.load_class(&"java/lang/Object".to_string())?; // 2
self.load_class(&"java/lang/Number".to_string())?; // 3
self.load_class(&"java/lang/Byte".to_string())?; // 4
self.load_class(&"java/lang/String".to_string())?; // 5
self.load_class(&"java/lang/Class".to_string())?; // 6
self.make_class_class("Ljava/lang/Byte;");
self.make_class_class("Ljava/lang/String;");
@ -388,7 +417,7 @@ impl JVM {
if ! self.class_store.have_class(&class_name) {
println!("Loading Class {class_name}");
self.class_store.load_class(&class_name)?;
self.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());
@ -536,6 +565,25 @@ impl JVM {
Ok(())
}
fn native_call(&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 class_name = class.get_classname().unwrap();
let native_method = match self.native_registry.get(class_name, &method.name) {
Some(m) => m,
None => {
return Err(Error::RunTimeError(format!("Tried to call native method '{class_name}.{}' but there is no such method in the method registry", method.name)));
}
};
native_method(self)
}
fn bytecode_loop(&mut self) -> Result<JVMCallbackOperation, Error> {
let frame = {
@ -544,6 +592,11 @@ impl JVM {
};
let class = self.class_store.class_file_from_idx(frame.class_index).unwrap();
let method = & class.methods[frame.method_index as usize];
if method.access_flags & MethodAccessFlag::Native {
return self.native_call()
}
let code_attr = method.get_code_attribute().unwrap();
let bytecode = & code_attr.code;
@ -577,6 +630,16 @@ impl JVM {
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::BranchIntEquality(branch_offset) => {
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
if value_1 == value_2 {
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::BranchIntInequality(branch_offset) => {
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
@ -587,6 +650,24 @@ impl JVM {
}
}
Instruction::BranchNonNull(branch_offset) => {
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
if test_value != ObjectReference::NULL {
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::BranchNull(branch_offset) => {
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
if test_value == ObjectReference::NULL {
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))?;
@ -596,12 +677,29 @@ impl JVM {
}
}
Instruction::DivideInt() => {
// TODO: Obey all the rules
let quotient = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let divident = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
frame.operand_stack.push(StackValue::Int(divident / quotient)).unwrap();
}
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))?;
}
Instruction::EnterMonitor() => {
// TODO: Revisit this when doing multi-threading
let _monitored_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
}
Instruction::ExitMonitor() => {
// TODO: Revisit this when doing multi-threading
let _monitored_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
}
Instruction::GetField(fieldref_index) => {
let (class_name, field_name, field_descriptor) = class.gather_fieldref(fieldref_index).unwrap();
@ -742,6 +840,9 @@ impl JVM {
)));
}
if callee_method_info.access_flags & MethodAccessFlag::Native {
}
let supplied_descriptor: MethodDescriptor = supplied_descriptor_string.try_into()?;
// TODO: Throw exception on fail
@ -759,6 +860,7 @@ impl JVM {
let mut arguments = VecDeque::new();
fill_arguments(class, method, &mut arguments, &callee_method_info.descriptor.argument_types, &mut frame.operand_stack)?;
// TODO: Throw errors on abstract methods etc.
let new_frame = StackFrame::new(
callee_class_file,
callee_class_index,
@ -849,11 +951,93 @@ impl JVM {
Ok(_) => (),
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),
}
}
Instruction::LoadConstant(index) => {
// TODO: Handle error instead of unwrap
match class.pool_entry(index as u16).unwrap() {
ConstantPoolInfo::Class(_) => {
let class_name = class.gather_class(index as u16).unwrap();
if ! self.class_store.have_class(class_name) {
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(class_name.to_string()));
}
if ! self.class_store.was_init(class_name).unwrap() {
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 class_object_ref = self.class_store.get_class_objectref_from_index(class_index);
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(class_object_ref)))?;
}
ConstantPoolInfo::String(_) => {
// TODO: Handle error instead of unwrap
let string_constant = class.gather_string(index as u16).unwrap();
let string_obj_ref = self.heap_area.make_handmade_string(string_constant, &self.class_store);
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?;
},
_ => {
println!("{:?}", class.pool_entry(index as u16).unwrap());
todo!()
}
}
},
Instruction::LoadWideConstant(wide_index) => {
Instruction::LoadCostantWide(wide_index) => {
// TODO: Handle error instead of unwrap
match class.pool_entry(wide_index).unwrap() {
ConstantPoolInfo::Class(_) => {
let class_name = class.gather_class(wide_index).unwrap();
let class_object_ref = if class_name.starts_with('[') {
let component_name = class_name.trim_start_matches('[');
let array_level = class_name.len() - component_name.len();
let array_type_desc = AbstractTypeDescription {
array_level: array_level as u8,
kind: if component_name.len() == 1 {
component_name.into()
} else {
AbstractTypeKind::Classname(component_name.to_string())
}
};
if let Some(array_ref) = self.class_store.get_array_class_ref(&array_type_desc) {
array_ref
} else {
let mut test_type = array_type_desc.super_component();
let mut test_object_ref = self.class_store.class_ref_for_type(test_type.clone()).unwrap();
while let Some(new_test_object_ref) = self.class_store.class_ref_for_type(test_type.array()) {
test_type = test_type.array();
test_object_ref = new_test_object_ref;
}
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::MakeArrayClass(test_object_ref, test_type))
}
} else {
if ! self.class_store.have_class(class_name) {
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(class_name.to_string()));
}
if ! self.class_store.was_init(class_name).unwrap() {
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();
self.class_store.get_class_objectref_from_index(class_index)
};
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(class_object_ref)))?;
}
ConstantPoolInfo::String(_) => {
// TODO: Handle error instead of unwrap
let string_constant = class.gather_string(wide_index).unwrap();
@ -862,7 +1046,10 @@ impl JVM {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?;
},
_ => todo!(),
_ => {
println!("{:?}", class.pool_entry(wide_index).unwrap());
todo!()
}
}
},
@ -998,6 +1185,10 @@ impl JVM {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(5)))?;
}
Instruction::PushNull() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(ObjectReference::NULL)))?;
}
Instruction::PutStatic(fieldref_index) => {
let (target_class_name, target_field_name, expected_field_descriptor) = class.gather_fieldref(fieldref_index)?;
@ -1042,11 +1233,13 @@ impl JVM {
(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 ref_value != ObjectReference::NULL {
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)));
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)
@ -1070,6 +1263,16 @@ impl JVM {
return Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(int)));
}
Instruction::ReturnReference() => {
match (method.descriptor.return_type.array_level, &method.descriptor.return_type.kind) {
(_, AbstractTypeKind::Classname(_)) => (),
_ => return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type)))
}
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
return Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(ref_value)));
}
Instruction::ReturnVoid() => {
let expected_type = AbstractTypeDescription {
array_level: 0,
@ -1090,17 +1293,7 @@ impl JVM {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int >> shift)))?;
},
Instruction::StoreIntoRArray() => {
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let array_ref = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
// TODO: Type checking
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Reference(value));
}
Instruction::StoreIntoBArray() => {
Instruction::StoreIntoBArray() => {
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let array_ref = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
@ -1115,6 +1308,16 @@ impl JVM {
}
}
Instruction::StoreIntoRArray() => {
let value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
let index = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let array_ref = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
// TODO: Type checking
self.heap_area.object_area.set_array_element(array_ref, index as usize, FieldValue::Reference(value));
}
Instruction::StoreLocalInt(index) => {
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
@ -1175,7 +1378,7 @@ impl JVM {
}
enum JVMCallbackOperation {
pub enum JVMCallbackOperation {
PopFrame(),
ReturnFrame(StackValue),
PushFrame(StackFrame),