Implemented some more native methods

This commit is contained in:
VegOwOtenks 2024-11-03 23:03:10 +01:00
parent 272a34b7cd
commit aba29af0a3
5 changed files with 198 additions and 6 deletions

View file

@ -854,6 +854,24 @@ impl Into<String> for &AbstractTypeDescription {
impl AbstractTypeDescription {
pub fn storage_size(&self) -> u8 {
match self.array_level {
0 => match self.kind {
AbstractTypeKind::Void() => 0,
AbstractTypeKind::Byte() => 1,
AbstractTypeKind::Char() => 2,
AbstractTypeKind::Double() => 8,
AbstractTypeKind::Float() => 4,
AbstractTypeKind::Int() => 4,
AbstractTypeKind::Long() => 8,
AbstractTypeKind::Short() => 2,
AbstractTypeKind::Boolean() => 1,
AbstractTypeKind::Classname(_) => 8
}
_ => 8
}
}
pub fn super_component(&self) -> Self {
AbstractTypeDescription {
array_level: 0,
@ -927,6 +945,14 @@ impl AbstractTypeDescription {
kind: AbstractTypeKind::Classname(name.to_string()),
}
}
pub fn extract_class_name(&self) -> &String {
match self.kind {
AbstractTypeKind::Classname(ref name) => name,
_ => unreachable!()
}
}
}
#[derive(Debug, Eq, PartialEq)]

View file

@ -261,6 +261,13 @@ impl ClassStore {
return self.array_classes.get(type_desc).copied();
}
pub fn class_index_for_type(&self, r#type: AbstractTypeDescription) -> Option<usize> {
match (r#type.array_level, &r#type.kind) {
(0, AbstractTypeKind::Classname(ref name)) => Some(self.class_idx_from_name(name).unwrap()),
_ => None
}
}
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)) => {

View file

@ -62,6 +62,24 @@ impl HeapArea {
array_ref
}
pub fn decode_java_string(&mut self, string_ref: ObjectReference, class_store: &ClassStore) -> String {
let byte_array_reference = self.object_area.get_object_field(string_ref, "value", self.object_area.get_object_class_index(string_ref), class_store).unwrap().expect_reference();
let byte_array_length = self.object_area.get_array_length(byte_array_reference);
let mut utf16_bytes = Vec::with_capacity(byte_array_length / 2);
for index in 0..byte_array_length/2 {
let i0 = self.object_area.get_array_element(byte_array_reference, (index * 2) as i32).expect_byte();
let i1 = self.object_area.get_array_element(byte_array_reference, (index * 2 + 1) as i32).expect_byte();
let u0 = u8::from_ne_bytes(i0.to_ne_bytes());
let u1 = u8::from_ne_bytes(i1.to_ne_bytes());
utf16_bytes.push(u16::from_ne_bytes([u0, u1]));
}
String::from_utf16(&utf16_bytes).unwrap()
}
pub fn make_handmade_string(&mut self, s: &String, class_store: &ClassStore) -> ObjectReference {
let utf16_bytes = {
let utf16 = s.encode_utf16();
@ -713,6 +731,20 @@ impl FieldValue {
}
}
fn expect_reference(&self) -> ObjectReference {
match self {
Self::Reference(r) => *r,
_ => unreachable!()
}
}
fn expect_byte(&self) -> i8 {
match self {
Self::Byte(b) => *b,
_ => unreachable!()
}
}
fn default_for(t: &AbstractTypeDescription) -> Self {
if t.array_level != 0 {
return Self::Reference(ObjectReference::NULL);

View file

@ -474,8 +474,7 @@ impl JVM {
let class_name = waiting_queue.pop_front().unwrap();
if ! self.class_store.have_class(&class_name) {
println!("Loading Class {class_name}");
self.load_class(&class_name)?;
let new_class_index = 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());
@ -485,6 +484,7 @@ impl JVM {
let interface_name = file.gather_class(*interface_index)?;
waiting_queue.push_back(interface_name.to_string());
}
println!("Loaded Class {class_name} ({new_class_index})");
}
}
@ -672,7 +672,7 @@ impl JVM {
let (instruction, offset) = bytecode.next_instruction(frame.instruction_pointer as usize);
frame.instruction_pointer += offset as u32;
//println!("{} locals: {:?}", " ".repeat(frame_index), frame.locals);
println!("{} locals: {:?}", " ".repeat(frame_index), frame.locals);
println!("{} stack: {:?}", " ".repeat(frame_index), frame.operand_stack);
println!("{}{}.{}:{:<10}{instruction:?}\n", " ".repeat(frame_index), class.get_classname().unwrap(), method.name, frame.instruction_pointer);
@ -1484,6 +1484,19 @@ impl JVM {
array_ref
} else {
let mut test_type = array_type_desc.super_component();
if component_name.len() != 1 {
let base_type_name = test_type.extract_class_name();
if ! self.class_store.have_class(base_type_name) {
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(base_type_name.to_string()));
}
if ! self.class_store.was_init(base_type_name).unwrap() {
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::InitClass(base_type_name.to_string()));
}
}
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()) {
@ -1844,7 +1857,12 @@ impl JVM {
let value = match expected_field_descriptor.as_str() {
"J" | "D" => wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_2(0))?,
_ => match wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))? {
StackValue::Int(i) => FieldValue::Int(i),
StackValue::Int(i) => {
match expected_field_descriptor.as_str() {
"Z" => FieldValue::Boolean(i != 0),
_ => FieldValue::Int(i)
}
}
StackValue::Reference(r) => FieldValue::Reference(r),
StackValue::Float(f) => FieldValue::Float(f),
StackValue::Byte(b) => FieldValue::Byte(b),

View file

@ -1,9 +1,9 @@
use crate::stackframe::StackFrame;
use crate::heap_area::ObjectReference;
use crate::heap_area::FieldValue;
use crate::jvm::wrap_stackframe_error;
use crate::stackframe::StackValue;
use crate::iterators::ClassFieldIterator;
use crate::classfile::{ AbstractTypeDescription, AbstractTypeKind, MethodDescriptor };
use crate::native_registry::NativeMethodCallable;
use crate::jvm::JVM;
@ -328,6 +328,14 @@ impl JavaLangDouble {
}
}
struct JavaLangRuntime {}
impl JavaLangRuntime {
pub fn available_processors(_jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(1)))
}
}
struct JavaLangStringUTF16 {}
impl JavaLangStringUTF16 {
@ -339,6 +347,29 @@ impl JavaLangStringUTF16 {
struct JdkInternalMiscUnsafe {}
impl JdkInternalMiscUnsafe {
pub fn object_field_offset_1(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
// args: Class class, String fieldName
let frame = {
let frame_index = jvm.stack_frames.len() - 1;
&mut jvm.stack_frames[frame_index]
};
let class_object_reference = frame.load_local_reference(1).unwrap();
let class_descriptor = jvm.heap_area.object_area.get_class_ref_native_class_name(class_object_reference, &jvm.class_store);
let class_index = jvm.class_store.class_index_for_type(AbstractTypeDescription::parse_full(class_descriptor).unwrap()).unwrap();
let field_name_string_reference = frame.load_local_reference(2).unwrap();
let rust_field_name_string = jvm.heap_area.decode_java_string(field_name_string_reference, &jvm.class_store);
let byte_offset: i64 = ClassFieldIterator::new(class_index as usize, &jvm.class_store)
.take_while(|f| f.name != rust_field_name_string)
.map(|f| f.descriptor.storage_size() as i64)
.sum();
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Long(byte_offset)))
}
pub fn array_index_scale_0(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
let frame = {
let frame_index = jvm.stack_frames.len() - 1;
@ -1127,6 +1158,71 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
Ok(todo_call)
}
("java/lang/Runtime", "availableProcessors") => {
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(JavaLangRuntime::available_processors)
}
("java/lang/Runtime", "freeMemory") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long()},
};
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/Runtime", "gc") => {
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/Runtime", "maxMemory") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long()},
};
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/Runtime", "totalMemory") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long()},
};
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/System", "arraycopy") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
@ -1263,6 +1359,19 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
Ok(todo_call)
}
("java/lang/Thread", "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(ignore_call)
}
("jdk/internal/misc/Unsafe", "arrayBaseOffset0") => {
let expected_descriptor = MethodDescriptor {
argument_types: Box::new([
@ -2149,7 +2258,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
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)
Ok(JdkInternalMiscUnsafe::object_field_offset_1)
}
("jdk/internal/misc/Unsafe", "registerNatives") => {