Native Unsafe:: methods, main loading, stuff!
This commit is contained in:
parent
90e244c964
commit
fba596ce5a
8 changed files with 242 additions and 22 deletions
|
@ -119,6 +119,7 @@ impl Bytecode {
|
|||
|
||||
0x80 => (Instruction::OrInt(), 1),
|
||||
0x82 => (Instruction::XorInt(), 1),
|
||||
0x83 => (Instruction::XorLong(), 1),
|
||||
0x84 => (Instruction::IncrementLocalInt(self.bytes[offset+1], i8::from_be_bytes([self.bytes[offset+2]])), 3),
|
||||
0x85 => (Instruction::ConvertIntToLong(), 1),
|
||||
|
||||
|
@ -416,6 +417,7 @@ pub enum Instruction {
|
|||
|
||||
OrInt() = 0x80, // value, value => or
|
||||
XorInt() = 0x82, // value, value => xor
|
||||
XorLong() = 0x83, // value, value => xor
|
||||
IncrementLocalInt(u8, i8) = 0x84, // increment local variable by constant i8
|
||||
ConvertIntToLong() = 0x85, // convert int on stack to long
|
||||
|
||||
|
|
|
@ -6,9 +6,8 @@ use core::str::Utf8Error;
|
|||
use crate::accessmasks::*;
|
||||
use crate::bytecode::Bytecode;
|
||||
use crate::classstore::ClassStore;
|
||||
use crate::constantpool::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantInterfaceMethodRefInfo, ConstantStringInfo, ConstantMethodRefInfo, ConstantFloatInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo };
|
||||
use crate::constantpool::*;
|
||||
use crate::constantpool::ConstantDoubleInfo;
|
||||
use crate::heap_area::ObjectReference;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
@ -240,6 +239,17 @@ impl JavaClassFile {
|
|||
return Ok(methodref_entry);
|
||||
}
|
||||
|
||||
pub fn pool_methodhandle_entry(&self, index: u16) -> Result<&ConstantMethodHandleInfo, Error> {
|
||||
let pool_entry = self.pool_entry(index)?;
|
||||
|
||||
let methodhandle_entry = match pool_entry {
|
||||
ConstantPoolInfo::MethodHandle(data) => data,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
return Ok(methodhandle_entry);
|
||||
}
|
||||
|
||||
pub fn pool_fieldref_entry(&self, index: u16) -> Result<&ConstantFieldRefInfo, Error> {
|
||||
let pool_entry = self.pool_entry(index)?;
|
||||
|
||||
|
@ -429,6 +439,7 @@ impl JavaClassFile {
|
|||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -702,9 +713,60 @@ impl NestMembersAttributeData {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BootstrapMethodEntry {
|
||||
bootstrap_method_ref: u16,
|
||||
bootstrap_arguments: Box<[u16]>
|
||||
}
|
||||
|
||||
impl BootstrapMethodEntry {
|
||||
fn from_reader(reader: &mut dyn Read) -> Result<Self, Error> {
|
||||
Ok(
|
||||
BootstrapMethodEntry {
|
||||
bootstrap_method_ref: read_u16(reader)?,
|
||||
bootstrap_arguments: {
|
||||
let length = read_u16(reader)?;
|
||||
let mut v = Vec::with_capacity(length.into());
|
||||
|
||||
for _i in 0..length {
|
||||
v.push(read_u16(reader)?);
|
||||
}
|
||||
|
||||
v.into_boxed_slice()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BootstrapMethodsData {
|
||||
bootstrap_methods: Box<[BootstrapMethodEntry]>
|
||||
}
|
||||
|
||||
impl BootstrapMethodsData {
|
||||
fn from_reader(reader: &mut dyn Read) -> Result<Self, Error> {
|
||||
Ok(
|
||||
BootstrapMethodsData {
|
||||
bootstrap_methods: {
|
||||
let length = read_u16(reader)?;
|
||||
let mut v = Vec::with_capacity(length.into());
|
||||
|
||||
for _i in 0..length {
|
||||
v.push(BootstrapMethodEntry::from_reader(reader)?);
|
||||
}
|
||||
|
||||
v.into_boxed_slice()
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AttributeData {
|
||||
Code(CodeAttributeData),
|
||||
BootstrapMethods(BootstrapMethodsData),
|
||||
Signature(SignatureAttributeData),
|
||||
Synthetic(),
|
||||
Exceptions(ExceptionAttributeData),
|
||||
|
@ -755,6 +817,10 @@ impl AttributeInfo {
|
|||
}
|
||||
),
|
||||
|
||||
"BootstrapMethods" => AttributeData::BootstrapMethods(
|
||||
BootstrapMethodsData::from_reader(reader)?,
|
||||
),
|
||||
|
||||
"LineNumberTable" => AttributeData::LineNumberTable(
|
||||
LineNumberTableAttributeData::from_reader(reader)?
|
||||
),
|
||||
|
|
|
@ -16,7 +16,7 @@ pub struct ClassStore {
|
|||
pub array_classes: HashMap<AbstractTypeDescription, ObjectReference>,
|
||||
pub classes: Vec<ClassStoreEntry>,
|
||||
pub class_path_fragments: Vec<PathBuf>,
|
||||
pub native_class_names: Vec<String>,
|
||||
pub native_class_descriptors: Vec<String>,
|
||||
pub primitive_classes: PrimitiveClassStore,
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ impl ClassStore {
|
|||
array_classes: HashMap::new(),
|
||||
classes: Vec::new(),
|
||||
class_path_fragments: vec![current_dir_path],
|
||||
native_class_names: Vec::new(),
|
||||
native_class_descriptors: Vec::new(),
|
||||
primitive_classes: PrimitiveClassStore::default(),
|
||||
}
|
||||
}
|
||||
|
@ -106,12 +106,12 @@ impl ClassStore {
|
|||
}
|
||||
|
||||
pub fn add_native_class_descriptor(&mut self, name: String) -> usize {
|
||||
self.native_class_names.push(name);
|
||||
return self.native_class_names.len() - 1;
|
||||
self.native_class_descriptors.push(name);
|
||||
return self.native_class_descriptors.len() - 1;
|
||||
}
|
||||
|
||||
pub fn get_native_class_name(&self, index: usize) -> &String {
|
||||
return &self.native_class_names[index];
|
||||
return &self.native_class_descriptors[index];
|
||||
}
|
||||
|
||||
pub fn load_class_from_file(&mut self, class_file_path: &PathBuf) -> Result<usize, Error> {
|
||||
|
|
|
@ -223,7 +223,7 @@ impl ObjectArea {
|
|||
fn make_array(&mut self, class_store: &ClassStore, elements: Box<[ObjectReference]>) -> (ObjectReference, usize) {
|
||||
assert!(elements.len() != 0);
|
||||
let array_element_class_name = self.get_reference_native_class_name(elements[0], class_store);
|
||||
let array_element_type_desc = AbstractTypeDescription::parse_first(array_element_class_name).unwrap().1;
|
||||
let array_element_type_desc = AbstractTypeDescription::parse_full(array_element_class_name).unwrap();
|
||||
|
||||
let (array_object_ref, array_size) = self.make_empty_array(class_store, array_element_type_desc, elements.len());
|
||||
|
||||
|
@ -255,6 +255,23 @@ impl ObjectArea {
|
|||
return (object_ref, object_size);
|
||||
}
|
||||
|
||||
pub fn class_ref_get_class_index(&self, class_ref: ObjectReference, class_store: &ClassStore) -> usize {
|
||||
let class_data_ref = match self.get_object_field(class_ref, "classData", self.get_object_class_index(class_ref), class_store).unwrap() {
|
||||
FieldValue::Reference(r) => r,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let native_name_index = match self.get_object_field(class_data_ref, "native_class_descriptor_index", self.get_object_class_index(class_data_ref), class_store).unwrap() {
|
||||
FieldValue::Int(i) => i,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let native_class_name = class_store.get_native_class_name(native_name_index as usize);
|
||||
|
||||
let native_class_index = class_store.class_index_for_type(AbstractTypeDescription::parse_full(native_class_name).unwrap()).unwrap();
|
||||
|
||||
return native_class_index;
|
||||
}
|
||||
|
||||
pub fn get_class_ref_native_class_name<'a>(&self, class_ref: ObjectReference, class_store: &'a ClassStore) -> &'a String {
|
||||
let class_data_ref = match self.get_object_field(class_ref, "classData", self.get_object_class_index(class_ref), class_store).unwrap() {
|
||||
FieldValue::Reference(r) => r,
|
||||
|
|
11
src/jvm.rs
11
src/jvm.rs
|
@ -1471,6 +1471,10 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(instruction_result)))?;
|
||||
}
|
||||
|
||||
Instruction::InvokeDynamic(invokedynamic_index, _zero) => {
|
||||
let methodhandle_reference = class.pool_methodhandle_entry(invokedynamic_index)?;
|
||||
}
|
||||
|
||||
Instruction::InvokeInterface(methodref_index) => {
|
||||
let (supplied_interface_name, supplied_method_name, supplied_descriptor_string) = class.gather_interfacemethodref(methodref_index)?;
|
||||
|
||||
|
@ -2600,6 +2604,13 @@ impl JVM {
|
|||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 ^ value_2)))?;
|
||||
}
|
||||
|
||||
Instruction::XorLong() => {
|
||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?;
|
||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?;
|
||||
|
||||
wrap_stackframe_error(class, method, frame.operand_stack.push_long(value_1 ^ value_2))?;
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction)))
|
||||
},
|
||||
|
|
|
@ -25,9 +25,9 @@ fn main() {
|
|||
jvm.class_store.class_path_fragments.push(PathBuf::from("./classpath"));
|
||||
|
||||
match jvm.entrypoint(
|
||||
&"Main".to_string(),
|
||||
&"SiedepunktNamen".to_string(),
|
||||
&"main".to_string(),
|
||||
&["Hello World"],
|
||||
&["5"],
|
||||
) {
|
||||
Ok(()) => (),
|
||||
Err(e) => println!("{:#?}", e),
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use std::time::SystemTime;
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
use crate::accessmasks::FieldAccessFlag;
|
||||
use crate::classfile::FieldInfo;
|
||||
use crate::classstore::ClassStore;
|
||||
use crate::stackframe::StackFrame;
|
||||
|
@ -58,6 +62,59 @@ impl JavaIOFileDescriptor {
|
|||
struct JavaLangClass {}
|
||||
|
||||
impl JavaLangClass {
|
||||
fn get_declared_fields_0(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
let frame = {
|
||||
let thread = &mut jvm.threads[jvm.active_thread];
|
||||
let frame_index = thread.stack_frames.len() - 1;
|
||||
&mut thread.stack_frames[frame_index]
|
||||
};
|
||||
let this = frame.load_local_reference(0).unwrap();
|
||||
let public_only = frame.load_local_boolean_compatible(1).unwrap();
|
||||
let class_index = jvm.heap_area.object_area.class_ref_get_class_index(this, &jvm.class_store);
|
||||
|
||||
if ! jvm.class_store.have_class(&"java/lang/reflect/Field".to_string()) {
|
||||
return Ok(JVMCallbackOperation::LoadClass("java/lang/reflect/Field".to_string()));
|
||||
}
|
||||
if ! jvm.class_store.was_init(&"java/lang/reflect/Field".to_string()).unwrap() {
|
||||
return Ok(JVMCallbackOperation::InitClass("java/lang/reflect/Field".to_string()));
|
||||
}
|
||||
if ! jvm.class_store.have_class(&"[Ljava/lang/reflect/Field;".to_string()) {
|
||||
let description = AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: AbstractTypeKind::Classname("java/lang/reflect/Field".to_string()),
|
||||
};
|
||||
return Ok(JVMCallbackOperation::MakeArrayClass(this, description));
|
||||
}
|
||||
let field_class_index = jvm.class_store.class_idx_from_name(&"java/lang/reflect/Field".to_string()).unwrap();
|
||||
|
||||
let fields = ClassFieldIterator::new(class_index, &jvm.class_store)
|
||||
.filter(|field_info| if public_only { field_info.access_flags & FieldAccessFlag::Public } else { true } )
|
||||
.map(|field_info| {
|
||||
let field = jvm.heap_area.make_object(&jvm.class_store, field_class_index);
|
||||
let java_string = jvm.heap_area.make_handmade_string(&field_info.name, &jvm.class_store);
|
||||
jvm.heap_area.object_area.set_object_field(
|
||||
field,
|
||||
"name",
|
||||
java_string.into(),
|
||||
field_class_index,
|
||||
&jvm.class_store
|
||||
).unwrap();
|
||||
jvm.heap_area.object_area.set_object_field(
|
||||
field,
|
||||
"clazz",
|
||||
this.into(),
|
||||
field_class_index,
|
||||
&jvm.class_store
|
||||
).unwrap();
|
||||
|
||||
field
|
||||
})
|
||||
.collect();
|
||||
|
||||
let field_array = jvm.heap_area.make_array(&jvm.class_store, fields);
|
||||
|
||||
Ok(JVMCallbackOperation::ReturnFrame(field_array.into()))
|
||||
}
|
||||
|
||||
fn is_array(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
let frame = {
|
||||
|
@ -500,6 +557,12 @@ impl JavaLangStringUTF16 {
|
|||
struct JavaLangSystem {}
|
||||
|
||||
impl JavaLangSystem {
|
||||
fn nano_time(_: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
let nanos = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_nanos() as i64;
|
||||
|
||||
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Long(nanos)))
|
||||
}
|
||||
|
||||
fn register_natives(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
// Load class because it won't be loaded otherwise
|
||||
let frame = {
|
||||
|
@ -849,7 +912,18 @@ impl JdkInternalMiscUnsafe {
|
|||
|
||||
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Boolean(success)))
|
||||
} else {
|
||||
todo!()
|
||||
let object_class_descriptor = jvm.heap_area.object_area.get_reference_native_class_name(object, &jvm.class_store);
|
||||
let object_class_index = jvm.class_store.class_index_for_type(AbstractTypeDescription::parse_full(object_class_descriptor).unwrap()).unwrap();
|
||||
|
||||
let field = JdkInternalMiscUnsafe::class_field_at_offset(object_class_index, &jvm.class_store, offset)?;
|
||||
|
||||
let current_value = jvm.heap_area.object_area.get_object_field(object, &field.name, object_class_index, &jvm.class_store)?;
|
||||
let function_result = current_value == expected.into();
|
||||
if function_result {
|
||||
jvm.heap_area.object_area.set_object_field(object, &field.name, replacement.into(), object_class_index, &jvm.class_store)?;
|
||||
}
|
||||
|
||||
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Boolean(function_result)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1003,6 +1077,46 @@ impl JdkInternalMiscUnsafe {
|
|||
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Boolean(function_result)))
|
||||
}
|
||||
|
||||
pub fn object_field_offset_0(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
let frame = {
|
||||
let thread = &mut jvm.threads[jvm.active_thread];
|
||||
let frame_index = thread.stack_frames.len() - 1;
|
||||
&mut thread.stack_frames[frame_index]
|
||||
};
|
||||
let field_object_reference = frame.load_local_reference(1).unwrap();
|
||||
let field_class_index = jvm.heap_area.object_area.get_reference_class_index(field_object_reference, &jvm.class_store);
|
||||
|
||||
let class = jvm.heap_area.object_area.get_object_field(
|
||||
field_object_reference,
|
||||
"clazz",
|
||||
field_class_index,
|
||||
&jvm.class_store
|
||||
)?.expect_reference();
|
||||
let field_name = jvm.heap_area.object_area.get_object_field(
|
||||
field_object_reference,
|
||||
"name",
|
||||
field_class_index,
|
||||
&jvm.class_store
|
||||
)?.expect_reference();
|
||||
|
||||
let byte_offset = JdkInternalMiscUnsafe::object_field_offset_2(jvm, class, field_name)?;
|
||||
|
||||
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Long(byte_offset)))
|
||||
}
|
||||
|
||||
fn object_field_offset_2(jvm: &mut JVM, class_object_reference: ObjectReference, field_name_string_reference: ObjectReference) -> Result<i64, Error> {
|
||||
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 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(byte_offset)
|
||||
}
|
||||
|
||||
pub fn object_field_offset_1(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
// args: Class class, String fieldName
|
||||
let frame = {
|
||||
|
@ -1012,16 +1126,9 @@ impl JdkInternalMiscUnsafe {
|
|||
};
|
||||
|
||||
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();
|
||||
let byte_offset = JdkInternalMiscUnsafe::object_field_offset_2(jvm, class_object_reference, field_name_string_reference)?;
|
||||
|
||||
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Long(byte_offset)))
|
||||
}
|
||||
|
@ -1257,7 +1364,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
|||
]),
|
||||
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/reflect/Field".to_string()) },
|
||||
},
|
||||
todo_call
|
||||
JavaLangClass::get_declared_fields_0
|
||||
),
|
||||
|
||||
(
|
||||
|
@ -1784,7 +1891,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
|||
]),
|
||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long()},
|
||||
},
|
||||
todo_call
|
||||
JavaLangSystem::nano_time
|
||||
),
|
||||
|
||||
(
|
||||
|
@ -2543,7 +2650,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
|||
]),
|
||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long()},
|
||||
},
|
||||
todo_call
|
||||
JdkInternalMiscUnsafe::object_field_offset_0
|
||||
),
|
||||
|
||||
(
|
||||
|
|
|
@ -430,6 +430,23 @@ impl StackFrame {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn load_local_boolean_compatible(&self, index: u16) -> Result<bool, Error> {
|
||||
let local = self.locals[index as usize];
|
||||
match local {
|
||||
StackValue::Boolean(b) => Ok(b),
|
||||
StackValue::Int(i) => Ok(i != 0),
|
||||
_ => Err(Error::LocalError(format!("Mismatched type at index {} of the function locals, expected Boolean but found '{:?}'", index, local)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_local_boolean(&self, index: u16) -> Result<bool, Error> {
|
||||
let local = self.locals[index as usize];
|
||||
match local {
|
||||
StackValue::Boolean(b) => Ok(b),
|
||||
_ => Err(Error::LocalError(format!("Mismatched type at index {} of the function locals, expected Boolean but found '{:?}'", index, local)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_local_int(&self, index: u16) -> Result<i32, Error> {
|
||||
let local = self.locals[index as usize];
|
||||
match local {
|
||||
|
|
Loading…
Reference in a new issue