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

@ -11,7 +11,7 @@ impl Bytecode {
match opcode {
0x00 => (Instruction::NoOperation(), 1),
0x01 => (Instruction::StoreIntoIntArray(), 1),
0x01 => (Instruction::PushNull(), 1),
0x02 => (Instruction::PushConstIntM1(), 1),
0x03 => (Instruction::PushConstInt0(), 1),
0x04 => (Instruction::PushConstInt1(), 1),
@ -25,7 +25,7 @@ impl Bytecode {
0x10 => (Instruction::LoadByteImmediate(self.bytes[offset+1]), 2),
0x11 => (Instruction::LoadShortImmediate((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0x12 => (Instruction::LoadConstant(self.bytes[offset+1]), 2),
0x13 => (Instruction::LoadWideConstant((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0x13 => (Instruction::LoadCostantWide((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0x14 => (Instruction::LoadConstant64((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0x1A => (Instruction::LoadLocalInt0(), 1),
@ -59,6 +59,7 @@ impl Bytecode {
0x59 => (Instruction::Duplicate(), 1),
0x68 => (Instruction::MultiplyInt(), 1),
0x6C => (Instruction::DivideInt(), 1),
0x6D => (Instruction::DivideLong(), 1),
0x7A => (Instruction::ShiftIntRight(), 1),
@ -135,6 +136,18 @@ impl Bytecode {
0xBC => (Instruction::NewPrimitiveArray(self.bytes[offset+1]), 2),
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0xBE => (Instruction::ArrayLength(), 1),
0xC2 => (Instruction::EnterMonitor(), 1),
0xC3 => (Instruction::ExitMonitor(), 1),
0xC6 => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchNull(i16::from_be_bytes(bytes)), 3)
}
0xC7 => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchNonNull(i16::from_be_bytes(bytes)), 3)
}
_ => (Instruction::Unknown(opcode), 1)
}
}
@ -167,7 +180,7 @@ impl Debug for Bytecode {
#[repr(u8)]
pub enum Instruction {
NoOperation() = 0x00, // No-Operation
StoreIntoIntArray() = 0x01, // ..., arrayref, index, value
PushNull() = 0x01, // ..., arrayref, index, value
PushConstIntM1() = 0x02, // Push -1
PushConstInt0() = 0x03, // Push 0
PushConstInt1() = 0x04, // Push 1
@ -181,7 +194,7 @@ pub enum Instruction {
LoadByteImmediate(u8) = 0x10, // push immediate short
LoadShortImmediate(u16) = 0x11, // push immediate short
LoadConstant(u8) = 0x12, // Push from constant pool
LoadWideConstant(u16) = 0x13, // Push from constant pool with wide index, don't load
LoadCostantWide(u16) = 0x13, // Push from constant pool with wide index, don't load
// double or long or whatever
LoadConstant64(u16) = 0x14, // Push Long or Double from constant pool
LoadLocalInt0() = 0x1A, // Load int from local variable
@ -215,6 +228,7 @@ pub enum Instruction {
Duplicate() = 0x59, // duplicate top stack value
MultiplyInt() = 0x68, // int multiplication
DivideInt() = 0x6C, // integer division, round toward zero and more rules
DivideLong() = 0x6D, // long division
ShiftIntRight() = 0x7a, // shift int
@ -252,5 +266,11 @@ pub enum Instruction {
NewPrimitiveArray(u8) = 0xBC, // make a primitive array
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
ArrayLength() = 0xBE, // Get length from array reference
EnterMonitor() = 0xC2, // enter the synchronization monitor of an object
ExitMonitor() = 0xC3, // exit the synchronization monitor of an object
BranchNull(i16) = 0xC6, // branch if Null
BranchNonNull(i16) = 0xC7, // branch if Null
Unknown(u8),
}

View file

@ -763,6 +763,24 @@ impl Into<String> for &AbstractTypeKind {
}
}
impl From<&str> for AbstractTypeKind {
fn from(value: &str) -> Self {
match value.chars().nth(0).unwrap() {
'V' => AbstractTypeKind::Void(),
'B' => AbstractTypeKind::Byte(),
'C' => AbstractTypeKind::Char(),
'D' => AbstractTypeKind::Double(),
'F' => AbstractTypeKind::Float(),
'I' => AbstractTypeKind::Int(),
'J' => AbstractTypeKind::Long(),
'S' => AbstractTypeKind::Short(),
'Z' => AbstractTypeKind::Boolean(),
'L' => todo!(),
_ => todo!(),
}
}
}
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct AbstractTypeDescription {
pub array_level: u8,
@ -786,6 +804,28 @@ impl Into<String> for &AbstractTypeDescription {
}
impl AbstractTypeDescription {
pub fn super_component(&self) -> Self {
AbstractTypeDescription {
array_level: 0,
kind: self.kind.clone()
}
}
pub fn component(&self) -> Self {
AbstractTypeDescription {
array_level: self.array_level - 1,
kind: self.kind.clone()
}
}
pub fn array(&self) -> Self {
AbstractTypeDescription {
array_level: self.array_level + 1,
kind: self.kind.clone()
}
}
pub fn parse_full(s: &str) -> Result<Self, Error> {
let (c, parsed) = Self::parse_first(s)?;

View file

@ -17,6 +17,19 @@ pub struct ClassStore {
classes: Vec<ClassStoreEntry>,
class_path_fragments: Vec<PathBuf>,
native_class_names: Vec<String>,
primitive_classes: PrimitiveClassStore,
}
#[derive(Debug, Default)]
pub struct PrimitiveClassStore {
byte_class: ObjectReference,
char_class: ObjectReference,
double_class: ObjectReference,
float_class: ObjectReference,
integer_class: ObjectReference,
long_class: ObjectReference,
short_class: ObjectReference,
boolean_class: ObjectReference,
}
#[derive(Debug)]
@ -71,6 +84,7 @@ impl ClassStore {
classes: Vec::new(),
class_path_fragments: vec![current_dir_path],
native_class_names: Vec::new(),
primitive_classes: PrimitiveClassStore::default(),
}
}
@ -121,7 +135,7 @@ impl ClassStore {
}
};
return Err(Error::ClassNotFoundError(format!("Could not find class '{}' in classpath", classname)));
return Err(Error::ClassNotFoundError(format!("Could not find class '{classname}' in classpath")));
}
pub fn are_types_compatible(&self, my_type: &AbstractTypeDescription, other_type: &AbstractTypeDescription) -> bool {
@ -209,7 +223,33 @@ impl ClassStore {
self.classes[index].class_object
}
pub fn get_class_objectref_from_primitive(&self, primitive: AbstractTypeKind) -> Option<ObjectReference> {
match primitive {
AbstractTypeKind::Boolean() => {
Some(self.primitive_classes.boolean_class)
}
_ => todo!(),
}
}
pub fn get_array_class_ref(&self, type_desc: &AbstractTypeDescription) -> Option<ObjectReference> {
return self.array_classes.get(type_desc).copied();
}
pub fn class_ref_for_type(&self, r#type: AbstractTypeDescription) -> Option<ObjectReference> {
match (r#type.array_level, &r#type.kind) {
(0, AbstractTypeKind::Classname(ref name)) => {
let class_index = self.class_idx_from_name(name).unwrap();
Some(self.get_class_objectref_from_index(class_index))
}
(0, _) => {
self.get_class_objectref_from_primitive(r#type.kind)
}
(1..=u8::MAX, _) => {
self.get_array_class_ref(&r#type)
}
}
}
}

View file

@ -93,7 +93,7 @@ impl HeapArea {
}
#[derive(Debug, Clone, Copy)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct ObjectReference(u32);

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),

View file

@ -7,15 +7,17 @@ mod accessmasks;
mod constantpool;
mod heap_area;
mod iterators;
mod native_registry;
mod native_methods;
use std::fs::File;
//use std::fs::File;
//
use crate::accessmasks::FieldAccessFlag;
//use crate::accessmasks::FieldAccessFlag;
//use crate::stackframe::StackValue;
use crate::classfile::JavaClassFile;
//use crate::classfile::JavaClassFile;
fn main() {
//println!("{:#?}", JavaClassFile::new(&mut File::open("java/lang/String.class").unwrap()).unwrap().fields.iter().filter(|f| ! (f.access_flags & FieldAccessFlag::Static)).collect::<Vec<_>>());
//println!("{:#?}", JavaClassFile::new(&mut File::open("java/lang/System.class").unwrap()).unwrap());
let mut jvm = jvm::JVM::new();

603
src/native_methods.rs Normal file
View file

@ -0,0 +1,603 @@
use crate::classfile::{ AbstractTypeDescription, AbstractTypeKind, MethodDescriptor };
use crate::native_registry::NativeMethodCallable;
use crate::jvm::JVM;
use crate::jvm::Error;
use crate::jvm::JVMCallbackOperation;
pub fn ignore_call(_: &mut JVM) -> Result<JVMCallbackOperation, Error> {
Ok(JVMCallbackOperation::PopFrame())
}
pub fn todo_call(_: &mut JVM) -> Result<JVMCallbackOperation, Error> {
todo!()
}
pub fn java_lang_object_get_class(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
todo!()
}
pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Result<NativeMethodCallable, Error> {
let method_name: &str = &m.name;
match (class_name, method_name) {
("java/lang/Class", "forName0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string()) },
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/ClassLoader".to_string()) },
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Class"))},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "desiredAssertionStatus0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getClassAccessFlagsRaw0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getClassFileVersion0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getConstantPool") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("jdk/internal/reflect/ConstantPool".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getDeclaredClasses0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getDeclaredConstructors0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/reflect/Constructor".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getDeclaredFields0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/reflect/Field".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getDeclaredMethods0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/reflect/Method".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getDeclaringClass0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getEnclosingMethod0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getGenericSignature0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getInterfaces0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getNestMembers0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getModifiers") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getNestHost0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getPermittedSubclasses0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getPrimitiveClass") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string()) },
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getProtectionDomain0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/security/ProtectionDomain".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getRawAnnotations") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getRawTypeAnnotations") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getRecordComponents0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/reflect/RecordComponent".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getSimpleBinaryName0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getSigners") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "getSuperclass") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "isAssignableFrom") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Class".to_string()) },
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "initClassName") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".to_string()) },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "isArray") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "isHidden") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "isInstance") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Object".to_string()) },
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "isInterface") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "isPrimitive") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "isRecord0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "registerNatives") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Class", "setSigners") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/Object".to_string()) }
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/String", "intern") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/String"))},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Object", "clone") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Object"))},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Object", "getClass") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Class"))},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(java_lang_object_get_class)
}
("java/lang/Object", "hashCode") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Object", "notifyAll") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Object", "notify") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
("java/lang/Object", "wait0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long() },
]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void()},
};
if m.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("Native descriptor mismatch for method '{class_name}.{method_name}': found '{}' but expected '{}'", m.descriptor.source_string(), expected_descriptor.source_string())));
}
Ok(todo_call)
}
_ => Err(Error::RunTimeError(format!("Failed to find native implementation for method '{class_name}.{method_name}'"))),
}
}

26
src/native_registry.rs Normal file
View file

@ -0,0 +1,26 @@
use crate::jvm::Error;
use crate::jvm::JVMCallbackOperation;
use crate::jvm::JVM;
use std::collections::HashMap;
#[derive(Debug, Default)]
pub struct NativeRegistry {
methods: HashMap<MethodPath, NativeMethodCallable>,
}
impl NativeRegistry {
pub fn get(&self, class_name: &String, method_name: &String) -> Option<&NativeMethodCallable> {
self.methods.get(&MethodPath(class_name.to_string(), method_name.to_string()))
}
pub fn register(&mut self, class_name: &str, method_name: &str, n: NativeMethodCallable) {
self.methods.insert(MethodPath(class_name.to_string(), method_name.to_string()), n);
}
}
pub type NativeMethodCallable=fn (&mut JVM) -> Result<JVMCallbackOperation, Error>;
#[derive(Debug)]
#[derive(Eq, Hash, PartialEq)]
pub struct MethodPath(String, String);

View file

@ -1,4 +1,5 @@
use crate::classfile::{ JavaClassFile, AttributeData };
use crate::accessmasks::MethodAccessFlag;
use crate::classfile::{ AttributeData, JavaClassFile };
use crate::heap_area::{ ObjectReference, FieldValue };
#[derive(Copy, Clone, Debug)]
@ -63,6 +64,10 @@ impl OperandStack {
self.push(StackValue::Int(b as i32))
}
FieldValue::Int(i) => {
self.push(StackValue::Int(i))
}
_ => {
println!("{value:?}");
todo!();
@ -244,11 +249,19 @@ pub struct StackFrame {
impl StackFrame {
pub fn new(classfile: &JavaClassFile, class_index: usize, method_index: u16, arguments: &[StackValue]) -> Self {
let method_info = &classfile.methods[method_index as usize];
let code_data = match &method_info.attributes[method_info.code_attribute_index].data {
AttributeData::Code(data) => data,
_ => unreachable!(),
let (max_locals, max_stack) = if method_info.access_flags & MethodAccessFlag::Native {
(arguments.len(), 1)
} else {
let code_data = match &method_info.attributes[method_info.code_attribute_index].data {
AttributeData::Code(data) => data,
_ => unreachable!(),
};
(code_data.max_locals as usize, code_data.max_stack)
};
let mut locals = vec![StackValue::Empty(); code_data.max_locals.into()].into_boxed_slice();
let mut locals = vec![StackValue::Empty(); max_locals].into_boxed_slice();
assert!(locals.len() >= arguments.len());
@ -258,7 +271,7 @@ impl StackFrame {
StackFrame {
locals,
operand_stack: OperandStack::new(code_data.max_stack),
operand_stack: OperandStack::new(max_stack),
class_index,
method_index,
instruction_pointer: 0,