@@ -113,6 +113,13 @@ pub enum Invariant {
113
113
/// The method ID of the method we want to assume unchanged
114
114
method : ID ,
115
115
} ,
116
+ /// A list of constant expression path segments that must have not been written to for the
117
+ /// following code to be valid.
118
+ StableConstantNames {
119
+ idlist : * const ID ,
120
+ } ,
121
+ /// There is one ractor running. If a non-root ractor gets spawned, this is invalidated.
122
+ SingleRactorMode ,
116
123
}
117
124
118
125
impl Invariant {
@@ -161,6 +168,22 @@ impl<'a> std::fmt::Display for InvariantPrinter<'a> {
161
168
self . ptr_map. map_id( method. 0 )
162
169
)
163
170
}
171
+ Invariant :: StableConstantNames { idlist } => {
172
+ write ! ( f, "StableConstantNames({:p}, " , self . ptr_map. map_ptr( idlist) ) ?;
173
+ let mut idx = 0 ;
174
+ let mut sep = "" ;
175
+ loop {
176
+ let id = unsafe { * idlist. wrapping_add ( idx) } ;
177
+ if id. 0 == 0 {
178
+ break ;
179
+ }
180
+ write ! ( f, "{sep}{}" , id. contents_lossy( ) ) ?;
181
+ sep = "::" ;
182
+ idx += 1 ;
183
+ }
184
+ write ! ( f, ")" )
185
+ }
186
+ Invariant :: SingleRactorMode => write ! ( f, "SingleRactorMode" ) ,
164
187
}
165
188
}
166
189
}
@@ -292,7 +315,7 @@ pub enum Insn {
292
315
// with IfTrue/IfFalse in the backend to generate jcc.
293
316
Test { val : InsnId } ,
294
317
Defined { op_type : usize , obj : VALUE , pushval : VALUE , v : InsnId } ,
295
- GetConstantPath { ic : * const u8 } ,
318
+ GetConstantPath { ic : * const iseq_inline_constant_cache } ,
296
319
297
320
//NewObject?
298
321
//SetIvar {},
@@ -1013,6 +1036,25 @@ impl Function {
1013
1036
let send_direct = self . push_insn ( block, Insn :: SendWithoutBlockDirect { self_val, call_info, cd, iseq, args, state } ) ;
1014
1037
self . make_equal_to ( insn_id, send_direct) ;
1015
1038
}
1039
+ Insn :: GetConstantPath { ic } => {
1040
+ let idlist: * const ID = unsafe { ( * ic) . segments } ;
1041
+ let ice = unsafe { ( * ic) . entry } ;
A3D4
div>
1042
+ if ice. is_null ( ) {
1043
+ self . push_insn_id ( block, insn_id) ; continue ;
1044
+ }
1045
+ let cref_sensitive = !unsafe { ( * ice) . ic_cref } . is_null ( ) ;
1046
+ let multi_ractor_mode = unsafe { rb_zjit_multi_ractor_p ( ) } ;
1047
+ if cref_sensitive || multi_ractor_mode {
1048
+ self . push_insn_id ( block, insn_id) ; continue ;
1049
+ }
1050
+ // Assume single-ractor mode.
1051
+ self . push_insn ( block, Insn :: PatchPoint ( Invariant :: SingleRactorMode ) ) ;
1052
+ // Invalidate output code on any constant writes associated with constants
1053
+ // referenced after the PatchPoint.
1054
+ self . push_insn ( block, Insn :: PatchPoint ( Invariant :: StableConstantNames { idlist } ) ) ;
1055
+ let replacement = self . push_insn ( block, Insn :: Const { val : Const :: Value ( unsafe { ( * ice) . value } ) } ) ;
1056
+ self . make_equal_to ( insn_id, replacement) ;
1057
+ }
1016
1058
_ => { self . push_insn_id ( block, insn_id) ; }
1017
1059
}
1018
1060
}
@@ -1714,7 +1756,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
1714
1756
state. stack_push ( fun. push_insn ( block, Insn :: Defined { op_type, obj, pushval, v } ) ) ;
1715
1757
}
1716
1758
YARVINSN_opt_getconstant_path => {
1717
- let ic = get_arg ( pc, 0 ) . as_ptr :: < u8 > ( ) ;
1759
+ let ic = get_arg ( pc, 0 ) . as_ptr ( ) ;
1718
1760
state. stack_push ( fun. push_insn ( block, Insn :: GetConstantPath { ic } ) ) ;
1719
1761
}
1720
1762
YARVINSN_branchunless => {
@@ -3565,4 +3607,70 @@ mod opt_tests {
3565
3607
Return v7
3566
3608
"# ] ] ) ;
3567
3609
}
3610
+
3611
+ #[ test]
3612
+ fn dont_replace_get_constant_path_with_empty_ic ( ) {
3613
+ eval ( "
3614
+ def test = Kernel
3615
+ " ) ;
3616
+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3617
+ fn test:
3618
+ bb0():
3619
+ v1:BasicObject = GetConstantPath 0x1000
3620
+ Return v1
3621
+ "# ] ] ) ;
3622
+ }
3623
+
3624
+ #[ test]
3625
+ fn dont_replace_get_constant_path_with_invalidated_ic ( ) {
3626
+ eval ( "
3627
+ def test = Kernel
3628
+ test
3629
+ Kernel = 5
3630
+ " ) ;
3631
+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3632
+ fn test:
3633
+ bb0():
3634
+ v1:BasicObject = GetConstantPath 0x1000
3635
+ Return v1
3636
+ "# ] ] ) ;
3637
+ }
3638
+
3639
+ #[ test]
3640
+ fn replace_get_constant_path_with_const ( ) {
3641
+ eval ( "
3642
+ def test = Kernel
3643
+ test
3644
+ " ) ;
3645
+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3646
+ fn test:
3647
+ bb0():
3648
+ PatchPoint SingleRactorMode
3649
+ PatchPoint StableConstantNames(0x1000, Kernel)
3650
+ v5:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
3651
+ Return v5
3652
+ "# ] ] ) ;
3653
+ }
3654
+
3655
+ #[ test]
3656
+ fn replace_nested_get_constant_path_with_const ( ) {
3657
+ eval ( "
3658
+ module Foo
3659
+ module Bar
3660
+ class C
3661
+ end
3662
+ end
3663
+ end
3664
+ def test = Foo::Bar::C
3665
+ test
3666
+ " ) ;
3667
+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3668
+ fn test:
3669
+ bb0():
3670
+ PatchPoint SingleRactorMode
3671
+ PatchPoint StableConstantNames(0x1000, Foo::Bar::C)
3672
+ v5:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
3673
+ Return v5
3674
+ "# ] ] ) ;
3675
+ }
3568
3676
}
0 commit comments