@@ -1028,10 +1028,11 @@ impl Function {
1028
1028
fun : & mut Function ,
1029
1029
block : BlockId ,
1030
1030
payload : & profile:: IseqPayload ,
1031
+ self_type : Type ,
1031
1032
send : Insn ,
1032
1033
send_insn_id : InsnId ,
1033
1034
) -> Result < ( ) , ( ) > {
1034
- let Insn :: SendWithoutBlock { self_val, cd, mut args, state, .. } = send else {
1035
+ let Insn :: SendWithoutBlock { mut self_val, cd, mut args, state, .. } = send else {
1035
1036
return Err ( ( ) ) ;
1036
1037
} ;
1037
1038
@@ -1045,13 +1046,14 @@ impl Function {
1045
1046
// TODO(alan): there was a seemingly a miscomp here if you swap with
1046
1047
// `inexact_ruby_class`. Theoretically it can call a method too general
1047
1048
// for the receiver. Confirm and add a test.
1048
- //
1049
- // TODO(max): Use runtime_exact_ruby_class so we can also specialize on known (not just
1050
- // profiled) types.
1051
- let ( recv_class , recv_type ) = payload. get_operand_types ( iseq_insn_idx)
1049
+ let ( recv_class , guard_type ) = if let Some ( klass ) = self_type . runtime_exact_ruby_class ( ) {
1050
+ ( klass , None )
1051
+ } else {
1052
+ payload. get_operand_types ( iseq_insn_idx)
1052
1053
. and_then ( |types| types. get ( argc as usize ) )
1053
- . and_then ( |recv_type| recv_type. exact_ruby_class ( ) . and_then ( |class| Some ( ( class, recv_type) ) ) )
1054
- . ok_or ( ( ) ) ?;
1054
+ . and_then ( |recv_type| recv_type. exact_ruby_class ( ) . and_then ( |class| Some ( ( class, Some ( recv_type. unspecialized ( ) ) ) ) ) )
1055
+ . ok_or ( ( ) ) ?
1056
+ } ;
1055
1057
1056
1058
// Do method lookup
1057
1059
let method = unsafe { rb_callable_method_entry ( recv_class, method_id) } ;
@@ -1090,8 +1092,10 @@ impl Function {
1090
1092
if ci_flags & VM_CALL_ARGS_SIMPLE != 0 {
1091
1093
// Commit to the replacement. Put PatchPoint.
1092
1094
fun. push_insn ( block, Insn :: PatchPoint ( Invariant :: MethodRedefined { klass : recv_class, method : method_id } ) ) ;
1093
- // Guard receiver class
1094
- let self_val = fun. push_insn ( block, Insn :: GuardType { val : self_val, guard_type : recv_type. unspecialized ( ) , state } ) ;
1095
+ if let Some ( guard_type) = guard_type {
1096
+ // Guard receiver class
1097
+ self_val = fun. push_insn ( block, Insn :: GuardType { val : self_val, guard_type, state } ) ;
1098
+ }
1095
1099
let cfun = unsafe { get_mct_func ( cfunc) } . cast ( ) ;
1096
1100
let mut cfunc_args = vec ! [ self_val] ;
1097
1101
cfunc_args. append ( & mut args) ;
@@ -1119,8 +1123,9 @@ impl Function {
1119
1123
let old_insns = std:: mem:: take ( & mut self . blocks [ block. 0 ] . insns ) ;
1120
1124
assert ! ( self . blocks[ block. 0 ] . insns. is_empty( ) ) ;
1121
1125
for insn_id in old_insns {
1122
- if let send @ Insn :: SendWithoutBlock { .. } = self . find ( insn_id) {
1123
- if reduce_to_ccall ( self , block, payload, send, insn_id) . is_ok ( ) {
1126
+ if let send @ Insn :: SendWithoutBlock { self_val, .. } = self . find ( insn_id) {
1127
+ let self_type = self . type_of ( self_val) ;
1128
+ if reduce_to_ccall ( self , block, payload, self_type, send, insn_id) . is_ok ( ) {
1124
1129
continue ;
1125
1130
}
1126
1131
}
@@ -3330,7 +3335,7 @@ mod opt_tests {
3330
3335
}
3331
3336
3332
3337
#[ test]
3333
- fn kernel_itself_simple ( ) {
3338
+ fn kernel_itself_const ( ) {
3334
3339
eval ( "
3335
3340
def test(x) = x.itself
3336
3341
test(0) # profile
@@ -3346,6 +3351,21 @@ mod opt_tests {
3346
3351
"# ] ] ) ;
3347
3352
}
3348
3353
3354
+ #[ test]
3355
+ fn kernel_itself_known_type ( ) {
3356
+ eval ( "
3357
+ def test(x) = [].itself
3358
+ " ) ;
3359
+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3360
+ fn test:
3361
+ bb0(v0:BasicObject):
3362
+ v3:ArrayExact = NewArray
3363
+ PatchPoint MethodRedefined(Array@0x1000, itself@0x1008)
3364
+ v8:BasicObject = CCall itself@0x1010, v3
3365
+ Return v8
3366
+ "# ] ] ) ;
3367
+ }
3368
+
3349
3369
#[ test]
3350
3370
fn kernel_itself_argc_mismatch ( ) {
3351
3371
eval ( "
@@ -3412,8 +3432,8 @@ mod opt_tests {
3412
3432
v1:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
3413
3433
v2:StringExact = StringCopy v1
3414
3434
PatchPoint MethodRedefined(String@0x1008, bytesize@0x1010)
3415
- v8 :Fixnum = CCall bytesize@0x1018, v2
3416
- Return v8
3435
+ v7 :Fixnum = CCall bytesize@0x1018, v2
3436
+ Return v7
3417
3437
"# ] ] ) ;
3418
3438
}
3419
3439
}
0 commit comments