@@ -270,6 +270,14 @@ impl From<VALUE> for Opnd {
270
270
}
271
271
}
272
272
273
+ /// Set of things we need to restore for side exits.
274
+ #[ derive( Clone , Debug ) ]
275
+ pub struct SideExitContext {
276
+ pub pc : * const VALUE ,
277
+ pub stack : Vec < Opnd > ,
278
+ pub locals : Vec < Opnd > ,
279
+ }
280
+
273
281
/// Branch target (something that we can jump to)
274
282
/// for branch instructions
275
283
#[ derive( Clone , Debug ) ]
@@ -281,12 +289,14 @@ pub enum Target
281
289
Label ( Label ) ,
282
290
/// Side exit to the interpreter
283
291
SideExit {
284
- pc : * const VALUE ,
285
- stack : Vec < Opnd > ,
286
- locals : Vec < Opnd > ,
287
- c_stack_bytes : usize ,
292
+ /// Context to restore on regular side exits. None for side exits right
293
+ /// after JIT-to-JIT calls because we restore them before the JIT call.
294
+ context : Option < SideExitContext > ,
295
+ /// We use this to enrich asm comments.
288
296
reason : SideExitReason ,
289
- // Some if the side exit should write this label. We use it for patch points.
297
+ /// The number of bytes we need to adjust the C stack pointer by.
298
+ c_stack_bytes : usize ,
299
+ /// Some if the side exit should write this label. We use it for patch points.
290
300
label : Option < Label > ,
291
301
} ,
292
302
}
@@ -767,7 +777,7 @@ impl<'a> Iterator for InsnOpndIterator<'a> {
767
777
Insn :: Label ( target) |
768
778
Insn :: LeaJumpTarget { target, .. } |
769
779
Insn :: PatchPoint ( target) => {
770
- if let Target :: SideExit { stack, locals, .. } = target {
780
+ if let Target :: SideExit { context : Some ( SideExitContext { stack, locals, .. } ) , .. } = target {
771
781
let stack_idx = self . idx ;
772
782
if stack_idx < stack. len ( ) {
773
783
let opnd = & stack[ stack_idx] ;
@@ -792,7 +802,7 @@ impl<'a> Iterator for InsnOpndIterator<'a> {
792
802
return Some ( opnd) ;
793
803
}
794
804
795
- if let Target :: SideExit { stack, locals, .. } = target {
805
+ if let Target :: SideExit { context : Some ( SideExitContext { stack, locals, .. } ) , .. } = target {
796
806
let stack_idx = self . idx - 1 ;
797
807
if stack_idx < stack. len ( ) {
798
808
let opnd = & stack[ stack_idx] ;
@@ -923,7 +933,7 @@ impl<'a> InsnOpndMutIterator<'a> {
923
933
Insn :: Label ( target) |
924
934
Insn :: LeaJumpTarget { target, .. } |
925
935
Insn :: PatchPoint ( target) => {
926
- if let Target :: SideExit { stack, locals, .. } = target {
936
+ if let Target :: SideExit { context : Some ( SideExitContext { stack, locals, .. } ) , .. } = target {
927
937
let stack_idx = self . idx ;
928
938
if stack_idx < stack. len ( ) {
929
939
let opnd = & mut stack[ stack_idx] ;
@@ -948,7 +958,7 @@ impl<'a> InsnOpndMutIterator<'a> {
948
958
return Some ( opnd) ;
949
959
}
950
960
951
- if let Target :: SideExit { stack, locals, .. } = target {
961
+ if let Target :: SideExit { context : Some ( SideExitContext { stack, locals, .. } ) , .. } = target {
952
962
let stack_idx = self . idx - 1 ;
953
963
if stack_idx < stack. len ( ) {
954
964
let opnd = & mut stack[ stack_idx] ;
@@ -1803,7 +1813,7 @@ impl Assembler
1803
1813
for ( idx, target) in targets {
1804
1814
// Compile a side exit. Note that this is past the split pass and alloc_regs(),
1805
1815
// so you can't use a VReg or an instruction that needs to be split.
1806
- if let Target :: SideExit { pc , stack , locals , c_stack_bytes, reason , label } = target {
1816
+ if let Target :: SideExit { context , reason , c_stack_bytes, label } = target {
1807
1817
asm_comment ! ( self , "Exit: {reason}" ) ;
1808
1818
let side_exit_label = if let Some ( label) = label {
1809
1819
Target :: Label ( label)
@@ -1823,26 +1833,30 @@ impl Assembler
1823
1833
}
1824
1834
}
1825
1835
1826
- asm_comment ! ( self , "write stack slots: {stack:?}" ) ;
1827
- for ( idx, & opnd) in stack. iter ( ) . enumerate ( ) {
1828
- let opnd = split_store_source ( self , opnd) ;
1829
- self . store ( Opnd :: mem ( 64 , SP , idx as i32 * SIZEOF_VALUE_I32 ) , opnd) ;
1830
- }
1836
+ // Restore the PC and the stack for regular side exits. We don't do this for
1837
+ // side exits right after JIT-to-JIT calls, which restore them before the call.
1838
+ if let Some ( SideExitContext { pc, stack, locals } ) = context {
1839
+ asm_comment ! ( self , "write stack slots: {stack:?}" ) ;
1840
+ for ( idx, & opnd) in stack. iter ( ) . enumerate ( ) {
1841
+ let opnd = split_store_source ( self , opnd) ;
1842
+ self . store ( Opnd :: mem ( 64 , SP , idx as i32 * SIZEOF_VALUE_I32 ) , opnd) ;
1843
+ }
1831
1844
1832
- asm_comment ! ( self , "write locals: {locals:?}" ) ;
1833
- for ( idx, & opnd) in locals. iter ( ) . enumerate ( ) {
1834
- let opnd = split_store_source ( self , opnd) ;
1835
- self . store ( Opnd :: mem ( 64 , SP , ( -local_size_and_idx_to_ep_offset ( locals. len ( ) , idx) - 1 ) * SIZEOF_VALUE_I32 ) , opnd) ;
1836
- }
1845
+ asm_comment ! ( self , "write locals: {locals:?}" ) ;
1846
+ for ( idx, & opnd) in locals. iter ( ) . enumerate ( ) {
1847
+ let opnd = split_store_source ( self , opnd) ;
1848
+ self . store ( Opnd :: mem ( 64 , SP , ( -local_size_and_idx_to_ep_offset ( locals. len ( ) , idx) - 1 ) * SIZEOF_VALUE_I32 ) , opnd) ;
1849
+ }
1837
1850
1838
- asm_comment ! ( self , "save cfp->pc" ) ;
1839
- self . load_into ( Opnd :: Reg ( Assembler :: SCRATCH_REG ) , Opnd :: const_ptr ( pc) ) ;
1840
- self . store ( Opnd :: mem ( 64 , CFP , RUBY_OFFSET_CFP_PC ) , Opnd :: Reg ( Assembler :: SCRATCH_REG ) ) ;
1851
+ asm_comment ! ( self , "save cfp->pc" ) ;
1852
+ self . load_into ( Opnd :: Reg ( Assembler :: SCRATCH_REG ) , Opnd :: const_ptr ( pc) ) ;
1853
+ self . store ( Opnd :: mem ( 64 , CFP , RUBY_OFFSET_CFP_PC ) , Opnd :: Reg ( Assembler :: SCRATCH_REG ) ) ;
1841
1854
1842
- asm_comment ! ( self , "save cfp->sp" ) ;
1843
- self . lea_into ( Opnd :: Reg ( Assembler :: SCRATCH_REG ) , Opnd :: mem ( 64 , SP , stack. len ( ) as i32 * SIZEOF_VALUE_I32 ) ) ;
1844
- let cfp_sp = Opnd :: mem ( 64 , CFP , RUBY_OFFSET_CFP_SP ) ;
1845
- self . store ( cfp_sp, Opnd :: Reg ( Assembler :: SCRATCH_REG ) ) ;
1855
+ asm_comment ! ( self , "save cfp->sp" ) ;
1856
+ self . lea_into ( Opnd :: Reg ( Assembler :: SCRATCH_REG ) , Opnd :: mem ( 64 , SP , stack. len ( ) as i32 * SIZEOF_VALUE_I32 ) ) ;
1857
+ let cfp_sp = Opnd :: mem ( 64 , CFP , RUBY_OFFSET_CFP_SP ) ;
1858
+ self . store ( cfp_sp, Opnd :: Reg ( Assembler :: SCRATCH_REG ) ) ;
1859
+ }
1846
1860
1847
1861
if c_stack_bytes > 0 {
1848
1862
asm_comment ! ( self , "restore C stack pointer" ) ;
0 commit comments