11// Register-based virtual machine for when we can't JIT,
22// like on iOS.
33
4+ use std:: convert:: TryInto ;
45use std:: fmt;
56
67/// Register index (0-255)
@@ -285,6 +286,15 @@ pub enum Opcode {
285286 /// Zero memory region
286287 MemZero { dst : Reg , size : u32 } ,
287288
289+ // ============ Register Save/Restore ============
290+
291+ /// Save registers [start_reg..start_reg+count] to locals at slot offset.
292+ /// Each register is 8 bytes.
293+ SaveRegs { start_reg : Reg , count : u8 , slot : u32 } ,
294+
295+ /// Restore registers [start_reg..start_reg+count] from locals at slot offset.
296+ RestoreRegs { start_reg : Reg , count : u8 , slot : u32 } ,
297+
288298 // ============ Debugging ============
289299
290300 /// Print integer value (for debugging)
@@ -394,9 +404,6 @@ struct CallFrame {
394404
395405 /// Register snapshot (for return value handling)
396406 return_reg : Reg ,
397-
398- /// Saved registers - stored as boxed array to avoid stack overflow
399- saved_registers : Box < [ u64 ; 256 ] > ,
400407}
401408
402409/// The virtual machine state
@@ -888,13 +895,12 @@ impl VM {
888895 }
889896
890897 Opcode :: Call { func, args_start, arg_count } => {
891- // Save current frame with registers
898+ // Save current frame
892899 let frame = CallFrame {
893900 func_idx : self . current_func ,
894901 ip : self . ip ,
895902 locals_base : self . locals_base ,
896903 return_reg : 0 ,
897- saved_registers : Box :: new ( self . registers ) ,
898904 } ;
899905 self . call_stack . push ( frame) ;
900906
@@ -925,13 +931,12 @@ impl VM {
925931 Opcode :: CallIndirect { func_reg, args_start, arg_count } => {
926932 let func_idx = self . get_u64 ( func_reg) as FuncIdx ;
927933
928- // Save current frame with registers
934+ // Save current frame
929935 let frame = CallFrame {
930936 func_idx : self . current_func ,
931937 ip : self . ip ,
932938 locals_base : self . locals_base ,
933939 return_reg : 0 ,
934- saved_registers : Box :: new ( self . registers ) ,
935940 } ;
936941 self . call_stack . push ( frame) ;
937942
@@ -953,36 +958,26 @@ impl VM {
953958 }
954959
955960 Opcode :: Return => {
956- // Save return value (implicitly in r0) before restoring registers
957- let return_value = self . registers [ 0 ] ;
958-
959961 if self . call_stack . is_empty ( ) {
960962 return self . get_i64 ( 0 ) ;
961963 }
962964 let frame = self . call_stack . pop ( ) . unwrap ( ) ;
963965 self . current_func = frame. func_idx ;
964966 self . ip = frame. ip ;
965967 self . locals_base = frame. locals_base ;
966- // Restore caller's registers and put return value in r0
967- self . registers = * frame. saved_registers ;
968- self . registers [ 0 ] = return_value;
969968 }
970969
971970 Opcode :: ReturnReg { src } => {
972- // Save return value before restoring registers
973- let return_value = self . registers [ src as usize ] ;
971+ // Move return value to r0
972+ self . registers [ 0 ] = self . registers [ src as usize ] ;
974973
975974 if self . call_stack . is_empty ( ) {
976- self . registers [ 0 ] = return_value;
977975 return self . get_i64 ( 0 ) ;
978976 }
979977 let frame = self . call_stack . pop ( ) . unwrap ( ) ;
980978 self . current_func = frame. func_idx ;
981979 self . ip = frame. ip ;
982980 self . locals_base = frame. locals_base ;
983- // Restore caller's registers and put return value in r0
984- self . registers = * frame. saved_registers ;
985- self . registers [ 0 ] = return_value;
986981 }
987982
988983 Opcode :: AllocLocals { size } => {
@@ -1011,6 +1006,24 @@ impl VM {
10111006 }
10121007 }
10131008
1009+ Opcode :: SaveRegs { start_reg, count, slot } => {
1010+ let base = self . locals_base + slot as usize ;
1011+ for i in 0 ..count as usize {
1012+ let reg_val = self . registers [ start_reg as usize + i] ;
1013+ let offset = base + i * 8 ;
1014+ self . locals [ offset..offset + 8 ] . copy_from_slice ( & reg_val. to_le_bytes ( ) ) ;
1015+ }
1016+ }
1017+
1018+ Opcode :: RestoreRegs { start_reg, count, slot } => {
1019+ let base = self . locals_base + slot as usize ;
1020+ for i in 0 ..count as usize {
1021+ let offset = base + i * 8 ;
1022+ let bytes: [ u8 ; 8 ] = self . locals [ offset..offset + 8 ] . try_into ( ) . unwrap ( ) ;
1023+ self . registers [ start_reg as usize + i] = u64:: from_le_bytes ( bytes) ;
1024+ }
1025+ }
1026+
10141027 // Debugging
10151028 Opcode :: PrintI32 { src } => {
10161029 println ! ( "{}" , self . get_i64( src) as i32 ) ;
0 commit comments