Implemented more opcodes and unsafe stuff
This commit is contained in:
parent
dfb6060df9
commit
d38d5b2897
5 changed files with 340 additions and 84 deletions
|
@ -1,3 +1,5 @@
|
|||
use crate::classfile::FieldInfo;
|
||||
use crate::classstore::ClassStore;
|
||||
use crate::stackframe::StackFrame;
|
||||
use crate::heap_area::ObjectReference;
|
||||
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 {}
|
||||
|
||||
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> {
|
||||
let frame = {
|
||||
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_index = jvm.class_store.class_index_for_type(AbstractTypeDescription::parse_full(object_class_descriptor).unwrap()).unwrap();
|
||||
|
||||
let mut offset_counter = 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}")))
|
||||
};
|
||||
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::Int(expected) {
|
||||
jvm.heap_area.object_area.set_object_field(
|
||||
object,
|
||||
|
@ -419,33 +606,10 @@ impl JdkInternalMiscUnsafe {
|
|||
};
|
||||
let class = jvm.class_store.class_file_from_idx(frame.class_index).unwrap();
|
||||
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 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 {
|
||||
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
|
||||
};
|
||||
let index_scale = JdkInternalMiscUnsafe::array_class_reference_index_scale(class_reference, jvm);
|
||||
|
||||
Ok(JVMCallbackOperation::ReturnFrame(FieldValue::Int(index_scale)))
|
||||
}
|
||||
|
@ -507,13 +671,16 @@ impl JdkInternalUtilSystemPropsRaw {
|
|||
// command-line configured properties, should return at least java.home
|
||||
pub fn vm_properties(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||
let native_array = vec![
|
||||
("java.home", "./"),
|
||||
("java.home", "./"), // TODO
|
||||
("stdout.encoding", "UTF-8"),
|
||||
("java.io.tmpdir", "/tmp"),
|
||||
("user.language", "en"),
|
||||
("user.script", ""),
|
||||
("user.country", "US"),
|
||||
("user.variant", ""),
|
||||
("user.dir", "./"),
|
||||
("user.home", "./"), // TODO
|
||||
("user.name", "java"), // TODO
|
||||
("sun.nio.MaxDirectMemorySize", "9223372036854775807"),
|
||||
("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()},
|
||||
},
|
||||
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() },
|
||||
},
|
||||
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() },
|
||||
},
|
||||
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"))},
|
||||
},
|
||||
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() },
|
||||
},
|
||||
todo_call
|
||||
JdkInternalMiscUnsafe::put_reference_volatile
|
||||
),
|
||||
|
||||
(
|
||||
|
@ -2684,6 +2851,18 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
|||
},
|
||||
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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue