Implemented more opcodes and unsafe stuff
This commit is contained in:
parent
dfb6060df9
commit
d38d5b2897
5 changed files with 340 additions and 84 deletions
|
@ -19,6 +19,8 @@ impl Bytecode {
|
||||||
0x06 => (Instruction::PushConstInt3(), 1),
|
0x06 => (Instruction::PushConstInt3(), 1),
|
||||||
0x07 => (Instruction::PushConstInt4(), 1),
|
0x07 => (Instruction::PushConstInt4(), 1),
|
||||||
0x08 => (Instruction::PushConstInt5(), 1),
|
0x08 => (Instruction::PushConstInt5(), 1),
|
||||||
|
0x09 => (Instruction::PushConstLong0(), 1),
|
||||||
|
0x0A => (Instruction::PushConstLong1(), 1),
|
||||||
0x0B => (Instruction::PushConstFloat0(), 1),
|
0x0B => (Instruction::PushConstFloat0(), 1),
|
||||||
0x0C => (Instruction::PushConstFloat1(), 1),
|
0x0C => (Instruction::PushConstFloat1(), 1),
|
||||||
0x0D => (Instruction::PushConstFloat2(), 1),
|
0x0D => (Instruction::PushConstFloat2(), 1),
|
||||||
|
@ -86,6 +88,7 @@ impl Bytecode {
|
||||||
0x57 => (Instruction::Pop(), 1),
|
0x57 => (Instruction::Pop(), 1),
|
||||||
0x59 => (Instruction::Duplicate(), 1),
|
0x59 => (Instruction::Duplicate(), 1),
|
||||||
0x5A => (Instruction::DuplicateInsertDown(), 1),
|
0x5A => (Instruction::DuplicateInsertDown(), 1),
|
||||||
|
0x5C => (Instruction::DuplicateComputationalValue(), 1),
|
||||||
|
|
||||||
0x60 => (Instruction::AddInt(), 1),
|
0x60 => (Instruction::AddInt(), 1),
|
||||||
0x61 => (Instruction::AddLong(), 1),
|
0x61 => (Instruction::AddLong(), 1),
|
||||||
|
@ -302,6 +305,8 @@ pub enum Instruction {
|
||||||
PushConstInt3() = 0x06, // Push 3
|
PushConstInt3() = 0x06, // Push 3
|
||||||
PushConstInt4() = 0x07, // Push 4
|
PushConstInt4() = 0x07, // Push 4
|
||||||
PushConstInt5() = 0x08, // Push 5
|
PushConstInt5() = 0x08, // Push 5
|
||||||
|
PushConstLong0() = 0x09, // Push 0
|
||||||
|
PushConstLong1() = 0x0A, // Push 1
|
||||||
PushConstFloat0() = 0x0B, // Push 0.0f
|
PushConstFloat0() = 0x0B, // Push 0.0f
|
||||||
PushConstFloat1() = 0x0C, // Push 1.0f
|
PushConstFloat1() = 0x0C, // Push 1.0f
|
||||||
PushConstFloat2() = 0x0D, // Push 2.0f
|
PushConstFloat2() = 0x0D, // Push 2.0f
|
||||||
|
@ -366,6 +371,7 @@ pub enum Instruction {
|
||||||
Pop() = 0x57, // Pop top stack value
|
Pop() = 0x57, // Pop top stack value
|
||||||
Duplicate() = 0x59, // duplicate top stack value
|
Duplicate() = 0x59, // duplicate top stack value
|
||||||
DuplicateInsertDown() = 0x5A, // duplicate top stack value and insert two low
|
DuplicateInsertDown() = 0x5A, // duplicate top stack value and insert two low
|
||||||
|
DuplicateComputationalValue() = 0x5C, // duplicate top computational value
|
||||||
|
|
||||||
AddInt() = 0x60, // int addition
|
AddInt() = 0x60, // int addition
|
||||||
AddLong() = 0x61, // long addition
|
AddLong() = 0x61, // long addition
|
||||||
|
|
|
@ -280,12 +280,15 @@ impl ObjectArea {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_reference_class_ref(&self, reference: ObjectReference, class_store: &ClassStore) -> ObjectReference {
|
pub fn get_reference_class_ref(&self, reference: ObjectReference, class_store: &ClassStore) -> ObjectReference {
|
||||||
match self.get_entry(reference) {
|
match self.get_entry(reference) {
|
||||||
CompartmentEntry::Object(o) => class_store.get_class_objectref_from_index(o.class_index),
|
CompartmentEntry::Object(o) => class_store.get_class_objectref_from_index(o.class_index),
|
||||||
CompartmentEntry::ReferenceArray(a) => a.class_ref,
|
CompartmentEntry::ReferenceArray(a) => a.class_ref,
|
||||||
CompartmentEntry::ByteArray(a) => a.class_ref,
|
CompartmentEntry::ByteArray(a) => a.class_ref,
|
||||||
_ => unreachable!(),
|
CompartmentEntry::CharArray(a) => a.class_ref,
|
||||||
|
CompartmentEntry::IntArray(a) => a.class_ref,
|
||||||
|
CompartmentEntry::EmptyNext(_) => unreachable!(),
|
||||||
|
CompartmentEntry::EmptyTail() => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,6 +329,18 @@ impl ObjectArea {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_array_reference(&mut self, reference: ObjectReference) -> bool {
|
||||||
|
match self.get_entry(reference) {
|
||||||
|
CompartmentEntry::Object(_) => false,
|
||||||
|
CompartmentEntry::ReferenceArray(_) => true,
|
||||||
|
CompartmentEntry::ByteArray(_) => true,
|
||||||
|
CompartmentEntry::CharArray(_) => true,
|
||||||
|
CompartmentEntry::IntArray(_) => true,
|
||||||
|
CompartmentEntry::EmptyNext(_) => true,
|
||||||
|
CompartmentEntry::EmptyTail() => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_array_length(&self, reference: ObjectReference) -> usize {
|
pub fn get_array_length(&self, reference: ObjectReference) -> usize {
|
||||||
// TODO: Throw errors
|
// TODO: Throw errors
|
||||||
match self.get_entry(reference) {
|
match self.get_entry(reference) {
|
||||||
|
@ -734,14 +749,14 @@ impl FieldValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_reference(&self) -> ObjectReference {
|
pub fn expect_reference(&self) -> ObjectReference {
|
||||||
match self {
|
match self {
|
||||||
Self::Reference(r) => *r,
|
Self::Reference(r) => *r,
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_byte(&self) -> i8 {
|
pub fn expect_byte(&self) -> i8 {
|
||||||
match self {
|
match self {
|
||||||
Self::Byte(b) => *b,
|
Self::Byte(b) => *b,
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
|
|
101
src/jvm.rs
101
src/jvm.rs
|
@ -706,8 +706,8 @@ impl JVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::ArithmeticShiftIntLeft() => {
|
Instruction::ArithmeticShiftIntLeft() => {
|
||||||
let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))? as u8 & 0b00011111;
|
let shift = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))? as u8 & 0b00011111;
|
||||||
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
|
|
||||||
// rust does arithmetic shift on singed values
|
// rust does arithmetic shift on singed values
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int << shift)))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(int << shift)))?;
|
||||||
|
@ -746,8 +746,8 @@ impl JVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::AndInt() => {
|
Instruction::AndInt() => {
|
||||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
|
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 & value_2)))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_1 & value_2)))?;
|
||||||
}
|
}
|
||||||
|
@ -758,8 +758,8 @@ impl JVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::BranchIntEquality(branch_offset) => {
|
Instruction::BranchIntEquality(branch_offset) => {
|
||||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
|
|
||||||
if value_1 == value_2 {
|
if value_1 == value_2 {
|
||||||
frame.instruction_pointer -= offset as u32;
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
@ -768,8 +768,8 @@ impl JVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::BranchIntGreaterEquals(branch_offset) => {
|
Instruction::BranchIntGreaterEquals(branch_offset) => {
|
||||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
|
|
||||||
if value_1 >= value_2 {
|
if value_1 >= value_2 {
|
||||||
frame.instruction_pointer -= offset as u32;
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
@ -778,8 +778,8 @@ impl JVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::BranchIntGreaterThan(branch_offset) => {
|
Instruction::BranchIntGreaterThan(branch_offset) => {
|
||||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
|
|
||||||
if value_1 > value_2 {
|
if value_1 > value_2 {
|
||||||
frame.instruction_pointer -= offset as u32;
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
@ -788,8 +788,8 @@ impl JVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::BranchIntInequality(branch_offset) => {
|
Instruction::BranchIntInequality(branch_offset) => {
|
||||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
|
|
||||||
if value_1 != value_2 {
|
if value_1 != value_2 {
|
||||||
frame.instruction_pointer -= offset as u32;
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
@ -798,8 +798,8 @@ impl JVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::BranchIntLessEquals(branch_offset) => {
|
Instruction::BranchIntLessEquals(branch_offset) => {
|
||||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int_compatible(0))?;
|
||||||
|
|
||||||
if value_1 <= value_2 {
|
if value_1 <= value_2 {
|
||||||
frame.instruction_pointer -= offset as u32;
|
frame.instruction_pointer -= offset as u32;
|
||||||
|
@ -1100,6 +1100,18 @@ impl JVM {
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(popped_value))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push(popped_value))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::DuplicateComputationalValue() => {
|
||||||
|
if frame.operand_stack.computational_type_at(0) == 1 {
|
||||||
|
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))?;
|
||||||
|
} else {
|
||||||
|
let popped_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_2(0))?;
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(popped_value))?;
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push_field_value(popped_value))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::DuplicateInsertDown() => {
|
Instruction::DuplicateInsertDown() => {
|
||||||
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?;
|
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?;
|
||||||
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?;
|
let value_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?;
|
||||||
|
@ -1182,34 +1194,39 @@ impl JVM {
|
||||||
Instruction::InstanceOf(classref_index) => {
|
Instruction::InstanceOf(classref_index) => {
|
||||||
let class_name = class.gather_class(classref_index)?;
|
let class_name = class.gather_class(classref_index)?;
|
||||||
let object = wrap_stackframe_error(class, method, frame.operand_stack.peek_reference(0))?;
|
let object = wrap_stackframe_error(class, method, frame.operand_stack.peek_reference(0))?;
|
||||||
let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store);
|
|
||||||
|
|
||||||
if class_name.starts_with("[") {
|
let instruction_result = if object == ObjectReference::NULL {
|
||||||
// TODO: Create array class on demand
|
frame.operand_stack.pop_reference(0).unwrap();
|
||||||
|
0
|
||||||
} else {
|
} else {
|
||||||
if ! self.class_store.have_class(class_name) {
|
let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store);
|
||||||
frame.instruction_pointer -= offset as u32;
|
|
||||||
return Ok(JVMCallbackOperation::LoadClass(class_name.to_string()));
|
if class_name.starts_with("[") {
|
||||||
|
// TODO: Create array class on demand
|
||||||
|
} 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()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ! self.class_store.was_init(class_name).unwrap() {
|
|
||||||
frame.instruction_pointer -= offset as u32;
|
frame.operand_stack.pop_reference(0).unwrap();
|
||||||
return Ok(JVMCallbackOperation::InitClass(class_name.to_string()));
|
|
||||||
|
if class_name == native_class_name {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store);
|
||||||
|
let class_description = AbstractTypeDescription::parse_full(native_class_description)?;
|
||||||
|
|
||||||
|
let object_description = AbstractTypeDescription::parse_full(native_class_name)?;
|
||||||
|
if self.class_store.are_types_compatible(&object_description, &class_description) { 1 } else { 0 }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
frame.operand_stack.pop_reference(0).unwrap();
|
|
||||||
|
|
||||||
|
|
||||||
let instruction_result = if class_name == native_class_name {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
let native_class_description = self.heap_area.object_area.get_class_ref_native_class_name(class_object_ref, &self.class_store);
|
|
||||||
let class_description = AbstractTypeDescription::parse_full(native_class_description)?;
|
|
||||||
|
|
||||||
let object_description = AbstractTypeDescription::parse_full(native_class_name)?;
|
|
||||||
if self.class_store.are_types_compatible(&object_description, &class_description) { 1 } else { 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1924,6 +1941,13 @@ impl JVM {
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(5)))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(5)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::PushConstLong0() => {
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push_long(0))?;
|
||||||
|
}
|
||||||
|
Instruction::PushConstLong1() => {
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push_long(1))?;
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::PushNull() => {
|
Instruction::PushNull() => {
|
||||||
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(ObjectReference::NULL)))?;
|
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(ObjectReference::NULL)))?;
|
||||||
}
|
}
|
||||||
|
@ -1937,6 +1961,7 @@ impl JVM {
|
||||||
StackValue::Int(i) => {
|
StackValue::Int(i) => {
|
||||||
match expected_field_descriptor.as_str() {
|
match expected_field_descriptor.as_str() {
|
||||||
"Z" => FieldValue::Boolean(i != 0),
|
"Z" => FieldValue::Boolean(i != 0),
|
||||||
|
"B" => FieldValue::Byte(i as i8),
|
||||||
_ => FieldValue::Int(i)
|
_ => FieldValue::Int(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::classfile::FieldInfo;
|
||||||
|
use crate::classstore::ClassStore;
|
||||||
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;
|
||||||
|
@ -344,9 +346,204 @@ impl JavaLangStringUTF16 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct JavaLangSystem {}
|
||||||
|
|
||||||
|
impl JavaLangSystem {
|
||||||
|
pub fn arraycopy(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
|
let frame = {
|
||||||
|
let frame_index = jvm.stack_frames.len() - 1;
|
||||||
|
&mut jvm.stack_frames[frame_index]
|
||||||
|
};
|
||||||
|
let src = frame.load_local_reference(0).unwrap();
|
||||||
|
let src_pos = frame.load_local_int(1).unwrap();
|
||||||
|
let dest = frame.load_local_reference(2).unwrap();
|
||||||
|
let dest_pos = frame.load_local_int(3).unwrap();
|
||||||
|
let length = frame.load_local_int(4).unwrap();
|
||||||
|
|
||||||
|
for i in 0..length {
|
||||||
|
let src_value = jvm.heap_area.object_area.get_array_element(src, src_pos + i);
|
||||||
|
jvm.heap_area.object_area.set_array_element(dest, (dest_pos + i) as usize, src_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::PopFrame())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct JavaLangThrowable {}
|
||||||
|
|
||||||
|
impl JavaLangThrowable {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
struct JdkInternalMiscUnsafe {}
|
struct JdkInternalMiscUnsafe {}
|
||||||
|
|
||||||
impl JdkInternalMiscUnsafe {
|
impl JdkInternalMiscUnsafe {
|
||||||
|
|
||||||
|
fn class_field_at_offset(class_index: usize, class_store: &ClassStore, offset: i64) -> Result<&FieldInfo, Error> {
|
||||||
|
let mut offset_counter = offset;
|
||||||
|
match ClassFieldIterator::new(class_index, class_store)
|
||||||
|
.take_while(|f| {
|
||||||
|
let result = offset_counter >= 0;
|
||||||
|
offset_counter -= f.descriptor.storage_size() as i64;
|
||||||
|
|
||||||
|
result
|
||||||
|
})
|
||||||
|
.last() {
|
||||||
|
Some(f) => Ok(f),
|
||||||
|
None => Err(Error::RunTimeError(format!("Couldn't find int field at offset {offset} in class {}", class_store.class_name_from_index(class_index).unwrap())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_class_reference_index_scale(class_reference: ObjectReference, jvm: &JVM) -> i32 {
|
||||||
|
let class_class_index = jvm.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap();
|
||||||
|
let component_class_reference = match jvm.heap_area.object_area.get_object_field(class_reference, "componentType", class_class_index, &jvm.class_store).unwrap() {
|
||||||
|
FieldValue::Reference(r) => r,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if component_class_reference == jvm.class_store.primitive_classes.boolean_class {
|
||||||
|
1
|
||||||
|
} else if component_class_reference == jvm.class_store.primitive_classes.byte_class {
|
||||||
|
1
|
||||||
|
} else if component_class_reference == jvm.class_store.primitive_classes.short_class {
|
||||||
|
2
|
||||||
|
} else if component_class_reference == jvm.class_store.primitive_classes.char_class {
|
||||||
|
2
|
||||||
|
} else if component_class_reference == jvm.class_store.primitive_classes.int_class {
|
||||||
|
4
|
||||||
|
} else if component_class_reference == jvm.class_store.primitive_classes.float_class {
|
||||||
|
4
|
||||||
|
} else if component_class_reference == jvm.class_store.primitive_classes.double_class {
|
||||||
|
8
|
||||||
|
} else if component_class_reference == jvm.class_store.primitive_classes.long_class {
|
||||||
|
8
|
||||||
|
} else {
|
||||||
|
std::mem::size_of::<usize>() as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compare_and_set_reference(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
|
let frame = {
|
||||||
|
let frame_index = jvm.stack_frames.len() - 1;
|
||||||
|
&mut jvm.stack_frames[frame_index]
|
||||||
|
};
|
||||||
|
|
||||||
|
let object = frame.load_local_reference(1).unwrap();
|
||||||
|
let offset = frame.load_local_long(2).unwrap();
|
||||||
|
let expected = frame.load_local_reference(4).unwrap();
|
||||||
|
let replacement = frame.load_local_reference(5).unwrap();
|
||||||
|
|
||||||
|
if jvm.heap_area.object_area.is_array_reference(object) {
|
||||||
|
let class_reference = jvm.heap_area.object_area.get_reference_class_ref(object, &jvm.class_store);
|
||||||
|
let scale = JdkInternalMiscUnsafe::array_class_reference_index_scale(class_reference, jvm);
|
||||||
|
let index = offset / (scale as i64);
|
||||||
|
|
||||||
|
let value = jvm.heap_area.object_area.get_array_element(object, index as i32);
|
||||||
|
|
||||||
|
let success = if value.expect_reference() == expected {
|
||||||
|
jvm.heap_area.object_area.set_array_element(object, index as usize, replacement.into());
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Boolean(success)))
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_reference_volatile(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
|
let frame = {
|
||||||
|
let frame_index = jvm.stack_frames.len() - 1;
|
||||||
|
&mut jvm.stack_frames[frame_index]
|
||||||
|
};
|
||||||
|
|
||||||
|
let object = frame.load_local_reference(1).unwrap();
|
||||||
|
let offset = frame.load_local_long(2).unwrap();
|
||||||
|
let replacement = frame.load_local_reference(4).unwrap();
|
||||||
|
|
||||||
|
if jvm.heap_area.object_area.is_array_reference(object) {
|
||||||
|
let class_reference = jvm.heap_area.object_area.get_reference_class_ref(object, &jvm.class_store);
|
||||||
|
let scale = JdkInternalMiscUnsafe::array_class_reference_index_scale(class_reference, jvm);
|
||||||
|
let index = offset / (scale as i64);
|
||||||
|
|
||||||
|
jvm.heap_area.object_area.set_array_element(object, index as usize, replacement.into());
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::PopFrame())
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_reference_volatile(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
|
let frame = {
|
||||||
|
let frame_index = jvm.stack_frames.len() - 1;
|
||||||
|
&mut jvm.stack_frames[frame_index]
|
||||||
|
};
|
||||||
|
|
||||||
|
let object = frame.load_local_reference(1).unwrap();
|
||||||
|
let offset = frame.load_local_long(2).unwrap();
|
||||||
|
|
||||||
|
if jvm.heap_area.object_area.is_array_reference(object) {
|
||||||
|
let class_reference = jvm.heap_area.object_area.get_reference_class_ref(object, &jvm.class_store);
|
||||||
|
let scale = JdkInternalMiscUnsafe::array_class_reference_index_scale(class_reference, jvm);
|
||||||
|
let index = offset / (scale as i64);
|
||||||
|
|
||||||
|
let value = jvm.heap_area.object_area.get_array_element(object, index as i32);
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(value))
|
||||||
|
} else {
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
// TODO: Type checking
|
||||||
|
let value = jvm.heap_area.object_area.get_object_field(
|
||||||
|
object,
|
||||||
|
&field.name,
|
||||||
|
object_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compare_and_set_long(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
|
let frame = {
|
||||||
|
let frame_index = jvm.stack_frames.len() - 1;
|
||||||
|
&mut jvm.stack_frames[frame_index]
|
||||||
|
};
|
||||||
|
|
||||||
|
let object = frame.load_local_reference(1).unwrap();
|
||||||
|
let offset = frame.load_local_long(2).unwrap();
|
||||||
|
let expected = frame.load_local_long(4).unwrap();
|
||||||
|
let replacement = frame.load_local_long(6).unwrap();
|
||||||
|
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
// TODO: Type checking
|
||||||
|
let function_result = if jvm.heap_area.object_area.get_object_field(object, &field.name, object_class_index, &jvm.class_store)? == FieldValue::Long(expected) {
|
||||||
|
jvm.heap_area.object_area.set_object_field(
|
||||||
|
object,
|
||||||
|
&field.name,
|
||||||
|
FieldValue::Long(replacement),
|
||||||
|
object_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
)?;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Boolean(function_result)))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn compare_and_set_int(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
pub fn compare_and_set_int(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;
|
||||||
|
@ -361,19 +558,9 @@ impl JdkInternalMiscUnsafe {
|
||||||
let object_class_descriptor = jvm.heap_area.object_area.get_reference_native_class_name(object, &jvm.class_store);
|
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 object_class_index = jvm.class_store.class_index_for_type(AbstractTypeDescription::parse_full(object_class_descriptor).unwrap()).unwrap();
|
||||||
|
|
||||||
let mut offset_counter = offset;
|
let field = JdkInternalMiscUnsafe::class_field_at_offset(object_class_index, &jvm.class_store, offset)?;
|
||||||
let field = match ClassFieldIterator::new(object_class_index, &jvm.class_store)
|
|
||||||
.take_while(|f| {
|
|
||||||
let result = offset_counter >= 0;
|
|
||||||
offset_counter -= f.descriptor.storage_size() as i64;
|
|
||||||
|
|
||||||
result
|
|
||||||
})
|
|
||||||
.last() {
|
|
||||||
Some(f) => f,
|
|
||||||
None => return Err(Error::RunTimeError(format!("Couldn't find int field at offset {offset} in class {object_class_descriptor}")))
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// TODO: Type checking
|
||||||
let function_result = if jvm.heap_area.object_area.get_object_field(object, &field.name, object_class_index, &jvm.class_store)? == FieldValue::Int(expected) {
|
let function_result = if jvm.heap_area.object_area.get_object_field(object, &field.name, object_class_index, &jvm.class_store)? == FieldValue::Int(expected) {
|
||||||
jvm.heap_area.object_area.set_object_field(
|
jvm.heap_area.object_area.set_object_field(
|
||||||
object,
|
object,
|
||||||
|
@ -419,33 +606,10 @@ impl JdkInternalMiscUnsafe {
|
||||||
};
|
};
|
||||||
let class = jvm.class_store.class_file_from_idx(frame.class_index).unwrap();
|
let class = jvm.class_store.class_file_from_idx(frame.class_index).unwrap();
|
||||||
let method = & class.methods[frame.method_index as usize];
|
let method = & class.methods[frame.method_index as usize];
|
||||||
let class_class_index = jvm.class_store.class_idx_from_name(&String::from("java/lang/Class")).unwrap();
|
|
||||||
|
|
||||||
let class_reference = wrap_stackframe_error(class, method, frame.load_local_reference(1))?;
|
let class_reference = wrap_stackframe_error(class, method, frame.load_local_reference(1))?;
|
||||||
let component_class_reference = match jvm.heap_area.object_area.get_object_field(class_reference, "componentType", class_class_index, &jvm.class_store).unwrap() {
|
|
||||||
FieldValue::Reference(r) => r,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let index_scale: i32 = if component_class_reference == jvm.class_store.primitive_classes.boolean_class {
|
let index_scale = JdkInternalMiscUnsafe::array_class_reference_index_scale(class_reference, jvm);
|
||||||
1
|
|
||||||
} else if component_class_reference == jvm.class_store.primitive_classes.byte_class {
|
|
||||||
1
|
|
||||||
} else if component_class_reference == jvm.class_store.primitive_classes.short_class {
|
|
||||||
2
|
|
||||||
} else if component_class_reference == jvm.class_store.primitive_classes.char_class {
|
|
||||||
2
|
|
||||||
} else if component_class_reference == jvm.class_store.primitive_classes.int_class {
|
|
||||||
4
|
|
||||||
} else if component_class_reference == jvm.class_store.primitive_classes.float_class {
|
|
||||||
4
|
|
||||||
} else if component_class_reference == jvm.class_store.primitive_classes.double_class {
|
|
||||||
8
|
|
||||||
} else if component_class_reference == jvm.class_store.primitive_classes.long_class {
|
|
||||||
8
|
|
||||||
} else {
|
|
||||||
std::mem::size_of::<usize>() as i32
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(index_scale)))
|
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(index_scale)))
|
||||||
}
|
}
|
||||||
|
@ -507,13 +671,16 @@ impl JdkInternalUtilSystemPropsRaw {
|
||||||
// command-line configured properties, should return at least java.home
|
// command-line configured properties, should return at least java.home
|
||||||
pub fn vm_properties(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
pub fn vm_properties(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
let native_array = vec![
|
let native_array = vec![
|
||||||
("java.home", "./"),
|
("java.home", "./"), // TODO
|
||||||
("stdout.encoding", "UTF-8"),
|
("stdout.encoding", "UTF-8"),
|
||||||
("java.io.tmpdir", "/tmp"),
|
("java.io.tmpdir", "/tmp"),
|
||||||
("user.language", "en"),
|
("user.language", "en"),
|
||||||
("user.script", ""),
|
("user.script", ""),
|
||||||
("user.country", "US"),
|
("user.country", "US"),
|
||||||
("user.variant", ""),
|
("user.variant", ""),
|
||||||
|
("user.dir", "./"),
|
||||||
|
("user.home", "./"), // TODO
|
||||||
|
("user.name", "java"), // TODO
|
||||||
("sun.nio.MaxDirectMemorySize", "9223372036854775807"),
|
("sun.nio.MaxDirectMemorySize", "9223372036854775807"),
|
||||||
("sun.nio.PageAlignDirectMemory", "false"),
|
("sun.nio.PageAlignDirectMemory", "false"),
|
||||||
];
|
];
|
||||||
|
@ -1121,7 +1288,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
]),
|
]),
|
||||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void()},
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void()},
|
||||||
},
|
},
|
||||||
todo_call
|
JavaLangSystem::arraycopy
|
||||||
),
|
),
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -1450,7 +1617,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
]),
|
]),
|
||||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
|
||||||
},
|
},
|
||||||
todo_call
|
JdkInternalMiscUnsafe::compare_and_set_long
|
||||||
),
|
),
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -1465,7 +1632,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
]),
|
]),
|
||||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Boolean() },
|
||||||
},
|
},
|
||||||
todo_call
|
JdkInternalMiscUnsafe::compare_and_set_reference
|
||||||
),
|
),
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -1772,7 +1939,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
]),
|
]),
|
||||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Object"))},
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname(String::from("java/lang/Object"))},
|
||||||
},
|
},
|
||||||
todo_call
|
JdkInternalMiscUnsafe::get_reference_volatile
|
||||||
),
|
),
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -2215,7 +2382,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
]),
|
]),
|
||||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Void() },
|
||||||
},
|
},
|
||||||
todo_call
|
JdkInternalMiscUnsafe::put_reference_volatile
|
||||||
),
|
),
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -2684,6 +2851,18 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
},
|
},
|
||||||
todo_call
|
todo_call
|
||||||
),
|
),
|
||||||
|
|
||||||
|
(
|
||||||
|
"java/lang/Throwable",
|
||||||
|
"fillInStackTrace",
|
||||||
|
MethodDescriptor {
|
||||||
|
argument_types: Box::new([
|
||||||
|
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int()}
|
||||||
|
]),
|
||||||
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Throwable".to_string())},
|
||||||
|
},
|
||||||
|
JavaLangThrowable::fill_in_stacktrace()
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (classname, methodname, methoddescriptor, binding) in native_mappings {
|
for (classname, methodname, methoddescriptor, binding) in native_mappings {
|
||||||
|
|
|
@ -105,6 +105,26 @@ impl OperandStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn computational_type_at(&self, index: usize) -> u8 {
|
||||||
|
let absolute_index = self.depth as usize - 1 - index;
|
||||||
|
|
||||||
|
match self.stack[absolute_index] {
|
||||||
|
StackValue::Boolean(_) => 1,
|
||||||
|
StackValue::Byte(_) => 1,
|
||||||
|
StackValue::Char(_) => 1,
|
||||||
|
StackValue::Short(_) => 1,
|
||||||
|
StackValue::Int(_) => 1,
|
||||||
|
StackValue::Float(_) => 1,
|
||||||
|
StackValue::Reference(_) => 1,
|
||||||
|
StackValue::ReturnAddress(_) => 1,
|
||||||
|
StackValue::Double0(_) => 0,
|
||||||
|
StackValue::Double1() => 0,
|
||||||
|
StackValue::Long0(_) => 0,
|
||||||
|
StackValue::Long1() => 0,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pop_computational_2(&mut self, index: usize) -> Result<FieldValue, Error> {
|
pub fn pop_computational_2(&mut self, index: usize) -> Result<FieldValue, Error> {
|
||||||
let absolute_index = self.depth as usize - 1 - index;
|
let absolute_index = self.depth as usize - 1 - index;
|
||||||
let value_top = self.stack[absolute_index];
|
let value_top = self.stack[absolute_index];
|
||||||
|
@ -187,6 +207,17 @@ impl OperandStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pop_int_compatible(&mut self, index: usize) -> Result<i32, Error> {
|
||||||
|
let absolute_index = self.depth as usize - 1 - index;
|
||||||
|
let value = self.stack[absolute_index];
|
||||||
|
self.depth -= 1;
|
||||||
|
match value {
|
||||||
|
StackValue::Int(i) => Ok(i),
|
||||||
|
StackValue::Byte(b) => Ok(b as i32),
|
||||||
|
_ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Int-compatible but found '{:?}'", index, value)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pop_float(&mut self, index: usize) -> Result<f32, Error> {
|
pub fn pop_float(&mut self, index: usize) -> Result<f32, Error> {
|
||||||
let absolute_index = self.depth as usize - 1 - index;
|
let absolute_index = self.depth as usize - 1 - index;
|
||||||
let value = self.stack[absolute_index];
|
let value = self.stack[absolute_index];
|
||||||
|
|
Loading…
Reference in a new issue