Native method registry java.lang.Class wtf
This commit is contained in:
parent
3282694b32
commit
b4c428685f
9 changed files with 987 additions and 40 deletions
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ impl HeapArea {
|
|||
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct ObjectReference(u32);
|
||||
|
||||
|
||||
|
|
241
src/jvm.rs
241
src/jvm.rs
|
@ -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,12 +1233,14 @@ impl JVM {
|
|||
(0..=255, AbstractTypeKind::Classname(_field_type_name)) => {
|
||||
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
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,16 +1293,6 @@ 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() => {
|
||||
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))?;
|
||||
|
@ -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),
|
||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -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
603
src/native_methods.rs
Normal 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
26
src/native_registry.rs
Normal 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);
|
|
@ -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 (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!(),
|
||||
};
|
||||
let mut locals = vec![StackValue::Empty(); code_data.max_locals.into()].into_boxed_slice();
|
||||
|
||||
(code_data.max_locals as usize, code_data.max_stack)
|
||||
};
|
||||
|
||||
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,
|
||||
|
|
Loading…
Reference in a new issue