Implemented some more native methods
This commit is contained in:
parent
272a34b7cd
commit
aba29af0a3
5 changed files with 198 additions and 6 deletions
|
@ -854,6 +854,24 @@ impl Into<String> for &AbstractTypeDescription {
|
||||||
|
|
||||||
impl 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 {
|
pub fn super_component(&self) -> Self {
|
||||||
AbstractTypeDescription {
|
AbstractTypeDescription {
|
||||||
array_level: 0,
|
array_level: 0,
|
||||||
|
@ -927,6 +945,14 @@ impl AbstractTypeDescription {
|
||||||
kind: AbstractTypeKind::Classname(name.to_string()),
|
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)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
|
|
@ -261,6 +261,13 @@ impl ClassStore {
|
||||||
return self.array_classes.get(type_desc).copied();
|
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> {
|
pub fn class_ref_for_type(&self, r#type: AbstractTypeDescription) -> Option<ObjectReference> {
|
||||||
match (r#type.array_level, &r#type.kind) {
|
match (r#type.array_level, &r#type.kind) {
|
||||||
(0, AbstractTypeKind::Classname(ref name)) => {
|
(0, AbstractTypeKind::Classname(ref name)) => {
|
||||||
|
|
|
@ -62,6 +62,24 @@ impl HeapArea {
|
||||||
array_ref
|
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 {
|
pub fn make_handmade_string(&mut self, s: &String, class_store: &ClassStore) -> ObjectReference {
|
||||||
let utf16_bytes = {
|
let utf16_bytes = {
|
||||||
let utf16 = s.encode_utf16();
|
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 {
|
fn default_for(t: &AbstractTypeDescription) -> Self {
|
||||||
if t.array_level != 0 {
|
if t.array_level != 0 {
|
||||||
return Self::Reference(ObjectReference::NULL);
|
return Self::Reference(ObjectReference::NULL);
|
||||||
|
|
26
src/jvm.rs
26
src/jvm.rs
|
@ -474,8 +474,7 @@ impl JVM {
|
||||||
let class_name = waiting_queue.pop_front().unwrap();
|
let class_name = waiting_queue.pop_front().unwrap();
|
||||||
|
|
||||||
if ! self.class_store.have_class(&class_name) {
|
if ! self.class_store.have_class(&class_name) {
|
||||||
println!("Loading Class {class_name}");
|
let new_class_index = self.load_class(&class_name)?;
|
||||||
self.load_class(&class_name)?;
|
|
||||||
let (file, _) = self.class_store.get_class(&class_name).unwrap();
|
let (file, _) = self.class_store.get_class(&class_name).unwrap();
|
||||||
if file.has_super_class() {
|
if file.has_super_class() {
|
||||||
waiting_queue.push_back(file.get_super_class_name()?.to_string());
|
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)?;
|
let interface_name = file.gather_class(*interface_index)?;
|
||||||
waiting_queue.push_back(interface_name.to_string());
|
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);
|
let (instruction, offset) = bytecode.next_instruction(frame.instruction_pointer as usize);
|
||||||
frame.instruction_pointer += offset as u32;
|
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!("{} stack: {:?}", " ".repeat(frame_index), frame.operand_stack);
|
||||||
println!("{}{}.{}:{:<10}{instruction:?}\n", " ".repeat(frame_index), class.get_classname().unwrap(), method.name, frame.instruction_pointer);
|
println!("{}{}.{}:{:<10}{instruction:?}\n", " ".repeat(frame_index), class.get_classname().unwrap(), method.name, frame.instruction_pointer);
|
||||||
|
|
||||||
|
@ -1484,6 +1484,19 @@ impl JVM {
|
||||||
array_ref
|
array_ref
|
||||||
} else {
|
} else {
|
||||||
let mut test_type = array_type_desc.super_component();
|
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();
|
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()) {
|
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() {
|
let value = match expected_field_descriptor.as_str() {
|
||||||
"J" | "D" => wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_2(0))?,
|
"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))? {
|
_ => 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::Reference(r) => FieldValue::Reference(r),
|
||||||
StackValue::Float(f) => FieldValue::Float(f),
|
StackValue::Float(f) => FieldValue::Float(f),
|
||||||
StackValue::Byte(b) => FieldValue::Byte(b),
|
StackValue::Byte(b) => FieldValue::Byte(b),
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
use crate::stackframe::StackFrame;
|
use crate::stackframe::StackFrame;
|
||||||
use crate::heap_area::ObjectReference;
|
use crate::heap_area::ObjectReference;
|
||||||
use crate::heap_area::FieldValue;
|
use crate::heap_area::FieldValue;
|
||||||
use crate::jvm::wrap_stackframe_error;
|
use crate::jvm::wrap_stackframe_error;
|
||||||
use crate::stackframe::StackValue;
|
use crate::stackframe::StackValue;
|
||||||
|
use crate::iterators::ClassFieldIterator;
|
||||||
use crate::classfile::{ AbstractTypeDescription, AbstractTypeKind, MethodDescriptor };
|
use crate::classfile::{ AbstractTypeDescription, AbstractTypeKind, MethodDescriptor };
|
||||||
use crate::native_registry::NativeMethodCallable;
|
use crate::native_registry::NativeMethodCallable;
|
||||||
use crate::jvm::JVM;
|
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 {}
|
struct JavaLangStringUTF16 {}
|
||||||
|
|
||||||
impl JavaLangStringUTF16 {
|
impl JavaLangStringUTF16 {
|
||||||
|
@ -339,6 +347,29 @@ impl JavaLangStringUTF16 {
|
||||||
struct JdkInternalMiscUnsafe {}
|
struct JdkInternalMiscUnsafe {}
|
||||||
|
|
||||||
impl 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> {
|
pub fn array_index_scale_0(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
let frame = {
|
let frame = {
|
||||||
let frame_index = jvm.stack_frames.len() - 1;
|
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)
|
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") => {
|
("java/lang/System", "arraycopy") => {
|
||||||
let expected_descriptor = MethodDescriptor {
|
let expected_descriptor = MethodDescriptor {
|
||||||
argument_types: Box::new([
|
argument_types: Box::new([
|
||||||
|
@ -1263,6 +1359,19 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
Ok(todo_call)
|
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") => {
|
("jdk/internal/misc/Unsafe", "arrayBaseOffset0") => {
|
||||||
let expected_descriptor = MethodDescriptor {
|
let expected_descriptor = MethodDescriptor {
|
||||||
argument_types: Box::new([
|
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())));
|
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") => {
|
("jdk/internal/misc/Unsafe", "registerNatives") => {
|
||||||
|
|
Loading…
Reference in a new issue