I need to make smaller commits

This commit is contained in:
VegOwOtenks 2024-09-10 00:17:17 +02:00
parent 64eef60c4e
commit 0c54a1d7e1
8 changed files with 377 additions and 83 deletions

View file

@ -58,6 +58,7 @@ impl Bytecode {
0x57 => (Instruction::Pop(), 1), 0x57 => (Instruction::Pop(), 1),
0x59 => (Instruction::Duplicate(), 1), 0x59 => (Instruction::Duplicate(), 1),
0x60 => (Instruction::AddInt(), 1),
0x68 => (Instruction::MultiplyInt(), 1), 0x68 => (Instruction::MultiplyInt(), 1),
0x6C => (Instruction::DivideInt(), 1), 0x6C => (Instruction::DivideInt(), 1),
0x6D => (Instruction::DivideLong(), 1), 0x6D => (Instruction::DivideLong(), 1),
@ -80,7 +81,7 @@ impl Bytecode {
} }
0x9C => { 0x9C => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchNonPositive(i16::from_be_bytes(bytes)), 3) (Instruction::BranchNonNegative(i16::from_be_bytes(bytes)), 3)
} }
0x9D => { 0x9D => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
@ -88,7 +89,7 @@ impl Bytecode {
} }
0x9E => { 0x9E => {
let bytes = [self.bytes[offset+1], self.bytes[offset+2]]; let bytes = [self.bytes[offset+1], self.bytes[offset+2]];
(Instruction::BranchNonNegative(i16::from_be_bytes(bytes)), 3) (Instruction::BranchNonPositive(i16::from_be_bytes(bytes)), 3)
} }
0x9F => { 0x9F => {
@ -227,6 +228,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
AddInt() = 0x60, // int addition
MultiplyInt() = 0x68, // int multiplication MultiplyInt() = 0x68, // int multiplication
DivideInt() = 0x6C, // integer division, round toward zero and more rules DivideInt() = 0x6C, // integer division, round toward zero and more rules
DivideLong() = 0x6D, // long division DivideLong() = 0x6D, // long division
@ -238,9 +240,9 @@ pub enum Instruction {
BranchZero(i16) = 0x99, // branch if value == 0 BranchZero(i16) = 0x99, // branch if value == 0
BranchNonZero(i16) = 0x9A, // branch if value != 0 BranchNonZero(i16) = 0x9A, // branch if value != 0
BranchNegative(i16) = 0x9B, // branch if value < 0 BranchNegative(i16) = 0x9B, // branch if value < 0
BranchNonPositive(i16) = 0x9C, // branch if value <= 0 BranchNonNegative(i16) = 0x9C, // branch if value <= 0
BranchPositive(i16) = 0x9D, // branch if value > 0 BranchPositive(i16) = 0x9D, // branch if value > 0
BranchNonNegative(i16) = 0x9E, // branch if value >= 0 BranchNonPositive(i16) = 0x9E, // branch if value >= 0
BranchIntEquality(i16) = 0x9F, BranchIntEquality(i16) = 0x9F,
BranchIntInequality(i16) = 0xA0, BranchIntInequality(i16) = 0xA0,

View file

@ -5,7 +5,7 @@ use core::str::Utf8Error;
use crate::accessmasks::*; use crate::accessmasks::*;
use crate::bytecode::Bytecode; use crate::bytecode::Bytecode;
use crate::constantpool::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantStringInfo, ConstantMethodRefInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo }; use crate::constantpool::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantStringInfo, ConstantMethodRefInfo, ConstantFloatInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo };
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -246,6 +246,15 @@ impl JavaClassFile {
}; };
} }
pub fn pool_float_entry(&self, index: u16) -> Result<&ConstantFloatInfo, Error> {
let pool_entry = self.pool_entry(index)?;
return match pool_entry {
ConstantPoolInfo::Float(data) => Ok(data),
_ => Err(Error::BadFileError(format!("Expected constant pool entry {} in class {} to be of type Float but found {:?}", index, self.get_classname()?, pool_entry)))
};
}
pub fn pool_long_entry(&self, index: u16) -> Result<&ConstantLongInfo, Error> { pub fn pool_long_entry(&self, index: u16) -> Result<&ConstantLongInfo, Error> {
let pool_entry = self.pool_entry(index)?; let pool_entry = self.pool_entry(index)?;
@ -282,6 +291,12 @@ impl JavaClassFile {
}; };
} }
pub fn gather_float(&self, index: u16) -> Result<f32, Error> {
let float = self.pool_float_entry(index)?;
return Ok(float.value);
}
pub fn gather_string(&self, index: u16) -> Result<&String, Error> { pub fn gather_string(&self, index: u16) -> Result<&String, Error> {
let string = self.pool_string_entry(index)?; let string = self.pool_string_entry(index)?;
@ -775,8 +790,8 @@ impl From<&str> for AbstractTypeKind {
'J' => AbstractTypeKind::Long(), 'J' => AbstractTypeKind::Long(),
'S' => AbstractTypeKind::Short(), 'S' => AbstractTypeKind::Short(),
'Z' => AbstractTypeKind::Boolean(), 'Z' => AbstractTypeKind::Boolean(),
'L' => todo!(), 'L' => AbstractTypeKind::Classname(value.chars().skip(1).map_while(|c| if c != ';' { Some(c) } else { None } ).collect()),
_ => todo!(), _ => unreachable!(),
} }
} }
} }

View file

@ -12,24 +12,24 @@ use crate::iterators::CompatibleTypesIterator;
#[derive(Debug)] #[derive(Debug)]
pub struct ClassStore { pub struct ClassStore {
class_ids: HashMap<String, usize>, pub class_ids: HashMap<String, usize>,
array_classes: HashMap<AbstractTypeDescription, ObjectReference>, pub array_classes: HashMap<AbstractTypeDescription, ObjectReference>,
classes: Vec<ClassStoreEntry>, pub classes: Vec<ClassStoreEntry>,
class_path_fragments: Vec<PathBuf>, pub class_path_fragments: Vec<PathBuf>,
native_class_names: Vec<String>, pub native_class_names: Vec<String>,
primitive_classes: PrimitiveClassStore, pub primitive_classes: PrimitiveClassStore,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct PrimitiveClassStore { pub struct PrimitiveClassStore {
byte_class: ObjectReference, pub byte_class: ObjectReference,
char_class: ObjectReference, pub char_class: ObjectReference,
double_class: ObjectReference, pub double_class: ObjectReference,
float_class: ObjectReference, pub float_class: ObjectReference,
integer_class: ObjectReference, pub int_class: ObjectReference,
long_class: ObjectReference, pub long_class: ObjectReference,
short_class: ObjectReference, pub short_class: ObjectReference,
boolean_class: ObjectReference, pub boolean_class: ObjectReference,
} }
#[derive(Debug)] #[derive(Debug)]
@ -228,6 +228,27 @@ impl ClassStore {
AbstractTypeKind::Boolean() => { AbstractTypeKind::Boolean() => {
Some(self.primitive_classes.boolean_class) Some(self.primitive_classes.boolean_class)
} }
AbstractTypeKind::Byte() => {
Some(self.primitive_classes.byte_class)
}
AbstractTypeKind::Char() => {
Some(self.primitive_classes.char_class)
}
AbstractTypeKind::Double() => {
Some(self.primitive_classes.double_class)
}
AbstractTypeKind::Float() => {
Some(self.primitive_classes.float_class)
}
AbstractTypeKind::Int() => {
Some(self.primitive_classes.int_class)
}
AbstractTypeKind::Long() => {
Some(self.primitive_classes.long_class)
}
AbstractTypeKind::Short() => {
Some(self.primitive_classes.short_class)
}
_ => todo!(), _ => todo!(),
} }
} }

View file

@ -104,7 +104,7 @@ impl <'i>ClassMethodIterator<'i> {
} }
} }
impl <'i> Iterator for ClassMethodIterator<'i>{ impl <'i> Iterator for ClassMethodIterator<'i> {
type Item = (usize, usize, &'i MethodInfo); // class index, method index, method info type Item = (usize, usize, &'i MethodInfo); // class index, method index, method info
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {

View file

@ -13,8 +13,8 @@ use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference, CompartmentEntry }; use crate::heap_area::{ HeapArea, FieldValue, ObjectReference, CompartmentEntry };
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator }; use crate::iterators::{ ClassMethodIterator, ClassFieldIterator };
use crate::native_methods; use crate::native_methods;
use crate::native_methods::ignore_call; use crate::native_methods::{ EntryPoint, ignore_call };
use crate::native_registry::{ NativeRegistry }; use crate::native_registry::NativeRegistry;
use crate::stackframe; use crate::stackframe;
use crate::stackframe::{ StackFrame, StackValue, OperandStack }; use crate::stackframe::{ StackFrame, StackValue, OperandStack };
@ -233,10 +233,6 @@ impl JVM {
primitive_class_object primitive_class_object
} }
fn register_native(&mut self, class_name: &str, method_name: &str, method_descriptor: &MethodDescriptor) {
self.native_registry.register("java/lang/System", "registerNatives", ignore_call);
}
pub fn entrypoint(&mut self, class_name: &String, method_name: &String, arguments: &[&str]) -> Result<(), Error> { pub fn entrypoint(&mut self, class_name: &String, method_name: &String, arguments: &[&str]) -> Result<(), Error> {
let entry_class = JavaClassFile { let entry_class = JavaClassFile {
minor_version: 0, minor_version: 0,
@ -251,12 +247,17 @@ impl JVM {
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: class_name.to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: class_name.to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: method_name.to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: method_name.to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "([Ljava/lang/String;)V".to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "([Ljava/lang/String;)V".to_string() }),
ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 11, name_and_type_index: 13}), // 10 ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 1, name_and_type_index: 11}), // 10
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 12 } ), ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 12, descriptor_index: 13 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/String".to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "populateUnsafeConstants".to_string() }),
ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 14, descriptor_index: 15 }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "()V".to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "<init>".to_string() }), ConstantPoolInfo::Class(ConstantClassInfo { name_index: 15 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "([B)V".to_string() }), // 15 ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "jdk/internal/misc/UnsafeConstants".to_string() }), // 15
ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 17, name_and_type_index: 19}),
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 18 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/System".to_string() }),
ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 20, descriptor_index: 13 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "initPhase1".to_string() }),
] ]
), ),
access_flags: ClassAccessFlagMask { mask: ClassAccessFlag::Super.discriminant() }, access_flags: ClassAccessFlagMask { mask: ClassAccessFlag::Super.discriminant() },
@ -267,7 +268,7 @@ impl JVM {
methods: Box::new([ methods: Box::new([
MethodInfo { MethodInfo {
access_flags: MethodAccessFlagMask { access_flags: MethodAccessFlagMask {
mask: MethodAccessFlag::Public.discriminant() | MethodAccessFlag::Static.discriminant() mask: MethodAccessFlag::Private.discriminant() | MethodAccessFlag::Static.discriminant()
}, },
name: "call_main".to_string(), name: "call_main".to_string(),
descriptor: MethodDescriptor { descriptor: MethodDescriptor {
@ -287,8 +288,22 @@ impl JVM {
max_locals: 1, max_locals: 1,
code: Bytecode { code: Bytecode {
bytes: Box::new([ bytes: Box::new([
0x2A_u8.to_be(), // aload_0 // access something from UnsafeConstants
0x12_u8.to_be(), // ldc
0x0E_u8.to_be(), // index 14 into the constant pool
0x57_u8.to_be(), // pop
// Update UnsafeConstants to actual values
0xb8_u8.to_be(), // invokestatic
0x0A_u16.to_be_bytes()[0], // index 10 into the constant
0x0A_u16.to_be_bytes()[1], // pool
// call initPhase1
0xb8_u8.to_be(), // invokestatic
0x10_u16.to_be_bytes()[0], // index 10 into the constant
0x10_u16.to_be_bytes()[1], // pool
0x2A_u8.to_be(), // aload_0
0xB8_u8.to_be(), // invokestatic 0xB8_u8.to_be(), // invokestatic
0x04_u16.to_be_bytes()[0], // index 4 into the constant 0x04_u16.to_be_bytes()[0], // index 4 into the constant
0x04_u16.to_be_bytes()[1], // pool 0x04_u16.to_be_bytes()[1], // pool
@ -301,29 +316,47 @@ impl JVM {
} }
]) ])
}, },
MethodInfo {
access_flags: MethodAccessFlagMask {
mask: MethodAccessFlag::Private.discriminant() | MethodAccessFlag::Static.discriminant() | MethodAccessFlag::Native.discriminant()
},
name: "populateUnsafeConstants".to_string(),
descriptor: MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription {
array_level: 0,
kind: AbstractTypeKind::Void(),
}
},
code_attribute_index: 0,
attributes: Box::new([])
}
]), ]),
attributes: Box::new([]), attributes: Box::new([]),
}; };
self.native_registry.register("::EntryPoint", "populateUnsafeConstants", EntryPoint::populate_unsafe_constants);
self.class_store.add_class(entry_class, true)?; // 0 self.class_store.add_class(entry_class, true)?; // 0
self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1 self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1
self.load_class(&"java/lang/Object".to_string())?; // 2 self.load_class(&"java/lang/Object".to_string())?; // 2
self.load_class(&"java/lang/Number".to_string())?; // 3 self.load_class(&"java/lang/Number".to_string())?; // 3
self.load_class(&"java/lang/Byte".to_string())?; // 4 let byte_class_index = self.load_class(&"java/lang/Byte".to_string())?; // 4
self.load_class(&"java/lang/String".to_string())?; // 5 let string_class_index = self.load_class(&"java/lang/String".to_string())?; // 5
self.load_class(&"java/lang/Class".to_string())?; // 6 let class_class_index = self.load_class(&"java/lang/Class".to_string())?; // 6
let system_class_index = self.load_class(&"java/lang/System".to_string())?; // 7
self.make_class_class("Ljava/lang/Byte;"); self.make_class_class("Ljava/lang/Byte;");
self.make_class_class("Ljava/lang/String;"); self.make_class_class("Ljava/lang/String;");
self.make_array_class( self.make_array_class(
self.class_store.get_class_objectref_from_index(4), self.class_store.get_class_objectref_from_index(byte_class_index),
AbstractTypeDescription { AbstractTypeDescription {
array_level: 0, array_level: 0,
kind: AbstractTypeKind::Classname("java/lang/Byte".into()), kind: AbstractTypeKind::Classname("java/lang/Byte".into()),
} }
); );
self.make_array_class( self.make_array_class(
self.class_store.get_class_objectref_from_index(5), self.class_store.get_class_objectref_from_index(string_class_index),
AbstractTypeDescription { AbstractTypeDescription {
array_level: 0, array_level: 0,
kind: AbstractTypeKind::Classname("java/lang/String".into()), kind: AbstractTypeKind::Classname("java/lang/String".into()),
@ -332,18 +365,24 @@ impl JVM {
self.heap_area.fill_byte_cache(&self.class_store); self.heap_area.fill_byte_cache(&self.class_store);
let int_class_ref = self.make_primitive_class("int", "I"); self.class_store.primitive_classes.int_class = self.make_primitive_class("int", "I");
let byte_class_ref = self.make_primitive_class("byte", "B"); self.class_store.primitive_classes.byte_class = self.make_primitive_class("byte", "B");
self.class_store.primitive_classes.char_class = self.make_primitive_class("char", "C");
self.class_store.primitive_classes.long_class = self.make_primitive_class("long", "J");
self.class_store.primitive_classes.float_class = self.make_primitive_class("float", "F");
self.class_store.primitive_classes.short_class = self.make_primitive_class("short", "S");
self.class_store.primitive_classes.double_class = self.make_primitive_class("double", "D");
self.class_store.primitive_classes.boolean_class = self.make_primitive_class("boolean", "Z");
self.make_array_class( self.make_array_class(
int_class_ref, self.class_store.primitive_classes.int_class,
AbstractTypeDescription { AbstractTypeDescription {
array_level: 0, array_level: 0,
kind: AbstractTypeKind::Int(), kind: AbstractTypeKind::Int(),
} }
); );
self.make_array_class( self.make_array_class(
byte_class_ref, self.class_store.primitive_classes.byte_class,
AbstractTypeDescription { AbstractTypeDescription {
array_level: 0, array_level: 0,
kind: AbstractTypeKind::Byte(), kind: AbstractTypeKind::Byte(),
@ -366,7 +405,6 @@ impl JVM {
pub fn run(&mut self) -> Result<(), Error> { pub fn run(&mut self) -> Result<(), Error> {
while self.stack_frames.len() != 0 { while self.stack_frames.len() != 0 {
println!("Enter bytecode loop:");
let jvm_op = self.bytecode_loop()?; let jvm_op = self.bytecode_loop()?;
match jvm_op { match jvm_op {
@ -517,6 +555,11 @@ impl JVM {
FieldValue::Long(long_entry.value) FieldValue::Long(long_entry.value)
}, },
AbstractTypeKind::Float() => {
let float_entry = class_file.pool_float_entry(constant_value_info.constant_value_index)?;
FieldValue::Float(float_entry.value)
},
AbstractTypeKind::Classname(ref name) => { AbstractTypeKind::Classname(ref name) => {
if name == "java/lang/String" { if name == "java/lang/String" {
let string_entry = class_file.gather_string(constant_value_info.constant_value_index)?; let string_entry = class_file.gather_string(constant_value_info.constant_value_index)?;
@ -585,15 +628,15 @@ impl JVM {
} }
fn bytecode_loop(&mut self) -> Result<JVMCallbackOperation, Error> { fn bytecode_loop(&mut self) -> Result<JVMCallbackOperation, Error> {
//println!("Enter bytecode loop:");
let frame = {
let frame_index = self.stack_frames.len() - 1; let frame_index = self.stack_frames.len() - 1;
&mut self.stack_frames[frame_index] let frame = &mut self.stack_frames[frame_index];
};
let class = self.class_store.class_file_from_idx(frame.class_index).unwrap(); let class = self.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];
if method.access_flags & MethodAccessFlag::Native { if method.access_flags & MethodAccessFlag::Native {
println!("{:25}.{:15}: (native)", class.get_classname().unwrap(), method.name);
return self.native_call() return self.native_call()
} }
@ -604,10 +647,17 @@ 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!("{:25}.{:15}:{:<10}{instruction:?}", class.get_classname().unwrap(), method.name, frame.instruction_pointer); println!("{}{:25}.{:15}:{:<10}{instruction:?}", " ".repeat(frame_index), class.get_classname().unwrap(), method.name, frame.instruction_pointer);
match instruction { match instruction {
Instruction::AddInt() => {
let value_0 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let value_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(value_0 + value_1)))?;
}
Instruction::ArrayLength() => { Instruction::ArrayLength() => {
let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; let array_reference = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
@ -659,6 +709,24 @@ impl JVM {
} }
} }
Instruction::BranchNonNegative(branch_offset) => {
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
if test_value >= 0 {
frame.instruction_pointer -= offset as u32;
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
}
}
Instruction::BranchNonZero(branch_offset) => {
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
if test_value != 0 {
frame.instruction_pointer -= offset as u32;
frame.instruction_pointer = if branch_offset < 0 { frame.instruction_pointer - branch_offset.abs() as u32} else { frame.instruction_pointer + branch_offset.abs() as u32};
}
}
Instruction::BranchNull(branch_offset) => { Instruction::BranchNull(branch_offset) => {
let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?; let test_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
@ -840,9 +908,6 @@ impl JVM {
))); )));
} }
if callee_method_info.access_flags & MethodAccessFlag::Native {
}
let supplied_descriptor: MethodDescriptor = supplied_descriptor_string.try_into()?; let supplied_descriptor: MethodDescriptor = supplied_descriptor_string.try_into()?;
// TODO: Throw exception on fail // TODO: Throw exception on fail
@ -982,6 +1047,12 @@ impl JVM {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?; wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(string_obj_ref)))?;
}, },
ConstantPoolInfo::Float(_) => {
// TODO: Handle error instead of unwrap
let float_constant = class.gather_float(index as u16).unwrap();
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Float(float_constant)))?;
},
_ => { _ => {
println!("{:?}", class.pool_entry(index as u16).unwrap()); println!("{:?}", class.pool_entry(index as u16).unwrap());
todo!() todo!()
@ -1000,11 +1071,7 @@ impl JVM {
let array_level = class_name.len() - component_name.len(); let array_level = class_name.len() - component_name.len();
let array_type_desc = AbstractTypeDescription { let array_type_desc = AbstractTypeDescription {
array_level: array_level as u8, array_level: array_level as u8,
kind: if component_name.len() == 1 { kind: component_name.into(),
component_name.into()
} else {
AbstractTypeKind::Classname(component_name.to_string())
}
}; };
if let Some(array_ref) = self.class_store.get_array_class_ref(&array_type_desc) { if let Some(array_ref) = self.class_store.get_array_class_ref(&array_type_desc) {
@ -1166,6 +1233,10 @@ impl JVM {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(new_object)))?; wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(new_object)))?;
}, },
Instruction::Pop() => {
wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?;
}
Instruction::PushConstInt0() => { Instruction::PushConstInt0() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?; wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?;
} }
@ -1189,6 +1260,26 @@ impl JVM {
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)))?;
} }
Instruction::PutField(fieldref_index) => {
let (_target_class_name, target_field_name, expected_field_descriptor) = class.gather_fieldref(fieldref_index)?;
let value = match expected_field_descriptor.as_str() {
"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))? {
StackValue::Int(i) => FieldValue::Int(i),
StackValue::Reference(r) => FieldValue::Reference(r),
stack_value @ _ => {
println!("{stack_value:?}");
todo!()
}
}
};
let this_object = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
self.heap_area.object_area.set_object_field(this_object, target_field_name, value, frame.class_index, &self.class_store)?;
}
Instruction::PutStatic(fieldref_index) => { Instruction::PutStatic(fieldref_index) => {
let (target_class_name, target_field_name, expected_field_descriptor) = class.gather_fieldref(fieldref_index)?; let (target_class_name, target_field_name, expected_field_descriptor) = class.gather_fieldref(fieldref_index)?;
@ -1228,7 +1319,13 @@ impl JVM {
let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
FieldValue::Boolean((int_value & 1) != 0) FieldValue::Boolean((int_value & 1) != 0)
}, }
(0, AbstractTypeKind::Int()) => {
let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
FieldValue::Int(int_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))?;
@ -1404,7 +1501,8 @@ fn load_local_int(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackF
} }
fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut VecDeque<StackValue>, argument_types: &Box<[AbstractTypeDescription]>, stack: &mut OperandStack) -> Result<(), Error> { fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut VecDeque<StackValue>, argument_types: &Box<[AbstractTypeDescription]>, stack: &mut OperandStack) -> Result<(), Error> {
for argument_type in argument_types { for argument_type_index in 0..argument_types.len() {
let argument_type = &argument_types[argument_types.len() - argument_type_index - 1];
if argument_type.array_level != 0 { if argument_type.array_level != 0 {
// TODO: Type checking // TODO: Type checking
arguments.push_front( arguments.push_front(
@ -1540,7 +1638,7 @@ fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut Ve
Ok(()) Ok(())
} }
fn wrap_stackframe_error<T>(class: &JavaClassFile, method: &MethodInfo, frame_result: Result<T, stackframe::Error>) -> Result<T, Error> { pub fn wrap_stackframe_error<T>(class: &JavaClassFile, method: &MethodInfo, frame_result: Result<T, stackframe::Error>) -> Result<T, Error> {
match frame_result { match frame_result {
Ok(t) => Ok(t), Ok(t) => Ok(t),
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))), Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),

View file

@ -1,4 +1,7 @@
use crate::heap_area::FieldValue;
use crate::jvm::wrap_stackframe_error;
use crate::stackframe::StackValue;
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;
@ -13,10 +16,110 @@ pub fn todo_call(_: &mut JVM) -> Result<JVMCallbackOperation, Error> {
todo!() todo!()
} }
pub fn java_lang_object_get_class(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> { pub struct EntryPoint {}
todo!()
impl EntryPoint {
pub fn populate_unsafe_constants(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
jvm.heap_area.static_area.set(&String::from("jdk/internal/misc/UnsafeConstants"), &String::from("ADDRESS_SIZE0"), FieldValue::Int(4))?; // objectreference use u32
jvm.heap_area.static_area.set(&String::from("jdk/internal/misc/UnsafeConstants"), &String::from("PAGE_SIZE"), FieldValue::Int(4096))?;
// TODO: Get actual page size
jvm.heap_area.static_area.set(&String::from("jdk/internal/misc/UnsafeConstants"), &String::from("BIG_ENDIAN"), FieldValue::Boolean(cfg!(target_endian = "big")))?;
// This is the safe version, TODO: Change it to the actual value
jvm.heap_area.static_area.set(&String::from("jdk/internal/misc/UnsafeConstants"), &String::from("UNALIGNED_ACCESS"), FieldValue::Boolean(false))?;
// This is the safe version, TODO: Change it to the actual value
jvm.heap_area.static_area.set(&String::from("jdk/internal/misc/UnsafeConstants"), &String::from("DATA_CACHE_LINE_FLUSH_SIZE"), FieldValue::Int(0))?;
Ok(JVMCallbackOperation::PopFrame())
}
} }
struct JavaLangClass {}
impl JavaLangClass {
pub fn desired_assertion_status_0(_: &mut JVM) -> Result<JVMCallbackOperation, Error> {
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(1)))
}
}
struct JdkInternalMiscUnsafe {}
impl JdkInternalMiscUnsafe {
pub fn array_index_scale_0(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
let frame = {
let frame_index = jvm.stack_frames.len() - 1;
&mut jvm.stack_frames[frame_index]
};
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
};
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(index_scale)))
}
pub fn array_base_offset_0(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
// TODO: Check passed class
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Int(0)))
}
}
pub struct JdkInternalUtilSystemPropsRaw {}
impl JdkInternalUtilSystemPropsRaw {
pub fn platform_properties(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
let array_length = jvm.heap_area.static_area.
get(
&String::from("jdk/internal/util/SystemProps$Raw"),
&String::from("FIXED_LENGTH"),
AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Int() })
.unwrap();
let array_length = match array_length {
FieldValue::Int(i) => i as usize,
_ => unreachable!()
};
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);
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference)))
}
pub fn vm_properties(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
let array_reference = jvm.heap_area.make_empty_array(&jvm.class_store, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()) }, 2);
Ok(JVMCallbackOperation::ReturnFrame(StackValue::Reference(array_reference)))
}
}
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;
match (class_name, method_name) { match (class_name, method_name) {
@ -51,7 +154,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(JavaLangClass::desired_assertion_status_0)
} }
("java/lang/Class", "getClassAccessFlagsRaw0") => { ("java/lang/Class", "getClassAccessFlagsRaw0") => {
@ -487,7 +590,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(ignore_call)
} }
("java/lang/Class", "setSigners") => { ("java/lang/Class", "setSigners") => {
@ -541,7 +644,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(java_lang_object_get_class) Ok(todo_call)
} }
("java/lang/Object", "hashCode") => { ("java/lang/Object", "hashCode") => {
@ -746,7 +849,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::array_base_offset_0)
} }
("jdk/internal/misc/Unsafe", "arrayIndexScale0") => { ("jdk/internal/misc/Unsafe", "arrayIndexScale0") => {
@ -761,7 +864,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::array_index_scale_0)
} }
("jdk/internal/misc/Unsafe", "allocateInstance") => { ("jdk/internal/misc/Unsafe", "allocateInstance") => {
@ -2109,6 +2212,34 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
Ok(todo_call) Ok(todo_call)
} }
("jdk/internal/util/SystemProps$Raw", "platformProperties") => {
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(JdkInternalUtilSystemPropsRaw::platform_properties)
}
("jdk/internal/util/SystemProps$Raw", "vmProperties") => {
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(JdkInternalUtilSystemPropsRaw::vm_properties)
}
_ => Err(Error::RunTimeError(format!("Failed to find native implementation for method '{class_name}.{method_name}'"))), _ => Err(Error::RunTimeError(format!("Failed to find native implementation for method '{class_name}.{method_name}'"))),
} }

View file

@ -1,4 +1,5 @@
use crate::stackframe::StackFrame;
use crate::jvm::Error; use crate::jvm::Error;
use crate::jvm::JVMCallbackOperation; use crate::jvm::JVMCallbackOperation;
use crate::jvm::JVM; use crate::jvm::JVM;

View file

@ -75,6 +75,32 @@ impl OperandStack {
} }
} }
pub fn pop_computational_2(&mut self, index: usize) -> Result<FieldValue, Error> {
let absolute_index = self.depth as usize - 1 - index;
let value_top = self.stack[absolute_index];
let value_bot = self.stack[absolute_index - 1];
self.depth -= 2;
match (value_bot, value_top) {
(StackValue::Long0(l0), StackValue::Long1(l1)) => {
let l0_bytes = l0.to_ne_bytes();
let l1_bytes = l1.to_ne_bytes();
let concat_bytes = [l0_bytes[0], l0_bytes[1], l0_bytes[2], l0_bytes[3], l1_bytes[0], l1_bytes[1], l1_bytes[2], l1_bytes[3]];
Ok(FieldValue::Long(i64::from_ne_bytes(concat_bytes)))
}
(StackValue::Double0(d0), StackValue::Double1(d1)) => {
let d0_bytes = d0.to_ne_bytes();
let d1_bytes = d1.to_ne_bytes();
let concat_bytes = [d0_bytes[0], d0_bytes[1], d0_bytes[2], d0_bytes[3], d1_bytes[0], d1_bytes[1], d1_bytes[2], d1_bytes[3]];
Ok(FieldValue::Double(f64::from_ne_bytes(concat_bytes)))
}
_ => Err(Error::LocalError(format!("Mismatched type at index {index} of the function operand stack, expected type with computational type 2 but found '{value_bot:?}, {value_top:?}'")))
}
}
pub fn pop_computational_1(&mut self, index: usize) -> Result<StackValue, Error> { pub fn pop_computational_1(&mut self, index: usize) -> Result<StackValue, 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];