Implemented VM.initalize and LoadConstant64
This commit is contained in:
parent
b4c33a0d9b
commit
43ceaa95bb
3 changed files with 204 additions and 13 deletions
39
src/jvm.rs
39
src/jvm.rs
|
@ -1045,11 +1045,26 @@ impl JVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::InstanceOf(classref_index) => {
|
Instruction::InstanceOf(classref_index) => {
|
||||||
// TODO: Class loading checks
|
|
||||||
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.pop_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);
|
let native_class_name = self.heap_area.object_area.get_reference_native_class_name(object, &self.class_store);
|
||||||
|
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.operand_stack.pop_reference(0).unwrap();
|
||||||
|
|
||||||
|
|
||||||
let instruction_result = if class_name == native_class_name {
|
let instruction_result = if class_name == native_class_name {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
|
@ -1449,6 +1464,20 @@ impl JVM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::LoadConstant64(wide_index) => {
|
||||||
|
match class.pool_entry(wide_index).unwrap() {
|
||||||
|
ConstantPoolInfo::Long(long_data) => {
|
||||||
|
let long_value = long_data.value;
|
||||||
|
|
||||||
|
wrap_stackframe_error(class, method, frame.operand_stack.push_long(long_value))?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("{:?}", class.pool_entry(wide_index).unwrap());
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::LoadLocalFloat(index) => {
|
Instruction::LoadLocalFloat(index) => {
|
||||||
load_local_float(class, method, frame, index as usize)?;
|
load_local_float(class, method, frame, index as usize)?;
|
||||||
}
|
}
|
||||||
|
@ -1749,6 +1778,12 @@ impl JVM {
|
||||||
FieldValue::Int(int_value)
|
FieldValue::Int(int_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(0, AbstractTypeKind::Long()) => {
|
||||||
|
let long_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_long(0))?;
|
||||||
|
|
||||||
|
FieldValue::Long(long_value)
|
||||||
|
}
|
||||||
|
|
||||||
(0..=255, AbstractTypeKind::Classname(_field_type_name)) => {
|
(0..=255, AbstractTypeKind::Classname(_field_type_name)) => {
|
||||||
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
|
||||||
|
|
||||||
|
|
|
@ -395,22 +395,42 @@ 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 array_length = 4;
|
let native_array = vec![
|
||||||
|
("java.home", "./"),
|
||||||
|
("stdout.encoding", "UTF-8"),
|
||||||
|
("java.io.tmpdir", "/tmp"),
|
||||||
|
("user.language", "en"),
|
||||||
|
("user.script", ""),
|
||||||
|
("user.country", "US"),
|
||||||
|
("user.variant", ""),
|
||||||
|
];
|
||||||
|
// TODO: Cross-Platform tmpdir
|
||||||
|
// TODO: locale detection
|
||||||
|
let array_length = native_array.len() * 2 + 2;
|
||||||
let array_reference = jvm.heap_area.make_empty_array(&jvm.class_store, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()) }, array_length);
|
let array_reference = jvm.heap_area.make_empty_array(&jvm.class_store, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()) }, array_length);
|
||||||
|
|
||||||
{
|
for (index, (key, value)) in native_array.iter().enumerate() {
|
||||||
// TODO: Actual java home path
|
let key_string: String = key.to_string();
|
||||||
let java_home_key_reference = jvm.heap_area.make_handmade_string(&String::from("java.home"), &jvm.class_store);
|
let value_string: String = value.to_string();
|
||||||
let java_home_value_reference = jvm.heap_area.make_handmade_string(&String::from("./"), &jvm.class_store);
|
let key_reference = jvm.heap_area.make_handmade_string(&key_string, &jvm.class_store);
|
||||||
|
let value_reference = jvm.heap_area.make_handmade_string(&value_string, &jvm.class_store);
|
||||||
|
|
||||||
jvm.heap_area.object_area.set_array_element(array_reference, 0, java_home_key_reference.into());
|
jvm.heap_area.object_area.set_array_element(array_reference, index * 2 , key_reference.into());
|
||||||
jvm.heap_area.object_area.set_array_element(array_reference, 1, java_home_value_reference.into());
|
jvm.heap_area.object_area.set_array_element(array_reference, index * 2 + 1, value_reference.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference)))
|
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct JdkInternalMiscVM {}
|
||||||
|
|
||||||
|
impl JdkInternalMiscVM {
|
||||||
|
pub fn initialize(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
|
Ok(JVMCallbackOperation::PopFrame())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Result<NativeMethodCallable, Error> {
|
pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Result<NativeMethodCallable, Error> {
|
||||||
let method_name: &str = &m.name;
|
let method_name: &str = &m.name;
|
||||||
|
@ -2548,6 +2568,119 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
Ok(todo_call)
|
Ok(todo_call)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
("jdk/internal/misc/VM", "getgid") => {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
("jdk/internal/misc/VM", "getegid") => {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
("jdk/internal/misc/VM", "geteuid") => {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
("jdk/internal/misc/VM", "getuid") => {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
("jdk/internal/misc/VM", "getNanoTimeAdjustment") => {
|
||||||
|
let expected_descriptor = MethodDescriptor {
|
||||||
|
argument_types: Box::new([
|
||||||
|
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Long()},
|
||||||
|
]),
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
("jdk/internal/misc/VM", "getRuntimeArguments") => {
|
||||||
|
let expected_descriptor = MethodDescriptor {
|
||||||
|
argument_types: Box::new([
|
||||||
|
]),
|
||||||
|
return_type: AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Classname("java/lang/String".to_string())},
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
("jdk/internal/misc/VM", "initialize") => {
|
||||||
|
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(JdkInternalMiscVM::initialize)
|
||||||
|
}
|
||||||
|
|
||||||
|
("jdk/internal/misc/VM", "latestUserDefinedLoader0") => {
|
||||||
|
let expected_descriptor = MethodDescriptor {
|
||||||
|
argument_types: Box::new([
|
||||||
|
]),
|
||||||
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/ClassLoader".to_string())},
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
("jdk/internal/util/SystemProps$Raw", "platformProperties") => {
|
("jdk/internal/util/SystemProps$Raw", "platformProperties") => {
|
||||||
let expected_descriptor = MethodDescriptor {
|
let expected_descriptor = MethodDescriptor {
|
||||||
argument_types: Box::new([
|
argument_types: Box::new([
|
||||||
|
|
|
@ -50,6 +50,17 @@ impl OperandStack {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push_long(&mut self, long: i64) -> Result<(), Error> {
|
||||||
|
let long_bytes: [u8; 8] = long.to_be_bytes();
|
||||||
|
|
||||||
|
let long0_bytes = u32::from_be_bytes([long_bytes[0], long_bytes[1], long_bytes[2], long_bytes[3]]);
|
||||||
|
self.push(StackValue::Long0(long0_bytes))?;
|
||||||
|
let long1_bytes = u32::from_be_bytes([long_bytes[4], long_bytes[5], long_bytes[6], long_bytes[7]]);
|
||||||
|
self.push(StackValue::Long1(long1_bytes))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push_field_value(&mut self, value: FieldValue) -> Result<(), Error> {
|
pub fn push_field_value(&mut self, value: FieldValue) -> Result<(), Error> {
|
||||||
match value {
|
match value {
|
||||||
FieldValue::Reference(r) => {
|
FieldValue::Reference(r) => {
|
||||||
|
@ -187,6 +198,15 @@ impl OperandStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn peek_reference(&mut self, index: usize) -> Result<ObjectReference, Error> {
|
||||||
|
let absolute_index = self.depth as usize - 1 - index;
|
||||||
|
let value = self.stack[absolute_index];
|
||||||
|
match value {
|
||||||
|
StackValue::Reference(o) => Ok(o),
|
||||||
|
_ => Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected Reference but found '{:?}'", index, value)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pop_returnaddress(&mut self, index: usize) -> Result<u32, Error> {
|
pub fn pop_returnaddress(&mut self, index: usize) -> Result<u32, 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];
|
||||||
|
@ -253,14 +273,17 @@ impl OperandStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_long(&mut self, index: usize) -> Result<u64, Error> {
|
pub fn pop_long(&mut self, index: usize) -> Result<i64, Error> {
|
||||||
let absolute_index = self.depth as usize - 1 - index;
|
let absolute_index = self.depth as usize - 1 - index;
|
||||||
let higher_bytes = self.stack[absolute_index];
|
let lower_bytes = self.stack[absolute_index];
|
||||||
let lower_bytes = self.stack[absolute_index + 1];
|
let higher_bytes = self.stack[absolute_index - 1];
|
||||||
self.depth -= 2;
|
self.depth -= 2;
|
||||||
match (higher_bytes, lower_bytes) {
|
match (higher_bytes, lower_bytes) {
|
||||||
(StackValue::Long0(hi), StackValue::Long1(lo)) => {
|
(StackValue::Long0(hi), StackValue::Long1(lo)) => {
|
||||||
Ok(((hi as u64) << 32) | lo as u64)
|
let concat_u64 = ((hi as u64) << 32) | lo as u64;
|
||||||
|
let concat_array = concat_u64.to_ne_bytes();
|
||||||
|
let long_value = i64::from_ne_bytes(concat_array);
|
||||||
|
Ok(long_value)
|
||||||
},
|
},
|
||||||
_ => Err(Error::LocalError(format!("Mismatched types at index {} of the function operand stack, expected (Long0, Long1) but found '{:?}'", index, (higher_bytes, lower_bytes))))
|
_ => Err(Error::LocalError(format!("Mismatched types at index {} of the function operand stack, expected (Long0, Long1) but found '{:?}'", index, (higher_bytes, lower_bytes))))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue