2024-08-30 15:33:54 +02:00
use core ::fmt ::{ Display , Formatter } ;
2024-09-02 11:28:00 +02:00
2024-09-02 15:42:42 +02:00
use std ::collections ::VecDeque ;
2024-08-30 15:33:54 +02:00
use std ::error ::Error as ErrorTrait ;
2024-09-05 00:33:14 +02:00
use crate ::accessmasks ::{ ClassAccessFlagMask , ClassAccessFlag , MethodAccessFlagMask , MethodAccessFlag , FieldAccessFlag , FieldAccessFlagMask } ;
2024-09-02 11:28:00 +02:00
use crate ::bytecode ::{ Bytecode , Instruction } ;
use crate ::classfile ;
2024-09-05 00:33:14 +02:00
use crate ::classfile ::{ JavaClassFile , FieldInfo , MethodInfo , MethodDescriptor , AbstractTypeDescription , AbstractTypeKind , AttributeInfo , AttributeData , CodeAttributeData , ConstantValueAttributeData } ;
2024-08-30 15:33:54 +02:00
use crate ::classstore ;
use crate ::classstore ::ClassStore ;
2024-09-02 11:28:00 +02:00
use crate ::constantpool ::{ ConstantPoolInfo , ConstantClassInfo , ConstantUtf8Info , ConstantMethodRefInfo , ConstantNameAndTypeInfo } ;
2024-09-06 23:51:35 +02:00
use crate ::heap_area ::{ HeapArea , FieldValue , ObjectReference , CompartmentEntry } ;
use crate ::iterators ::{ ClassMethodIterator , ClassFieldIterator } ;
2024-09-09 15:43:26 +02:00
use crate ::native_methods ;
2024-09-10 00:23:53 +02:00
use crate ::native_methods ::EntryPoint ;
2024-09-10 00:17:17 +02:00
use crate ::native_registry ::NativeRegistry ;
2024-09-02 15:42:42 +02:00
use crate ::stackframe ;
2024-09-02 17:46:00 +02:00
use crate ::stackframe ::{ StackFrame , StackValue , OperandStack } ;
2024-08-30 15:33:54 +02:00
#[ derive(Debug) ]
pub enum Error {
ClassStoreError ( classstore ::Error ) ,
2024-09-02 11:28:00 +02:00
ClassFileError ( classfile ::Error ) ,
2024-09-02 15:42:42 +02:00
StackFrameError ( stackframe ::Error , String ) ,
2024-08-30 15:33:54 +02:00
BadNameError ( String ) ,
2024-09-02 11:28:00 +02:00
RunTimeError ( String ) ,
2024-09-02 12:02:19 +02:00
OpcodeError ( String ) ,
2024-09-02 11:28:00 +02:00
}
impl From < classfile ::Error > for Error {
fn from ( value : classfile ::Error ) -> Self {
return Error ::ClassFileError ( value ) ;
}
2024-08-30 15:33:54 +02:00
}
impl From < classstore ::Error > for Error {
fn from ( value : classstore ::Error ) -> Self {
return Error ::ClassStoreError ( value ) ;
}
}
impl ErrorTrait for Error { }
impl Display for Error {
fn fmt ( & self , formatter : & mut Formatter < '_ > ) -> Result < ( ) , std ::fmt ::Error > {
writeln! ( formatter , " {self} " ) ? ;
if let Some ( e ) = self . source ( ) {
writeln! ( formatter , " \t Caused by: {e:?} " ) ? ;
}
Ok ( ( ) )
}
}
#[ derive(Debug) ]
pub struct JVM {
2024-09-02 15:42:42 +02:00
pub class_store : ClassStore ,
pub stack_frames : Vec < StackFrame > ,
pub heap_area : HeapArea ,
2024-09-09 15:43:26 +02:00
pub native_registry : NativeRegistry ,
2024-08-30 15:33:54 +02:00
}
impl JVM {
pub fn new ( ) -> Self {
return JVM {
class_store : ClassStore ::new ( ) ,
stack_frames : Vec ::new ( ) ,
2024-09-02 15:42:42 +02:00
heap_area : HeapArea ::new ( usize ::MAX ) ,
2024-09-09 15:43:26 +02:00
native_registry : NativeRegistry ::default ( ) ,
2024-08-30 15:33:54 +02:00
}
}
2024-09-09 15:43:26 +02:00
fn load_class ( & mut self , class_name : & String ) -> Result < usize , Error > {
let class_index = self . class_store . load_class ( class_name ) ? ;
let class_file = self . class_store . class_file_from_idx ( class_index ) . unwrap ( ) ;
for ( method_name , method_implementation ) in class_file . methods . iter ( )
. filter ( | m | m . access_flags & MethodAccessFlag ::Native )
. map ( | m | ( & m . name , native_methods ::function_for ( class_name , m ) ) ) {
let method_implementation = match method_implementation {
Ok ( m ) = > m ,
Err ( e ) = > return Err ( e )
} ;
self . native_registry . register ( class_name , method_name , method_implementation ) ;
}
Ok ( class_index )
}
2024-09-05 00:33:14 +02:00
fn class_native_class_data ( ) -> JavaClassFile {
JavaClassFile {
minor_version : 0 ,
major_version : 0 ,
constant_pool : Box ::new ( [
ConstantPoolInfo ::Class ( ConstantClassInfo { name_index : 2 } ) ,
ConstantPoolInfo ::Utf8 ( ConstantUtf8Info { utf8 : " ::NativeClassData " . to_string ( ) } ) ,
ConstantPoolInfo ::Class ( ConstantClassInfo { name_index : 4 } ) ,
ConstantPoolInfo ::Utf8 ( ConstantUtf8Info { utf8 : " java/lang/Object " . to_string ( ) } ) ,
]
) ,
access_flags : ClassAccessFlagMask { mask : ClassAccessFlag ::Super . discriminant ( ) } ,
this_class : 1 ,
super_class : 3 ,
interfaces : Box ::new ( [ ] ) ,
fields : Box ::new ( [
FieldInfo {
access_flags : FieldAccessFlagMask {
mask : FieldAccessFlag ::Public . discriminant ( )
} ,
name : " native_class_descriptor_index " . to_string ( ) ,
descriptor : AbstractTypeDescription {
array_level : 0 ,
kind : AbstractTypeKind ::Int ( ) ,
} ,
attributes : Box ::new ( [ ] ) ,
} ,
] ) ,
methods : Box ::new ( [ ] ) ,
attributes : Box ::new ( [ ] ) ,
}
}
fn make_class_class ( & mut self , class_name : & str ) {
let class_object = self . heap_area . make_object ( & self . class_store , self . class_store . class_idx_from_name ( & " java/lang/Class " . to_string ( ) ) . unwrap ( ) ) ;
let class_data_object = self . heap_area . make_object ( & self . class_store , self . class_store . class_idx_from_name ( & " ::NativeClassData " . to_string ( ) ) . unwrap ( ) ) ;
self . heap_area . object_area . set_object_field (
class_object ,
" classData " ,
FieldValue ::Reference ( class_data_object ) ,
self . class_store . class_idx_from_name ( & " java/lang/Class " . to_string ( ) ) . unwrap ( ) ,
& self . class_store ,
) . unwrap ( ) ;
// set native name index on class data
self . heap_area . object_area . set_object_field (
class_data_object ,
" native_class_descriptor_index " ,
2024-09-06 15:04:21 +02:00
FieldValue ::Int ( self . class_store . add_native_class_descriptor ( class_name . to_string ( ) ) as i32 ) ,
2024-09-05 00:33:14 +02:00
self . class_store . class_idx_from_name ( & " ::NativeClassData " . to_string ( ) ) . unwrap ( ) ,
& self . class_store ,
) . unwrap ( ) ;
let parsed_class_name = match AbstractTypeDescription ::parse_first ( class_name ) . unwrap ( ) {
( _ , desc ) = > {
assert! ( desc . array_level = = 0 ) ;
match desc . kind {
AbstractTypeKind ::Classname ( name ) = > name ,
_ = > unreachable! ( ) ,
}
}
} ;
self . class_store . set_class_objectref_by_index ( self . class_store . class_idx_from_name ( & parsed_class_name ) . unwrap ( ) , class_object ) ;
}
2024-09-06 23:51:35 +02:00
fn make_array_class ( & mut self , element_class_ref : ObjectReference , element_descriptor : AbstractTypeDescription ) {
let class_class_index = self . class_store . class_idx_from_name ( & " java/lang/Class " . to_string ( ) ) . unwrap ( ) ;
2024-09-05 00:33:14 +02:00
let array_class_object = self . heap_area . make_object ( & self . class_store , 6 ) ;
let array_class_data_object = self . heap_area . make_object ( & self . class_store , 1 ) ;
let array_type_description = AbstractTypeDescription {
array_level : 1 + element_descriptor . array_level ,
kind : element_descriptor . kind ,
} ;
// set component type
self . heap_area . object_area . set_object_field (
array_class_object ,
" componentType " ,
FieldValue ::Reference ( element_class_ref ) ,
2024-09-06 23:51:35 +02:00
class_class_index ,
2024-09-05 00:33:14 +02:00
& self . class_store ,
) . unwrap ( ) ;
// set classdata object
self . heap_area . object_area . set_object_field (
array_class_object ,
" classData " ,
FieldValue ::Reference ( array_class_data_object ) ,
2024-09-06 23:51:35 +02:00
class_class_index ,
2024-09-05 00:33:14 +02:00
& self . class_store ,
) . unwrap ( ) ;
// set native name index on class data
self . heap_area . object_area . set_object_field (
array_class_data_object ,
" native_class_descriptor_index " ,
2024-09-06 15:04:21 +02:00
FieldValue ::Int ( self . class_store . add_native_class_descriptor ( ( & array_type_description ) . into ( ) ) as i32 ) ,
2024-09-05 00:33:14 +02:00
self . class_store . class_idx_from_name ( & " ::NativeClassData " . to_string ( ) ) . unwrap ( ) ,
& self . class_store ,
) . unwrap ( ) ;
self . class_store . put_array_class_ref (
array_type_description ,
array_class_object ,
) ;
}
2024-09-10 12:26:05 +02:00
fn make_primitive_class ( & mut self , class_name : & str , class_descriptor : & str , string_names : bool ) -> ObjectReference {
2024-09-06 23:51:35 +02:00
let class_class_index = self . class_store . class_idx_from_name ( & String ::from ( " java/lang/Class " ) ) . unwrap ( ) ;
let data_class_index = self . class_store . class_idx_from_name ( & String ::from ( " ::NativeClassData " ) ) . unwrap ( ) ;
let primitive_class_object = self . heap_area . make_object ( & self . class_store , class_class_index ) ;
let primitive_class_data_object = self . heap_area . make_object ( & self . class_store , data_class_index ) ;
// set classdata object
self . heap_area . object_area . set_object_field (
primitive_class_object ,
" classData " ,
FieldValue ::Reference ( primitive_class_data_object ) ,
class_class_index ,
& self . class_store ,
) . unwrap ( ) ;
2024-09-10 12:26:05 +02:00
if string_names {
let name_string_ref = self . heap_area . make_handmade_string ( & class_name . into ( ) , & self . class_store ) ;
// set name string object
self . heap_area . object_area . set_object_field (
primitive_class_object ,
" name " ,
FieldValue ::Reference ( name_string_ref ) ,
class_class_index ,
& self . class_store ,
) . unwrap ( ) ;
}
2024-09-06 23:51:35 +02:00
// set native name index on class data
self . heap_area . object_area . set_object_field (
primitive_class_data_object ,
" native_class_descriptor_index " ,
FieldValue ::Int ( self . class_store . add_native_class_descriptor ( class_descriptor . into ( ) ) as i32 ) ,
self . class_store . class_idx_from_name ( & " ::NativeClassData " . to_string ( ) ) . unwrap ( ) ,
& self . class_store ,
) . unwrap ( ) ;
// TODO: Set Static
primitive_class_object
}
2024-09-05 00:33:14 +02:00
pub fn entrypoint ( & mut self , class_name : & String , method_name : & String , arguments : & [ & str ] ) -> Result < ( ) , Error > {
2024-09-02 11:28:00 +02:00
let entry_class = JavaClassFile {
minor_version : 0 ,
major_version : 0 ,
constant_pool : Box ::new ( [
ConstantPoolInfo ::Class ( ConstantClassInfo { name_index : 2 } ) ,
ConstantPoolInfo ::Utf8 ( ConstantUtf8Info { utf8 : " ::EntryPoint " . to_string ( ) } ) ,
ConstantPoolInfo ::Utf8 ( ConstantUtf8Info { utf8 : " Code " . to_string ( ) } ) ,
ConstantPoolInfo ::MethodRef ( ConstantMethodRefInfo { class_index : 5 , name_and_type_index : 6 } ) ,
2024-09-05 00:33:14 +02:00
ConstantPoolInfo ::Class ( ConstantClassInfo { name_index : 7 } ) , // 5
2024-09-02 11:28:00 +02:00
ConstantPoolInfo ::NameAndType ( ConstantNameAndTypeInfo { name_index : 8 , descriptor_index : 9 } ) ,
ConstantPoolInfo ::Utf8 ( ConstantUtf8Info { utf8 : class_name . to_string ( ) } ) ,
ConstantPoolInfo ::Utf8 ( ConstantUtf8Info { utf8 : method_name . to_string ( ) } ) ,
2024-09-06 21:11:03 +02:00
ConstantPoolInfo ::Utf8 ( ConstantUtf8Info { utf8 : " ([Ljava/lang/String;)V " . to_string ( ) } ) ,
2024-09-10 00:17:17 +02:00
ConstantPoolInfo ::MethodRef ( ConstantMethodRefInfo { class_index : 1 , name_and_type_index : 11 } ) , // 10
ConstantPoolInfo ::NameAndType ( ConstantNameAndTypeInfo { name_index : 12 , descriptor_index : 13 } ) ,
ConstantPoolInfo ::Utf8 ( ConstantUtf8Info { utf8 : " populateUnsafeConstants " . to_string ( ) } ) ,
ConstantPoolInfo ::Utf8 ( ConstantUtf8Info { utf8 : " ()V " . to_string ( ) } ) ,
ConstantPoolInfo ::Class ( ConstantClassInfo { name_index : 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 ( ) } ) ,
2024-09-02 11:28:00 +02:00
]
) ,
access_flags : ClassAccessFlagMask { mask : ClassAccessFlag ::Super . discriminant ( ) } ,
this_class : 1 ,
super_class : 0 ,
interfaces : Box ::new ( [ ] ) ,
fields : Box ::new ( [ ] ) ,
methods : Box ::new ( [
MethodInfo {
access_flags : MethodAccessFlagMask {
2024-09-10 00:17:17 +02:00
mask : MethodAccessFlag ::Private . discriminant ( ) | MethodAccessFlag ::Static . discriminant ( )
2024-09-02 11:28:00 +02:00
} ,
name : " call_main " . to_string ( ) ,
descriptor : MethodDescriptor {
argument_types : Box ::new ( [ ] ) ,
return_type : AbstractTypeDescription {
array_level : 0 ,
kind : AbstractTypeKind ::Void ( ) ,
}
} ,
code_attribute_index : 0 ,
attributes : Box ::new ( [
AttributeInfo {
attribute_name_index : 3 ,
data : AttributeData ::Code (
CodeAttributeData {
2024-09-06 21:11:03 +02:00
max_stack : 1 ,
2024-09-05 00:33:14 +02:00
max_locals : 1 ,
2024-09-02 11:28:00 +02:00
code : Bytecode {
bytes : Box ::new ( [
2024-09-10 00:17:17 +02:00
// 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
2024-09-06 21:11:03 +02:00
2024-09-10 00:17:17 +02:00
0x2A_ u8 . to_be ( ) , // aload_0
2024-09-02 11:28:00 +02:00
0xB8_ u8 . to_be ( ) , // invokestatic
0x04_ u16 . to_be_bytes ( ) [ 0 ] , // index 4 into the constant
0x04_ u16 . to_be_bytes ( ) [ 1 ] , // pool
] ) ,
} ,
exception_table : Box ::new ( [ ] ) ,
attributes : Box ::new ( [ ] ) ,
}
)
}
] )
2024-09-05 00:33:14 +02:00
} ,
2024-09-10 00:17:17 +02:00
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 ( [ ] )
}
2024-09-02 11:28:00 +02:00
] ) ,
attributes : Box ::new ( [ ] ) ,
} ;
2024-09-06 15:04:21 +02:00
2024-09-10 00:17:17 +02:00
self . native_registry . register ( " ::EntryPoint " , " populateUnsafeConstants " , EntryPoint ::populate_unsafe_constants ) ;
self . class_store . add_class ( entry_class , true ) ? ; // 0
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/Number " . to_string ( ) ) ? ; // 3
let byte_class_index = self . load_class ( & " java/lang/Byte " . to_string ( ) ) ? ; // 4
let string_class_index = self . load_class ( & " java/lang/String " . to_string ( ) ) ? ; // 5
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
2024-09-05 00:33:14 +02:00
self . make_class_class ( " Ljava/lang/Byte; " ) ;
self . make_class_class ( " Ljava/lang/String; " ) ;
2024-09-06 23:51:35 +02:00
self . make_array_class (
2024-09-10 00:17:17 +02:00
self . class_store . get_class_objectref_from_index ( byte_class_index ) ,
2024-09-06 23:51:35 +02:00
AbstractTypeDescription {
array_level : 0 ,
kind : AbstractTypeKind ::Classname ( " java/lang/Byte " . into ( ) ) ,
}
) ;
self . make_array_class (
2024-09-10 00:17:17 +02:00
self . class_store . get_class_objectref_from_index ( string_class_index ) ,
2024-09-06 23:51:35 +02:00
AbstractTypeDescription {
array_level : 0 ,
kind : AbstractTypeKind ::Classname ( " java/lang/String " . into ( ) ) ,
}
) ;
2024-09-05 00:33:14 +02:00
2024-09-06 15:04:21 +02:00
self . heap_area . fill_byte_cache ( & self . class_store ) ;
2024-09-10 12:26:05 +02:00
self . class_store . primitive_classes . byte_class = self . make_primitive_class ( " byte " , " B " , false ) ;
self . make_array_class (
self . class_store . primitive_classes . byte_class ,
AbstractTypeDescription {
array_level : 0 ,
kind : AbstractTypeKind ::Byte ( ) ,
}
) ;
{
// we can only make a byte class name after the byte array is loaded
let string_ref = self . heap_area . make_handmade_string ( & String ::from ( " byte " ) , & self . class_store ) ;
self . heap_area . object_area . set_object_field (
self . class_store . primitive_classes . byte_class ,
" name " ,
FieldValue ::Reference ( string_ref ) ,
class_class_index ,
& self . class_store
) . unwrap ( ) ;
}
self . class_store . primitive_classes . int_class = self . make_primitive_class ( " int " , " I " , true ) ;
self . class_store . primitive_classes . char_class = self . make_primitive_class ( " char " , " C " , true ) ;
self . class_store . primitive_classes . long_class = self . make_primitive_class ( " long " , " J " , true ) ;
self . class_store . primitive_classes . float_class = self . make_primitive_class ( " float " , " F " , true ) ;
self . class_store . primitive_classes . short_class = self . make_primitive_class ( " short " , " S " , true ) ;
self . class_store . primitive_classes . double_class = self . make_primitive_class ( " double " , " D " , true ) ;
self . class_store . primitive_classes . boolean_class = self . make_primitive_class ( " boolean " , " Z " , true ) ;
2024-09-06 23:51:35 +02:00
self . make_array_class (
2024-09-10 12:26:05 +02:00
self . class_store . primitive_classes . char_class ,
2024-09-06 23:51:35 +02:00
AbstractTypeDescription {
array_level : 0 ,
2024-09-10 12:26:05 +02:00
kind : AbstractTypeKind ::Char ( ) ,
2024-09-06 23:51:35 +02:00
}
) ;
self . make_array_class (
2024-09-10 12:26:05 +02:00
self . class_store . primitive_classes . int_class ,
2024-09-06 23:51:35 +02:00
AbstractTypeDescription {
array_level : 0 ,
2024-09-10 12:26:05 +02:00
kind : AbstractTypeKind ::Int ( ) ,
2024-09-06 23:51:35 +02:00
}
) ;
2024-09-06 15:04:21 +02:00
let string_refs = arguments . iter ( )
. map ( | s | self . heap_area . make_handmade_string ( & s . to_string ( ) , & self . class_store ) )
. collect ( ) ;
let argument_array_ref = self . heap_area . make_array ( & self . class_store , string_refs ) ;
2024-09-02 11:28:00 +02:00
2024-09-03 00:49:28 +02:00
2024-09-05 00:33:14 +02:00
// push the entry frame which will call main
2024-09-06 15:04:21 +02:00
let entry_frame = StackFrame ::new ( self . class_store . get_class ( & String ::from ( " ::EntryPoint " ) ) . unwrap ( ) . 0 , 0 , 0 , & [ StackValue ::Reference ( argument_array_ref ) ] ) ;
2024-09-05 00:33:14 +02:00
self . stack_frames . push ( entry_frame ) ;
2024-09-02 11:28:00 +02:00
Ok ( ( ) )
}
pub fn run ( & mut self ) -> Result < ( ) , Error > {
while self . stack_frames . len ( ) ! = 0 {
2024-09-05 00:33:14 +02:00
2024-09-02 11:28:00 +02:00
let jvm_op = self . bytecode_loop ( ) ? ;
match jvm_op {
2024-09-02 15:42:42 +02:00
JVMCallbackOperation ::PopFrame ( ) = > {
self . stack_frames . truncate ( self . stack_frames . len ( ) - 1 )
} ,
JVMCallbackOperation ::ReturnFrame ( value ) = > {
// Pop returning frame
self . stack_frames . truncate ( self . stack_frames . len ( ) - 1 ) ;
let frame = {
let frame_index = self . stack_frames . len ( ) - 1 ;
& mut self . stack_frames [ frame_index ]
} ;
let class = self . class_store . class_file_from_idx ( frame . class_index ) . unwrap ( ) ;
let method = & class . methods [ frame . method_index as usize ] ;
wrap_stackframe_error ( class , method , self . stack_frames . last_mut ( ) . unwrap ( ) . operand_stack . push ( value ) ) ? ;
}
2024-09-02 11:28:00 +02:00
JVMCallbackOperation ::PushFrame ( frame ) = > self . stack_frames . push ( frame ) ,
2024-09-02 15:42:42 +02:00
2024-09-02 11:28:00 +02:00
JVMCallbackOperation ::LoadClass ( name ) = > {
2024-09-03 00:49:28 +02:00
// TODO: throw exception
self . load_class_hierarchy ( & name ) ? ;
2024-09-02 11:28:00 +02:00
} ,
2024-09-02 15:42:42 +02:00
2024-09-02 11:28:00 +02:00
JVMCallbackOperation ::InitClass ( name ) = > {
2024-09-03 00:49:28 +02:00
// TODO: throw exception
self . init_class_hierarchy ( & name ) ? ;
2024-09-05 00:33:14 +02:00
} ,
2024-09-06 23:51:35 +02:00
JVMCallbackOperation ::MakeArrayClass ( component_class_ref , component_descriptor ) = > {
self . make_array_class ( component_class_ref , component_descriptor ) ;
2024-09-02 11:28:00 +02:00
}
}
}
Ok ( ( ) )
}
2024-09-03 00:49:28 +02:00
fn load_class_hierarchy ( & mut self , name : & String ) -> Result < ( ) , Error > {
2024-09-05 00:33:14 +02:00
let mut waiting_queue = VecDeque ::new ( ) ;
waiting_queue . push_back ( name . clone ( ) ) ;
while waiting_queue . len ( ) ! = 0 {
let class_name = waiting_queue . pop_front ( ) . unwrap ( ) ;
if ! self . class_store . have_class ( & class_name ) {
println! ( " Loading Class {class_name} " ) ;
2024-09-09 15:43:26 +02:00
self . load_class ( & class_name ) ? ;
2024-09-05 00:33:14 +02:00
let ( file , _ ) = self . class_store . get_class ( & class_name ) . unwrap ( ) ;
if file . has_super_class ( ) {
waiting_queue . push_back ( file . get_super_class_name ( ) ? . to_string ( ) ) ;
}
2024-09-03 00:49:28 +02:00
2024-09-05 00:33:14 +02:00
for interface_index in & file . interfaces {
let interface_name = file . gather_class ( * interface_index ) ? ;
waiting_queue . push_back ( interface_name . to_string ( ) ) ;
2024-09-03 00:49:28 +02:00
}
}
}
Ok ( ( ) )
}
fn init_class_hierarchy ( & mut self , name : & String ) -> Result < ( ) , Error > {
let mut class_stack = vec! [ name . to_string ( ) ] ;
while class_stack . len ( ) ! = 0 {
let current_name = class_stack . pop ( ) . unwrap ( ) ;
let was_super_init = {
let ( file , _ ) = self . class_store . get_class ( & current_name ) ? ;
if ! file . has_super_class ( ) {
true
} else {
let super_name = file . get_super_class_name ( ) ? ;
self . class_store . was_init ( super_name ) . unwrap ( )
}
} ;
if was_super_init {
let class_idx = self . class_store . class_idx_from_name ( & current_name ) . unwrap ( ) ;
self . init_class ( class_idx ) ? ;
} else {
let super_name = {
let ( file , _ ) = self . class_store . get_class ( & current_name ) ? ;
file . get_super_class_name ( ) ?
} ;
class_stack . push ( current_name ) ;
class_stack . push ( super_name . to_string ( ) ) ;
}
}
Ok ( ( ) )
}
fn init_class ( & mut self , class_idx : usize ) -> Result < ( ) , Error > {
2024-09-05 00:33:14 +02:00
{
let class_file = self . class_store . class_file_from_idx ( class_idx ) . unwrap ( ) ;
self . heap_area . make_static ( class_file , class_idx ) ;
for field in & class_file . fields {
if field . access_flags & FieldAccessFlag ::Static {
let cvalue_attrs : Vec < & ConstantValueAttributeData > = ( & field . attributes ) . iter ( )
. filter ( | a | match a . data { AttributeData ::ConstantValue ( _ ) = > true , _ = > false } )
. map ( | a | match & a . data { AttributeData ::ConstantValue ( c ) = > c , _ = > unreachable! ( ) } )
. collect ( ) ;
assert! ( cvalue_attrs . len ( ) < 2 ) ;
// TODO: Throw error
if cvalue_attrs . len ( ) = = 1 {
let constant_value_info = cvalue_attrs [ 0 ] ;
assert! ( field . descriptor . array_level = = 0 ) ;
// TODO: Throw Error
let field_value = match field . descriptor . kind {
AbstractTypeKind ::Boolean ( ) = > {
let int_entry = class_file . pool_int_entry ( constant_value_info . constant_value_index ) ? ;
FieldValue ::Boolean ( int_entry . value ! = 0 )
} ,
AbstractTypeKind ::Byte ( ) = > {
let int_entry = class_file . pool_int_entry ( constant_value_info . constant_value_index ) ? ;
2024-09-10 17:15:20 +02:00
FieldValue ::Byte ( int_entry . value as i8 )
2024-09-05 00:33:14 +02:00
} ,
AbstractTypeKind ::Char ( ) = > {
let int_entry = class_file . pool_int_entry ( constant_value_info . constant_value_index ) ? ;
FieldValue ::Char ( int_entry . value as u16 )
} ,
AbstractTypeKind ::Int ( ) = > {
let int_entry = class_file . pool_int_entry ( constant_value_info . constant_value_index ) ? ;
FieldValue ::Int ( int_entry . value )
} ,
AbstractTypeKind ::Short ( ) = > {
let int_entry = class_file . pool_int_entry ( constant_value_info . constant_value_index ) ? ;
FieldValue ::Short ( int_entry . value as i16 )
} ,
AbstractTypeKind ::Long ( ) = > {
let long_entry = class_file . pool_long_entry ( constant_value_info . constant_value_index ) ? ;
FieldValue ::Long ( long_entry . value )
} ,
2024-09-10 00:17:17 +02:00
AbstractTypeKind ::Float ( ) = > {
let float_entry = class_file . pool_float_entry ( constant_value_info . constant_value_index ) ? ;
FieldValue ::Float ( float_entry . value )
} ,
2024-09-05 00:33:14 +02:00
AbstractTypeKind ::Classname ( ref name ) = > {
if name = = " java/lang/String " {
let string_entry = class_file . gather_string ( constant_value_info . constant_value_index ) ? ;
2024-09-06 15:04:21 +02:00
let string_object = self . heap_area . make_handmade_string ( string_entry , & self . class_store ) ;
2024-09-05 00:33:14 +02:00
FieldValue ::Reference ( string_object )
} else {
todo! ( )
}
} ,
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
_ = > {
println! ( " {:?} " , field . descriptor . kind ) ;
todo! ( )
} ,
} ;
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
self . heap_area . static_area . set ( class_file . get_classname ( ) ? , & field . name , field_value ) ? ;
}
}
}
}
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
// class object
self . make_class_class ( & ( " L " . to_owned ( ) + & self . class_store . class_file_from_idx ( class_idx ) . unwrap ( ) . get_classname ( ) ? . clone ( ) + " ; " ) ) ;
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
// Push clinit function
let class_file = self . class_store . class_file_from_idx ( class_idx ) . unwrap ( ) ;
let clinit_idx = class_file . find_method_index ( & " <clinit> " . to_string ( ) ) ;
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
if let Some ( method_index ) = clinit_idx {
let clinit_frame = StackFrame ::new (
class_file ,
class_idx ,
method_index as u16 ,
& [ ] ,
) ;
2024-09-02 19:28:22 +02:00
2024-09-05 00:33:14 +02:00
self . stack_frames . push ( clinit_frame ) ;
2024-09-02 19:28:22 +02:00
}
2024-09-05 00:33:14 +02:00
// finish
2024-09-02 12:02:19 +02:00
self . class_store . set_init ( class_idx , true ) ;
2024-09-02 17:44:59 +02:00
Ok ( ( ) )
2024-08-30 15:33:54 +02:00
}
2024-09-09 15:43:26 +02:00
fn native_call ( & mut self ) -> Result < JVMCallbackOperation , Error > {
let frame = {
let frame_index = self . stack_frames . len ( ) - 1 ;
& mut self . stack_frames [ frame_index ]
} ;
let class = self . class_store . class_file_from_idx ( frame . class_index ) . unwrap ( ) ;
let method = & class . methods [ frame . method_index as usize ] ;
let class_name = class . get_classname ( ) . unwrap ( ) ;
let native_method = match self . native_registry . get ( class_name , & method . name ) {
Some ( m ) = > m ,
None = > {
return Err ( Error ::RunTimeError ( format! ( " Tried to call native method ' {class_name} . {} ' but there is no such method in the method registry " , method . name ) ) ) ;
}
} ;
native_method ( self )
}
2024-09-02 11:28:00 +02:00
fn bytecode_loop ( & mut self ) -> Result < JVMCallbackOperation , Error > {
2024-09-10 00:17:17 +02:00
//println!("Enter bytecode loop:");
2024-09-02 11:28:00 +02:00
2024-09-10 00:17:17 +02:00
let frame_index = self . stack_frames . len ( ) - 1 ;
let frame = & mut self . stack_frames [ frame_index ] ;
2024-09-02 11:28:00 +02:00
let class = self . class_store . class_file_from_idx ( frame . class_index ) . unwrap ( ) ;
let method = & class . methods [ frame . method_index as usize ] ;
2024-09-09 15:43:26 +02:00
if method . access_flags & MethodAccessFlag ::Native {
2024-09-10 00:17:17 +02:00
println! ( " {:25} . {:15} : (native) " , class . get_classname ( ) . unwrap ( ) , method . name ) ;
2024-09-09 15:43:26 +02:00
return self . native_call ( )
}
2024-09-02 11:28:00 +02:00
let code_attr = method . get_code_attribute ( ) . unwrap ( ) ;
let bytecode = & code_attr . code ;
while frame . instruction_pointer as usize ! = bytecode . bytes . len ( ) {
let ( instruction , offset ) = bytecode . next_instruction ( frame . instruction_pointer as usize ) ;
frame . instruction_pointer + = offset as u32 ;
2024-09-10 00:17:17 +02:00
println! ( " {} {:25} . {:15} : {:<10} {instruction:?} " , " " . repeat ( frame_index ) , class . get_classname ( ) . unwrap ( ) , method . name , frame . instruction_pointer ) ;
2024-09-05 00:33:14 +02:00
2024-09-02 11:28:00 +02:00
match instruction {
2024-09-05 00:33:14 +02:00
2024-09-10 00:17:17 +02:00
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 ) ) ) ? ;
}
2024-09-10 17:15:20 +02:00
Instruction ::ArithmeticShiftIntRight ( ) = > {
let shift = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? as u8 & 0b00011111 ;
let int = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
// rust does arithmetic shift on singed values
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( int > > shift ) ) ) ? ;
} ,
2024-09-06 21:11:03 +02:00
Instruction ::ArrayLength ( ) = > {
let array_reference = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
let array_length = self . heap_area . object_area . get_array_length ( array_reference ) ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( array_length as i32 ) ) ) ? ;
} ,
Instruction ::ArrayElement ( ) = > {
let element_index = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let array_reference = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
let element = self . heap_area . object_area . get_array_element ( array_reference , element_index ) ;
2024-09-10 12:26:05 +02:00
wrap_stackframe_error ( class , method , frame . operand_stack . push_field_value ( element ) ) ? ;
2024-09-10 23:28:31 +02:00
}
Instruction ::AndInt ( ) = > {
let value_1 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let value_2 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( value_1 & value_2 ) ) ) ? ;
}
2024-09-06 21:11:03 +02:00
Instruction ::BranchAlways ( branch_offset ) = > {
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 } ;
}
2024-09-09 15:43:26 +02:00
Instruction ::BranchIntEquality ( branch_offset ) = > {
let value_2 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-10 00:23:53 +02:00
let value_1 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-09 15:43:26 +02:00
if value_1 = = value_2 {
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 } ;
}
}
2024-09-10 12:26:05 +02:00
Instruction ::BranchIntGreaterEquals ( branch_offset ) = > {
let value_2 = 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 ) ) ? ;
if value_1 > = value_2 {
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 } ;
}
}
2024-09-06 23:51:35 +02:00
Instruction ::BranchIntInequality ( branch_offset ) = > {
let value_2 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-10 00:23:53 +02:00
let value_1 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-06 23:51:35 +02:00
if value_1 ! = value_2 {
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 } ;
}
}
2024-09-10 00:23:53 +02:00
Instruction ::BranchIntLessEquals ( branch_offset ) = > {
let value_2 = 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 ) ) ? ;
if value_1 < = value_2 {
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 } ;
}
}
2024-09-10 17:15:20 +02:00
Instruction ::BranchIntLessThan ( branch_offset ) = > {
let value_2 = 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 ) ) ? ;
if value_1 < value_2 {
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 } ;
}
}
2024-09-09 15:43:26 +02:00
Instruction ::BranchNonNull ( branch_offset ) = > {
let test_value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
if test_value ! = ObjectReference ::NULL {
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 } ;
}
}
2024-09-10 00:17:17 +02:00
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 } ;
}
}
2024-09-10 01:33:35 +02:00
Instruction ::BranchNonPositive ( 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 } ;
}
}
2024-09-10 00:17:17 +02:00
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 } ;
}
}
2024-09-09 15:43:26 +02:00
Instruction ::BranchNull ( branch_offset ) = > {
let test_value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
if test_value = = ObjectReference ::NULL {
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 } ;
}
}
2024-09-10 17:15:20 +02:00
Instruction ::BranchPositive ( branch_offset ) = > {
2024-09-06 21:11:03 +02:00
let test_value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-10 17:15:20 +02:00
if test_value > 0 {
2024-09-06 21:11:03 +02:00
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 } ;
}
}
2024-09-10 01:33:35 +02:00
Instruction ::BranchReferenceInequality ( branch_offset ) = > {
let value_2 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
let value_1 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
if value_1 ! = value_2 {
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 } ;
}
}
2024-09-10 17:15:20 +02:00
Instruction ::BranchZero ( 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 } ;
}
}
2024-09-10 12:26:05 +02:00
Instruction ::CheckCast ( classref_index ) = > {
// TODO: Class loading checks
let class_name = class . gather_class ( classref_index ) ? ;
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 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
let native_class_name = self . heap_area . object_area . get_reference_native_class_name ( object , & self . class_store ) ;
let object_description = AbstractTypeDescription ::parse_full ( native_class_name ) ? ;
if ! self . class_store . are_types_compatible ( & object_description , & class_description ) {
// TODO: Throw Exception
return Err ( Error ::RunTimeError ( format! ( " Trying to cast an object of type {native_class_name} to {class_name} " ) ) )
}
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Reference ( object ) ) ) ? ;
}
2024-09-10 01:33:35 +02:00
Instruction ::CompareFloatG ( ) = > {
let value_2 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_float ( 0 ) ) ? ;
let value_1 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_float ( 0 ) ) ? ;
let comparison_result = if value_1 . is_nan ( ) | | value_2 . is_nan ( ) {
1
} else if value_1 = = value_2 {
0
} else if value_1 < value_2 {
- 1
} else {
1
} ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( comparison_result ) ) ) ? ;
}
Instruction ::CompareFloatL ( ) = > {
let value_2 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_float ( 0 ) ) ? ;
let value_1 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_float ( 0 ) ) ? ;
let comparison_result = if value_1 . is_nan ( ) | | value_2 . is_nan ( ) {
- 1
} else if value_1 = = value_2 {
0
} else if value_1 < value_2 {
- 1
} else {
1
} ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( comparison_result ) ) ) ? ;
}
2024-09-09 15:43:26 +02:00
Instruction ::DivideInt ( ) = > {
// TODO: Obey all the rules
let quotient = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let divident = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
frame . operand_stack . push ( StackValue ::Int ( divident / quotient ) ) . unwrap ( ) ;
}
2024-09-05 00:33:14 +02:00
Instruction ::Duplicate ( ) = > {
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 ) ) ? ;
}
2024-09-09 15:43:26 +02:00
Instruction ::EnterMonitor ( ) = > {
// TODO: Revisit this when doing multi-threading
let _monitored_object = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
}
Instruction ::ExitMonitor ( ) = > {
// TODO: Revisit this when doing multi-threading
let _monitored_object = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
}
2024-09-06 21:11:03 +02:00
Instruction ::GetField ( fieldref_index ) = > {
let ( class_name , field_name , field_descriptor ) = class . gather_fieldref ( fieldref_index ) . unwrap ( ) ;
let this_object = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
// TODO: Are there any methods callable on arrays?
let this_object_class_index = self . heap_area . object_area . get_object_class_index ( this_object ) ;
let this_object_class_name = self . class_store . class_name_from_index ( this_object_class_index ) . unwrap ( ) . to_string ( ) ;
let this_object_descriptor = AbstractTypeDescription {
array_level : 0 ,
kind : AbstractTypeKind ::Classname ( this_object_class_name . clone ( ) )
} ;
let object_descriptor = AbstractTypeDescription {
array_level : 0 ,
kind : AbstractTypeKind ::Classname ( class_name . to_string ( ) )
} ;
if ! self . class_store . are_types_compatible ( & this_object_descriptor , & object_descriptor ) {
return Err ( Error ::RunTimeError ( format! (
" GetField: Cannot fetch '{field_name}' from class '{class_name}' on instance from class '{}: Types are incompatible' " ,
this_object_class_name
) ) )
}
let fetched_value = self . heap_area . object_area . get_object_field ( this_object , field_name , frame . class_index , & self . class_store ) . unwrap ( ) ;
// println!("{fetched_value:?} {field_descriptor}");
// TODO: Check field and value compatability
wrap_stackframe_error ( class , method , frame . operand_stack . push_field_value ( fetched_value ) ) ? ;
}
Instruction ::GetStatic ( fieldref_index ) = > {
let ( class_name , field_name , field_descriptor ) = class . gather_fieldref ( fieldref_index ) . unwrap ( ) ;
if ! self . class_store . have_class ( class_name ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::LoadClass ( class_name . to_string ( ) ) ) ;
}
if ! self . class_store . was_init ( class_name ) . unwrap ( ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::InitClass ( class_name . to_string ( ) ) ) ;
}
// TODO: Throw error
let parsed_field_descriptor = AbstractTypeDescription ::parse_full ( field_descriptor ) . unwrap ( ) ;
// TODO: Throw error
let fetched_value = self . heap_area . static_area . get ( class_name , field_name , parsed_field_descriptor ) . unwrap ( ) ;
wrap_stackframe_error ( class , method , frame . operand_stack . push_field_value ( fetched_value ) ) ? ;
}
2024-09-10 12:26:05 +02:00
Instruction ::IncrementLocalInt ( index , constant ) = > {
let int = wrap_stackframe_error ( class , method , frame . load_local_int ( index as u16 ) ) ? ;
wrap_stackframe_error ( class , method , frame . store_local ( index as u16 , StackValue ::Int ( int + constant as i32 ) ) ) ? ;
}
2024-09-10 01:33:35 +02:00
Instruction ::InstanceOf ( classref_index ) = > {
2024-09-10 12:26:05 +02:00
// TODO: Class loading checks
2024-09-10 01:33:35 +02:00
let class_name = class . gather_class ( classref_index ) ? ;
2024-09-10 12:26:05 +02:00
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 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
let native_class_name = self . heap_area . object_area . get_reference_native_class_name ( object , & self . class_store ) ;
let object_description = AbstractTypeDescription ::parse_full ( native_class_name ) ? ;
let instruction_result = if self . class_store . are_types_compatible ( & object_description , & class_description ) { 1 } else { 0 } ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( instruction_result ) ) ) ? ;
2024-09-10 01:33:35 +02:00
}
2024-09-05 00:33:14 +02:00
Instruction ::InvokeSpecial ( methodref_index ) = > {
2024-09-06 21:11:03 +02:00
// No instance-based dispatch
2024-09-05 00:33:14 +02:00
let ( supplied_class_name , supplied_method_name , supplied_descriptor_string ) = class . gather_methodref ( methodref_index ) ? ;
if ! self . class_store . have_class ( supplied_class_name ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::LoadClass ( supplied_class_name . to_string ( ) ) ) ;
}
if ! self . class_store . was_init ( supplied_class_name ) . unwrap ( ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::InitClass ( supplied_class_name . to_string ( ) ) ) ;
}
let target_class_index = self . class_store . class_idx_from_name ( supplied_class_name ) . unwrap ( ) ;
let parsed_expected_descriptor : MethodDescriptor = MethodDescriptor ::try_from ( supplied_descriptor_string ) ? ;
let ( class_index , method_index , method_info ) = match ClassMethodIterator ::new ( target_class_index , & self . class_store )
. filter ( | ( _cid , _mid , minfo ) | minfo . name = = * supplied_method_name )
. filter ( | ( _cid , _mid , minfo ) | minfo . descriptor = = parsed_expected_descriptor )
. next ( ) {
Some ( m ) = > m ,
None = > {
// TODO: Throw exception
return Err ( Error ::RunTimeError ( format! ( " InvokeSpecial: Failed to find requested method ' {} ' with descriptor ' {} ' in the class ' {} ' " , supplied_method_name , supplied_descriptor_string , supplied_class_name ) ) ) ;
}
} ;
let mut arguments = VecDeque ::new ( ) ;
fill_arguments ( class , method , & mut arguments , & method_info . descriptor . argument_types , & mut frame . operand_stack ) ? ;
// this
arguments . push_front (
StackValue ::Reference (
wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ?
)
) ;
let new_frame = StackFrame ::new (
self . class_store . class_file_from_idx ( class_index ) . unwrap ( ) ,
class_index ,
method_index as u16 ,
& arguments . make_contiguous ( ) ,
) ;
return Ok ( JVMCallbackOperation ::PushFrame ( new_frame ) ) ;
} ,
2024-09-02 11:28:00 +02:00
Instruction ::InvokeStatic ( methodref_index ) = > {
let ( supplied_class_name , supplied_method_name , supplied_descriptor_string ) = class . gather_methodref ( methodref_index ) ? ;
if ! self . class_store . have_class ( supplied_class_name ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::LoadClass ( supplied_class_name . to_string ( ) ) ) ;
}
if ! self . class_store . was_init ( supplied_class_name ) . unwrap ( ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::InitClass ( supplied_class_name . to_string ( ) ) ) ;
}
let ( callee_class_file , callee_class_index ) = self . class_store . get_class ( supplied_class_name ) ? ;
// TODO: Throw exception on fail
let callee_method_index = callee_class_file . find_method_index ( supplied_method_name ) . unwrap ( ) ;
// TODO: Throw exception on fail
let callee_method_info = & callee_class_file . methods [ callee_method_index ] ;
2024-09-02 12:02:19 +02:00
if ! ( callee_method_info . access_flags & MethodAccessFlag ::Static ) {
// TODO: Throw IncompatibleClassChangeError
return Err ( Error ::RunTimeError ( format! (
" Invoked method '{}' in class '{}' does not have Access::Static (from invokestatic from '{}' in class '{}') " ,
method . name ,
class . get_classname ( ) . unwrap ( ) ,
supplied_method_name ,
supplied_class_name ,
) ) ) ;
}
2024-09-02 11:28:00 +02:00
let supplied_descriptor : MethodDescriptor = supplied_descriptor_string . try_into ( ) ? ;
// TODO: Throw exception on fail
if supplied_descriptor ! = callee_method_info . descriptor {
// TODO: Throw exception on fail
return Err ( Error ::RunTimeError ( format! (
" Mismatched method descriptors between caller and callee: Caller ({}) wanted '{}' but found '{}' on Callee ({}) " ,
class . get_classname ( ) . unwrap ( ) ,
supplied_descriptor_string ,
callee_method_info . descriptor . source_string ( ) ,
supplied_class_name ,
) ) ) ;
}
2024-09-02 15:42:42 +02:00
let mut arguments = VecDeque ::new ( ) ;
fill_arguments ( class , method , & mut arguments , & callee_method_info . descriptor . argument_types , & mut frame . operand_stack ) ? ;
2024-09-02 11:28:00 +02:00
2024-09-09 15:43:26 +02:00
// TODO: Throw errors on abstract methods etc.
2024-09-02 11:28:00 +02:00
let new_frame = StackFrame ::new (
callee_class_file ,
callee_class_index ,
callee_method_index as u16 ,
2024-09-02 15:42:42 +02:00
& arguments . make_contiguous ( ) ,
2024-09-02 11:28:00 +02:00
) ;
return Ok ( JVMCallbackOperation ::PushFrame ( new_frame ) ) ;
} ,
2024-09-06 21:11:03 +02:00
Instruction ::InvokeVirtual ( methodref_index ) = > {
let ( base_class_name , base_method_name , base_descriptor_string ) = class . gather_methodref ( methodref_index ) ? ;
if ! self . class_store . have_class ( base_class_name ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::LoadClass ( base_class_name . to_string ( ) ) ) ;
}
if ! self . class_store . was_init ( base_class_name ) . unwrap ( ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::InitClass ( base_class_name . to_string ( ) ) ) ;
}
let base_descriptor = MethodDescriptor ::try_from ( base_descriptor_string ) . unwrap ( ) ;
// extract arguments, they are on top of the stack
let mut arguments = VecDeque ::new ( ) ;
fill_arguments ( class , method , & mut arguments , & base_descriptor . argument_types , & mut frame . operand_stack ) ? ;
let this_object = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
arguments . push_front ( StackValue ::Reference ( this_object ) ) ;
// TODO: Are there any methods callable on arrays?
let this_object_class_index = self . heap_area . object_area . get_object_class_index ( this_object ) ;
let this_object_class_name = self . class_store . class_name_from_index ( this_object_class_index ) . unwrap ( ) . to_string ( ) ;
let this_object_descriptor = AbstractTypeDescription {
array_level : 0 ,
kind : AbstractTypeKind ::Classname ( this_object_class_name . clone ( ) )
} ;
let base_object_descriptor = AbstractTypeDescription {
array_level : 0 ,
kind : AbstractTypeKind ::Classname ( base_class_name . to_string ( ) )
} ;
// TODO: Throw error
if ! self . class_store . are_types_compatible ( & this_object_descriptor , & base_object_descriptor ) {
2024-09-10 17:15:20 +02:00
return Err ( Error ::RunTimeError ( format! ( " InvokeVirtual: Cannot call ' {base_method_name} ' from class ' {base_class_name} ' on instance from class ' {this_object_class_name} : Types are incompatible' " ) ) )
2024-09-06 21:11:03 +02:00
}
let ( invoked_class_index , invoked_method_index , _invoked_method_info ) = match ClassMethodIterator ::new ( this_object_class_index , & self . class_store )
. filter ( | ( _ , _ , method_info ) | method_info . name = = * base_method_name )
. filter ( | ( _ , _ , method_info ) | method_info . descriptor = = base_descriptor )
. next ( )
{
Some ( t ) = > t ,
None = > {
return Err ( Error ::RunTimeError ( format! (
" InvokeVirtual: Failed to find requested method '{}' with descriptor '{}' in the type hierarchy of '{}' " ,
base_method_name ,
base_descriptor_string ,
this_object_class_name ,
) ) ) ;
} ,
} ;
let invoked_class_file = self . class_store . class_file_from_idx ( invoked_class_index ) . unwrap ( ) ;
let new_frame = StackFrame ::new (
invoked_class_file ,
invoked_class_index ,
invoked_method_index as u16 ,
arguments . make_contiguous ( )
) ;
return Ok ( JVMCallbackOperation ::PushFrame ( new_frame ) ) ;
} ,
2024-09-02 15:42:42 +02:00
Instruction ::LoadByteImmediate ( byte ) = > {
// sign extend into int
2024-09-10 17:15:20 +02:00
let frame_result = frame . operand_stack . push ( StackValue ::Int ( byte as i32 ) ) ;
match frame_result {
Ok ( _ ) = > ( ) ,
Err ( err ) = > return Err ( Error ::StackFrameError ( err , format! ( " in ' {} ', in class ' {} ' " , method . name , class . get_classname ( ) . unwrap ( ) ) ) ) ,
}
}
Instruction ::LoadShortImmediate ( short ) = > {
// sign extend into int
let frame_result = frame . operand_stack . push ( StackValue ::Int ( short as i32 ) ) ;
2024-09-02 15:42:42 +02:00
match frame_result {
Ok ( _ ) = > ( ) ,
Err ( err ) = > return Err ( Error ::StackFrameError ( err , format! ( " in ' {} ', in class ' {} ' " , method . name , class . get_classname ( ) . unwrap ( ) ) ) ) ,
}
2024-09-09 15:43:26 +02:00
}
2024-09-10 12:26:05 +02:00
Instruction ::LoadFromBArray ( ) = > {
let index = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let array = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
let element = self . heap_area . object_area . get_array_element ( array , index ) ;
wrap_stackframe_error ( class , method , frame . operand_stack . push_field_value ( element ) ) ? ;
}
2024-09-09 15:43:26 +02:00
Instruction ::LoadConstant ( index ) = > {
// TODO: Handle error instead of unwrap
match class . pool_entry ( index as u16 ) . unwrap ( ) {
ConstantPoolInfo ::Class ( _ ) = > {
let class_name = class . gather_class ( index as u16 ) . unwrap ( ) ;
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 ( ) ) ) ;
}
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 ) ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Reference ( class_object_ref ) ) ) ? ;
}
ConstantPoolInfo ::String ( _ ) = > {
// TODO: Handle error instead of unwrap
let string_constant = class . gather_string ( index as u16 ) . unwrap ( ) ;
let string_obj_ref = self . heap_area . make_handmade_string ( string_constant , & self . class_store ) ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Reference ( string_obj_ref ) ) ) ? ;
2024-09-10 00:23:53 +02:00
}
2024-09-10 00:17:17 +02:00
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 ) ) ) ? ;
2024-09-10 00:23:53 +02:00
}
ConstantPoolInfo ::Integer ( int_data ) = > {
// TODO: Handle error instead of unwrap
let int_constant = int_data . value ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( int_constant ) ) ) ? ;
}
2024-09-09 15:43:26 +02:00
_ = > {
println! ( " {:?} " , class . pool_entry ( index as u16 ) . unwrap ( ) ) ;
todo! ( )
}
}
2024-09-02 15:42:42 +02:00
} ,
2024-09-09 15:43:26 +02:00
Instruction ::LoadCostantWide ( wide_index ) = > {
2024-09-06 23:51:35 +02:00
// TODO: Handle error instead of unwrap
match class . pool_entry ( wide_index ) . unwrap ( ) {
2024-09-09 15:43:26 +02:00
ConstantPoolInfo ::Class ( _ ) = > {
let class_name = class . gather_class ( wide_index ) . unwrap ( ) ;
let class_object_ref = if class_name . starts_with ( '[' ) {
let component_name = class_name . trim_start_matches ( '[' ) ;
let array_level = class_name . len ( ) - component_name . len ( ) ;
let array_type_desc = AbstractTypeDescription {
array_level : array_level as u8 ,
2024-09-10 00:17:17 +02:00
kind : component_name . into ( ) ,
2024-09-09 15:43:26 +02:00
} ;
if let Some ( array_ref ) = self . class_store . get_array_class_ref ( & array_type_desc ) {
array_ref
} else {
let mut test_type = array_type_desc . super_component ( ) ;
let mut test_object_ref = self . class_store . class_ref_for_type ( test_type . clone ( ) ) . unwrap ( ) ;
while let Some ( new_test_object_ref ) = self . class_store . class_ref_for_type ( test_type . array ( ) ) {
test_type = test_type . array ( ) ;
test_object_ref = new_test_object_ref ;
}
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::MakeArrayClass ( test_object_ref , test_type ) )
}
} 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 ( ) ) ) ;
}
let class_index = self . class_store . class_idx_from_name ( class_name ) . unwrap ( ) ;
self . class_store . get_class_objectref_from_index ( class_index )
} ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Reference ( class_object_ref ) ) ) ? ;
}
2024-09-06 23:51:35 +02:00
ConstantPoolInfo ::String ( _ ) = > {
// TODO: Handle error instead of unwrap
let string_constant = class . gather_string ( wide_index ) . unwrap ( ) ;
let string_obj_ref = self . heap_area . make_handmade_string ( string_constant , & self . class_store ) ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Reference ( string_obj_ref ) ) ) ? ;
2024-09-10 17:15:20 +02:00
}
ConstantPoolInfo ::Integer ( int_data ) = > {
let int_value = int_data . value ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( int_value ) ) ) ? ;
}
2024-09-09 15:43:26 +02:00
_ = > {
println! ( " {:?} " , class . pool_entry ( wide_index ) . unwrap ( ) ) ;
todo! ( )
}
2024-09-06 23:51:35 +02:00
}
2024-09-10 17:15:20 +02:00
}
2024-09-06 23:51:35 +02:00
2024-09-10 01:33:35 +02:00
Instruction ::LoadLocalFloat0 ( ) = > {
load_local_float ( class , method , frame , 0 ) ? ;
}
Instruction ::LoadLocalFloat1 ( ) = > {
load_local_float ( class , method , frame , 1 ) ? ;
}
Instruction ::LoadLocalFloat2 ( ) = > {
load_local_float ( class , method , frame , 2 ) ? ;
}
Instruction ::LoadLocalFloat3 ( ) = > {
load_local_float ( class , method , frame , 3 ) ? ;
}
2024-09-10 23:28:31 +02:00
Instruction ::LoadLocalInt ( index ) = > {
load_local_int ( class , method , frame , index as usize ) ? ;
}
2024-09-02 15:42:42 +02:00
Instruction ::LoadLocalInt0 ( ) = > {
load_local_int ( class , method , frame , 0 ) ? ;
}
Instruction ::LoadLocalInt1 ( ) = > {
load_local_int ( class , method , frame , 1 ) ? ;
}
Instruction ::LoadLocalInt2 ( ) = > {
load_local_int ( class , method , frame , 2 ) ? ;
}
Instruction ::LoadLocalInt3 ( ) = > {
load_local_int ( class , method , frame , 3 ) ? ;
}
2024-09-10 17:15:20 +02:00
Instruction ::LoadLocalReference ( index ) = > {
load_local_reference ( class , method , frame , index as usize ) ? ;
}
2024-09-05 00:33:14 +02:00
Instruction ::LoadLocalReference0 ( ) = > {
load_local_reference ( class , method , frame , 0 ) ? ;
}
2024-09-06 21:11:03 +02:00
Instruction ::LoadLocalReference1 ( ) = > {
load_local_reference ( class , method , frame , 1 ) ? ;
}
Instruction ::LoadLocalReference2 ( ) = > {
load_local_reference ( class , method , frame , 2 ) ? ;
}
Instruction ::LoadLocalReference3 ( ) = > {
load_local_reference ( class , method , frame , 3 ) ? ;
}
2024-09-05 00:33:14 +02:00
2024-09-10 17:15:20 +02:00
Instruction ::LogicalShiftIntRight ( ) = > {
let shift = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? as u8 & 0b00011111 ;
let int = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let uint = u32 ::from_ne_bytes ( int . to_ne_bytes ( ) ) ;
let u_result = uint > > shift ;
let i_result = i32 ::from_ne_bytes ( u_result . to_ne_bytes ( ) ) ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( i_result ) ) ) ? ;
}
Instruction ::LookupSwitch ( default_offset , pairs ) = > {
let key = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let jump_offset = match pairs . binary_search_by ( | ( match_key , _offset ) | match_key . cmp ( & key ) ) {
Ok ( offset ) = > pairs [ offset ] . 1 ,
Err ( _ ) = > default_offset ,
} ;
frame . instruction_pointer - = offset as u32 ;
frame . instruction_pointer = if jump_offset < 0 { frame . instruction_pointer - jump_offset . abs ( ) as u32 } else { frame . instruction_pointer + jump_offset . abs ( ) as u32 } ;
}
2024-09-02 15:42:42 +02:00
Instruction ::MultiplyInt ( ) = > {
let factor_1 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let factor_2 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-02 17:46:00 +02:00
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( factor_1 * factor_2 ) ) ) ? ;
2024-09-02 15:42:42 +02:00
}
2024-09-06 23:51:35 +02:00
Instruction ::NewArray ( component_class_index ) = > {
2024-09-05 00:33:14 +02:00
// construct single level array
2024-09-06 23:51:35 +02:00
let component_class_name = class . gather_class ( component_class_index ) ? ;
2024-09-05 00:33:14 +02:00
2024-09-06 23:51:35 +02:00
if ! self . class_store . have_class ( component_class_name ) {
2024-09-05 00:33:14 +02:00
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
2024-09-06 23:51:35 +02:00
return Ok ( JVMCallbackOperation ::LoadClass ( component_class_name . to_string ( ) ) ) ;
2024-09-05 00:33:14 +02:00
}
2024-09-06 23:51:35 +02:00
if ! self . class_store . was_init ( component_class_name ) . unwrap ( ) {
2024-09-05 00:33:14 +02:00
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
2024-09-06 23:51:35 +02:00
return Ok ( JVMCallbackOperation ::InitClass ( component_class_name . to_string ( ) ) ) ;
2024-09-05 00:33:14 +02:00
}
2024-09-06 23:51:35 +02:00
let component_class_descriptor = AbstractTypeDescription {
2024-09-05 00:33:14 +02:00
array_level : 0 ,
2024-09-06 23:51:35 +02:00
kind : match component_class_name {
_ = > AbstractTypeKind ::Classname ( component_class_name . to_string ( ) )
2024-09-05 00:33:14 +02:00
}
} ;
let array_descriptor = AbstractTypeDescription {
array_level : 1 ,
2024-09-06 23:51:35 +02:00
kind : component_class_descriptor . kind . clone ( ) ,
2024-09-05 00:33:14 +02:00
} ;
if let None = self . class_store . get_array_class_ref ( & array_descriptor ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
2024-09-06 23:51:35 +02:00
let component_class_index = self . class_store . class_idx_from_name ( component_class_name ) . unwrap ( ) ;
let component_class_class_ref = self . class_store . get_class_objectref_from_index ( component_class_index ) ;
return Ok ( JVMCallbackOperation ::MakeArrayClass ( component_class_class_ref , component_class_descriptor ) ) ;
2024-09-05 00:33:14 +02:00
}
let array_capacity = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-06 23:51:35 +02:00
let array_ref = self . heap_area . make_empty_array ( & self . class_store , component_class_descriptor , array_capacity as usize ) ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Reference ( array_ref ) ) ) ? ;
}
Instruction ::NewPrimitiveArray ( array_type ) = > {
let array_capacity = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-10 12:26:05 +02:00
const CHAR : u8 = 5 ;
2024-09-06 23:51:35 +02:00
const BYTE : u8 = 8 ;
let array_ref = match array_type {
BYTE = > {
let array_ref = self . heap_area . make_primitive_byte_array ( array_capacity as usize , & self . class_store ) ;
array_ref
}
2024-09-10 12:26:05 +02:00
CHAR = > {
let array_ref = self . heap_area . make_primitive_char_array ( array_capacity as usize , & self . class_store ) ;
array_ref
}
2024-09-06 23:51:35 +02:00
_ = > todo! ( )
} ;
2024-09-05 00:33:14 +02:00
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Reference ( array_ref ) ) ) ? ;
}
Instruction ::NewObject ( class_index ) = > {
let class_name = class . gather_class ( class_index ) ? ;
if ! self . class_store . have_class ( class_name ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::LoadClass ( class_name . to_string ( ) ) ) ;
}
if ! self . class_store . was_init ( class_name ) . unwrap ( ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::InitClass ( class_name . to_string ( ) ) ) ;
}
let class_index = self . class_store . class_idx_from_name ( class_name ) . unwrap ( ) ;
let new_object = self . heap_area . make_object ( & self . class_store , class_index ) ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Reference ( new_object ) ) ) ? ;
} ,
2024-09-10 00:17:17 +02:00
Instruction ::Pop ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . pop_computational_1 ( 0 ) ) ? ;
}
2024-09-10 01:33:35 +02:00
Instruction ::PushConstFloat0 ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Float ( 0.0 ) ) ) ? ;
}
Instruction ::PushConstFloat1 ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Float ( 1.0 ) ) ) ? ;
}
Instruction ::PushConstFloat2 ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Float ( 2.0 ) ) ) ? ;
}
2024-09-10 12:26:05 +02:00
Instruction ::PushConstIntM1 ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( - 1 ) ) ) ? ;
}
2024-09-05 00:33:14 +02:00
Instruction ::PushConstInt0 ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( 0 ) ) ) ? ;
}
Instruction ::PushConstInt1 ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( 1 ) ) ) ? ;
}
Instruction ::PushConstInt2 ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( 2 ) ) ) ? ;
}
Instruction ::PushConstInt3 ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( 3 ) ) ) ? ;
}
Instruction ::PushConstInt4 ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( 4 ) ) ) ? ;
}
2024-09-02 15:42:42 +02:00
Instruction ::PushConstInt5 ( ) = > {
2024-09-05 00:33:14 +02:00
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( 5 ) ) ) ? ;
}
2024-09-09 15:43:26 +02:00
Instruction ::PushNull ( ) = > {
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Reference ( ObjectReference ::NULL ) ) ) ? ;
}
2024-09-10 00:17:17 +02:00
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 ) ,
2024-09-10 12:26:05 +02:00
StackValue ::Float ( f ) = > FieldValue ::Float ( f ) ,
2024-09-10 00:17:17 +02:00
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 ) ? ;
}
2024-09-05 00:33:14 +02:00
Instruction ::PutStatic ( fieldref_index ) = > {
let ( target_class_name , target_field_name , expected_field_descriptor ) = class . gather_fieldref ( fieldref_index ) ? ;
if ! self . class_store . have_class ( target_class_name ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::LoadClass ( target_class_name . to_string ( ) ) ) ;
}
if ! self . class_store . was_init ( target_class_name ) . unwrap ( ) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame . instruction_pointer - = offset as u32 ;
return Ok ( JVMCallbackOperation ::InitClass ( target_class_name . to_string ( ) ) ) ;
}
let matched_field = match ClassFieldIterator ::new ( self . class_store . class_idx_from_name ( target_class_name ) . unwrap ( ) , & self . class_store )
. filter ( | f | f . name = = * target_field_name )
. filter ( | f | f . access_flags & FieldAccessFlag ::Static )
. next ( ) {
Some ( f ) = > f ,
None = > return Err ( Error ::RunTimeError ( format! ( " PutStatic: Trying to set field ' {} ' on class ' {} ' but there is no such static field " , target_field_name , target_class_name ) ) )
} ;
let ( consumed_chars , expected_descriptor ) = AbstractTypeDescription ::parse_first ( expected_field_descriptor ) ? ;
assert! ( expected_field_descriptor . len ( ) = = consumed_chars ) ;
// TODO: Throw exception on fail
if matched_field . descriptor ! = expected_descriptor {
return Err ( Error ::RunTimeError ( format! ( " PutStatic: Field descriptor mismatch: ' {expected_descriptor:?} ' but found ' {:?} ' " , matched_field . descriptor ) ) )
2024-09-02 15:42:42 +02:00
}
2024-09-05 00:33:14 +02:00
let set_value = match ( matched_field . descriptor . array_level , & matched_field . descriptor . kind ) {
( 0 , AbstractTypeKind ::Boolean ( ) ) = > {
let int_value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
FieldValue ::Boolean ( ( int_value & 1 ) ! = 0 )
2024-09-10 00:17:17 +02:00
}
( 0 , AbstractTypeKind ::Int ( ) ) = > {
let int_value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
FieldValue ::Int ( int_value )
}
2024-09-05 00:33:14 +02:00
( 0 ..= 255 , AbstractTypeKind ::Classname ( _field_type_name ) ) = > {
let ref_value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
2024-09-09 15:43:26 +02:00
if ref_value ! = ObjectReference ::NULL {
2024-09-10 17:15:20 +02:00
let value_native_name = self . heap_area . object_area . get_reference_native_class_name ( ref_value , & self . class_store ) ;
2024-09-09 15:43:26 +02:00
let parsed_native_name = AbstractTypeDescription ::parse_first ( value_native_name ) . unwrap ( ) . 1 ;
2024-09-05 00:33:14 +02:00
2024-09-10 17:15:20 +02:00
if ! self . class_store . are_types_compatible ( & parsed_native_name , & matched_field . descriptor ) {
2024-09-09 15:43:26 +02:00
return Err ( Error ::RunTimeError ( format! ( " PutStatic: Trying to set a value with type ' {parsed_native_name:?} ' on a field with type ' {:?} ' " , matched_field . descriptor ) ) ) ;
}
2024-09-05 00:33:14 +02:00
}
FieldValue ::Reference ( ref_value )
}
2024-09-10 17:15:20 +02:00
( 1 ..= 255 , _ ) = > {
let ref_value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
FieldValue ::Reference ( ref_value )
}
2024-09-05 00:33:14 +02:00
_ = > {
println! ( " {:?} " , matched_field ) ;
todo! ( )
2024-09-10 17:15:20 +02:00
}
2024-09-05 00:33:14 +02:00
} ;
self . heap_area . static_area . set ( target_class_name , target_field_name , set_value ) ? ;
2024-09-02 15:42:42 +02:00
}
Instruction ::ReturnInt ( ) = > {
2024-09-06 21:11:03 +02:00
match ( method . descriptor . return_type . array_level , & method . descriptor . return_type . kind ) {
( _ , AbstractTypeKind ::Byte ( ) | AbstractTypeKind ::Boolean ( ) | AbstractTypeKind ::Int ( ) | AbstractTypeKind ::Char ( ) | AbstractTypeKind ::Short ( ) ) = > ( ) ,
_ = > return Err ( Error ::OpcodeError ( format! ( " Found opcode ' {:?} ' on method returning ' {:?} ' " , instruction , method . descriptor . return_type ) ) )
2024-09-02 15:42:42 +02:00
}
let int = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-02 17:46:00 +02:00
return Ok ( JVMCallbackOperation ::ReturnFrame ( StackValue ::Int ( int ) ) ) ;
2024-09-02 15:42:42 +02:00
}
2024-09-09 15:43:26 +02:00
Instruction ::ReturnReference ( ) = > {
match ( method . descriptor . return_type . array_level , & method . descriptor . return_type . kind ) {
( _ , AbstractTypeKind ::Classname ( _ ) ) = > ( ) ,
_ = > return Err ( Error ::OpcodeError ( format! ( " Found opcode ' {:?} ' on method returning ' {:?} ' " , instruction , method . descriptor . return_type ) ) )
}
let ref_value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
return Ok ( JVMCallbackOperation ::ReturnFrame ( StackValue ::Reference ( ref_value ) ) ) ;
}
2024-09-02 12:02:19 +02:00
Instruction ::ReturnVoid ( ) = > {
let expected_type = AbstractTypeDescription {
array_level : 0 ,
kind : AbstractTypeKind ::Void ( ) ,
} ;
if method . descriptor . return_type ! = expected_type {
return Err ( Error ::OpcodeError ( format! ( " Found opcode ' {:?} ' on method returning ' {:?} ' " , instruction , method . descriptor . return_type ) ) )
}
return Ok ( JVMCallbackOperation ::PopFrame ( ) ) ;
} ,
2024-09-09 15:43:26 +02:00
Instruction ::StoreIntoBArray ( ) = > {
2024-09-06 23:51:35 +02:00
let value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let index = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let array_ref = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
match self . heap_area . object_area . get_entry ( array_ref ) {
CompartmentEntry ::ByteArray ( _ ) = > {
2024-09-10 17:15:20 +02:00
let byte_value = value as i8 ;
2024-09-06 23:51:35 +02:00
self . heap_area . object_area . set_array_element ( array_ref , index as usize , FieldValue ::Byte ( byte_value ) ) ;
}
_ = > todo! ( ) , // TODO: Handle as error, Boolean arrays also
}
}
2024-09-10 17:15:20 +02:00
Instruction ::StoreIntoCArray ( ) = > {
let value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let index = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let array_ref = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
match self . heap_area . object_area . get_entry ( array_ref ) {
CompartmentEntry ::CharArray ( _ ) = > {
let int_bytes = value . to_ne_bytes ( ) ;
let char_value = u16 ::from_ne_bytes ( [ int_bytes [ 2 ] , int_bytes [ 3 ] ] ) ;
self . heap_area . object_area . set_array_element ( array_ref , index as usize , FieldValue ::Char ( char_value ) ) ;
}
_ = > todo! ( ) , // TODO: Handle as error
}
}
2024-09-09 15:43:26 +02:00
Instruction ::StoreIntoRArray ( ) = > {
let value = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
let index = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let array_ref = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
// TODO: Type checking
self . heap_area . object_area . set_array_element ( array_ref , index as usize , FieldValue ::Reference ( value ) ) ;
}
2024-09-10 12:26:05 +02:00
Instruction ::SubtractInt ( ) = > {
let value_2 = 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_1 - value_2 ) ) ) ? ;
}
2024-09-06 23:51:35 +02:00
Instruction ::StoreLocalInt ( index ) = > {
let int = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
wrap_stackframe_error ( class , method , frame . store_local ( index as u16 , StackValue ::Int ( int ) ) ) ? ;
2024-09-10 12:26:05 +02:00
}
2024-09-02 15:42:42 +02:00
Instruction ::StoreLocalInt0 ( ) = > {
let int = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-02 17:46:00 +02:00
wrap_stackframe_error ( class , method , frame . store_local ( 0 , StackValue ::Int ( int ) ) ) ? ;
2024-09-10 12:26:05 +02:00
}
2024-09-02 15:42:42 +02:00
Instruction ::StoreLocalInt1 ( ) = > {
2024-09-05 00:33:14 +02:00
let int = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-02 15:42:42 +02:00
2024-09-05 00:33:14 +02:00
wrap_stackframe_error ( class , method , frame . store_local ( 1 , StackValue ::Int ( int ) ) ) ? ;
2024-09-10 12:26:05 +02:00
}
2024-09-02 15:42:42 +02:00
Instruction ::StoreLocalInt2 ( ) = > {
2024-09-05 00:33:14 +02:00
let int = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-02 15:42:42 +02:00
2024-09-05 00:33:14 +02:00
wrap_stackframe_error ( class , method , frame . store_local ( 2 , StackValue ::Int ( int ) ) ) ? ;
2024-09-10 12:26:05 +02:00
}
2024-09-02 15:42:42 +02:00
Instruction ::StoreLocalInt3 ( ) = > {
2024-09-05 00:33:14 +02:00
let int = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
2024-09-02 15:42:42 +02:00
2024-09-05 00:33:14 +02:00
wrap_stackframe_error ( class , method , frame . store_local ( 3 , StackValue ::Int ( int ) ) ) ? ;
2024-09-10 12:26:05 +02:00
}
2024-09-02 15:42:42 +02:00
2024-09-10 17:15:20 +02:00
Instruction ::StoreLocalReference ( index ) = > {
let reference = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
wrap_stackframe_error ( class , method , frame . store_local ( index as u16 , StackValue ::Reference ( reference ) ) ) ? ;
}
Instruction ::StoreLocalReference0 ( ) = > {
2024-09-06 21:11:03 +02:00
let reference = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
wrap_stackframe_error ( class , method , frame . store_local ( 0 , StackValue ::Reference ( reference ) ) ) ? ;
2024-09-10 17:15:20 +02:00
}
Instruction ::StoreLocalReference1 ( ) = > {
2024-09-06 21:11:03 +02:00
let reference = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
wrap_stackframe_error ( class , method , frame . store_local ( 1 , StackValue ::Reference ( reference ) ) ) ? ;
2024-09-10 17:15:20 +02:00
}
Instruction ::StoreLocalReference2 ( ) = > {
2024-09-06 21:11:03 +02:00
let reference = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
wrap_stackframe_error ( class , method , frame . store_local ( 2 , StackValue ::Reference ( reference ) ) ) ? ;
2024-09-10 17:15:20 +02:00
}
Instruction ::StoreLocalReference3 ( ) = > {
2024-09-06 21:11:03 +02:00
let reference = wrap_stackframe_error ( class , method , frame . operand_stack . pop_reference ( 0 ) ) ? ;
wrap_stackframe_error ( class , method , frame . store_local ( 3 , StackValue ::Reference ( reference ) ) ) ? ;
2024-09-10 17:15:20 +02:00
}
2024-09-06 21:11:03 +02:00
2024-09-10 23:28:31 +02:00
Instruction ::TableSwitch ( default , low , high , offsets ) = > {
let index = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
frame . instruction_pointer - = offset as u32 ;
if index < low | | index > high {
frame . instruction_pointer = if default < 0 { frame . instruction_pointer - default . abs ( ) as u32 } else { frame . instruction_pointer + default . abs ( ) as u32 } ;
} else {
let offset_index = index - low ;
let jump_offset = offsets [ offset_index as usize ] ;
frame . instruction_pointer = if jump_offset < 0 { frame . instruction_pointer - jump_offset . abs ( ) as u32 } else { frame . instruction_pointer + jump_offset . abs ( ) as u32 } ;
}
}
Instruction ::XorInt ( ) = > {
let value_1 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
let value_2 = wrap_stackframe_error ( class , method , frame . operand_stack . pop_int ( 0 ) ) ? ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( value_1 ^ value_2 ) ) ) ? ;
}
2024-09-02 11:28:00 +02:00
_ = > {
return Err ( Error ::RunTimeError ( format! ( " Opcode not implemented yet: {:?} " , instruction ) ) )
} ,
}
}
2024-09-02 15:42:42 +02:00
// TODO: Review this, maybe crash when there is no return?
2024-09-02 11:28:00 +02:00
Ok ( JVMCallbackOperation ::PopFrame ( ) )
}
}
2024-09-09 15:43:26 +02:00
pub enum JVMCallbackOperation {
2024-09-02 11:28:00 +02:00
PopFrame ( ) ,
2024-09-02 17:46:00 +02:00
ReturnFrame ( StackValue ) ,
2024-09-02 11:28:00 +02:00
PushFrame ( StackFrame ) ,
LoadClass ( String ) ,
InitClass ( String ) ,
2024-09-06 23:51:35 +02:00
MakeArrayClass ( ObjectReference , AbstractTypeDescription ) ,
2024-09-05 00:33:14 +02:00
}
fn load_local_reference ( class : & JavaClassFile , method : & MethodInfo , frame : & mut StackFrame , index : usize ) -> Result < ( ) , Error > {
let loaded_value = wrap_stackframe_error ( class , method , frame . load_local_reference ( index as u16 ) ) ? ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Reference ( loaded_value ) ) ) ? ;
2024-09-10 01:33:35 +02:00
Ok ( ( ) )
}
fn load_local_float ( class : & JavaClassFile , method : & MethodInfo , frame : & mut StackFrame , index : usize ) -> Result < ( ) , Error > {
let loaded_value = wrap_stackframe_error ( class , method , frame . load_local_float ( index as u16 ) ) ? ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Float ( loaded_value ) ) ) ? ;
2024-09-05 00:33:14 +02:00
Ok ( ( ) )
2024-08-30 15:33:54 +02:00
}
2024-09-02 15:42:42 +02:00
fn load_local_int ( class : & JavaClassFile , method : & MethodInfo , frame : & mut StackFrame , index : usize ) -> Result < ( ) , Error > {
2024-09-05 00:33:14 +02:00
let loaded_value = wrap_stackframe_error ( class , method , frame . load_local_int ( index as u16 ) ) ? ;
wrap_stackframe_error ( class , method , frame . operand_stack . push ( StackValue ::Int ( loaded_value ) ) ) ? ;
Ok ( ( ) )
2024-09-02 15:42:42 +02:00
}
2024-09-02 17:46:00 +02:00
fn fill_arguments ( class : & JavaClassFile , method : & MethodInfo , arguments : & mut VecDeque < StackValue > , argument_types : & Box < [ AbstractTypeDescription ] > , stack : & mut OperandStack ) -> Result < ( ) , Error > {
2024-09-10 00:17:17 +02:00
for argument_type_index in 0 .. argument_types . len ( ) {
let argument_type = & argument_types [ argument_types . len ( ) - argument_type_index - 1 ] ;
2024-09-02 15:42:42 +02:00
if argument_type . array_level ! = 0 {
// TODO: Type checking
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Reference ( wrap_stackframe_error ( class , method , stack . pop_reference ( 0 ) ) ? ) ,
2024-09-02 15:42:42 +02:00
)
} else {
match argument_type . kind {
AbstractTypeKind ::Void ( ) = > return Err ( Error ::RunTimeError ( " Functions cannot take arguments of type void " . to_string ( ) ) ) ,
// TODO: Add better description
AbstractTypeKind ::Byte ( ) = > {
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Byte (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_byte ( 0 )
) ?
)
)
} ,
AbstractTypeKind ::Char ( ) = > {
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Char (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_char ( 0 )
) ?
)
)
} ,
AbstractTypeKind ::Double ( ) = > {
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Double1 (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_double1 ( 0 )
) ?
)
) ;
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Double0 (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_double0 ( 0 )
) ?
)
) ;
} ,
AbstractTypeKind ::Float ( ) = > {
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Float (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_float ( 0 )
) ?
)
)
} ,
AbstractTypeKind ::Int ( ) = > {
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Int (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_int ( 0 )
) ?
)
)
} ,
AbstractTypeKind ::Long ( ) = > {
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Long1 (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_long1 ( 0 )
) ?
)
) ;
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Long0 (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_long0 ( 0 )
) ?
)
) ;
} ,
AbstractTypeKind ::Classname ( ref name ) = > {
// TODO: Type checking
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Reference (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_reference ( 0 )
) ?
)
)
} ,
AbstractTypeKind ::Short ( ) = > {
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Short (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_short ( 0 )
) ?
)
)
} ,
AbstractTypeKind ::Boolean ( ) = > {
arguments . push_front (
2024-09-02 17:46:00 +02:00
StackValue ::Boolean (
2024-09-02 15:42:42 +02:00
wrap_stackframe_error (
class ,
method ,
stack . pop_boolean ( 0 )
) ?
)
)
} ,
}
}
}
Ok ( ( ) )
}
2024-09-10 00:17:17 +02:00
pub fn wrap_stackframe_error < T > ( class : & JavaClassFile , method : & MethodInfo , frame_result : Result < T , stackframe ::Error > ) -> Result < T , Error > {
2024-09-02 15:42:42 +02:00
match frame_result {
Ok ( t ) = > Ok ( t ) ,
Err ( err ) = > return Err ( Error ::StackFrameError ( err , format! ( " in ' {} ', in class ' {} ' " , method . name , class . get_classname ( ) . unwrap ( ) ) ) ) ,
}
}