@@ -529,6 +529,7 @@ pub enum Insn {
529529 // Distinct from `SendWithoutBlock` with `mid:to_s` because does not have a patch point for String to_s being redefined
530530 ObjToString { val : InsnId , call_info : CallInfo , cd : * const rb_call_data , state : InsnId } ,
531531 AnyToString { val : InsnId , str : InsnId , state : InsnId } ,
532+ ConcatStrings { strings : Vec < InsnId > , state : InsnId } ,
532533
533534 /// Side-exit if val doesn't have the expected type.
534535 GuardType { val : InsnId , guard_type : Type , state : InsnId } ,
@@ -705,7 +706,14 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
705706 write ! ( f, ", {arg}" ) ?;
706707 }
707708 Ok ( ( ) )
708- } ,
709+ }
710+ Insn :: ConcatStrings { strings, state : _ } => {
711+ write ! ( f, "ConcatStrings {}" , strings[ 0 ] ) ?;
712+ for string in strings. iter ( ) . skip ( 1 ) {
713+ write ! ( f, ", {string}" ) ?;
714+ }
715+ Ok ( ( ) )
716+ }
709717 Insn :: Snapshot { state } => write ! ( f, "Snapshot {}" , state) ,
710718 Insn :: Defined { op_type, v, .. } => {
711719 // op_type (enum defined_type) printing logic from iseq.c.
@@ -1088,6 +1096,7 @@ impl Function {
10881096 str : find ! ( * str ) ,
10891097 state : * state,
10901098 } ,
1099+ ConcatStrings { state, strings } => ConcatStrings { state : * state, strings : find_vec ! ( strings) } ,
10911100 SendWithoutBlock { self_val, call_info, cd, args, state } => SendWithoutBlock {
10921101 self_val : find ! ( * self_val) ,
10931102 call_info : call_info. clone ( ) ,
@@ -1219,6 +1228,7 @@ impl Function {
12191228 Insn :: ToArray { .. } => types:: ArrayExact ,
12201229 Insn :: ObjToString { .. } => types:: BasicObject ,
12211230 Insn :: AnyToString { .. } => types:: String ,
1231+ Insn :: ConcatStrings { .. } => types:: StringExact ,
12221232 Insn :: GetLocal { .. } => types:: BasicObject ,
12231233 }
12241234 }
@@ -1778,7 +1788,8 @@ impl Function {
17781788 worklist. push_back ( state) ;
17791789 }
17801790 Insn :: ArrayMax { elements, state }
1781- | Insn :: NewArray { elements, state } => {
1791+ | Insn :: NewArray { elements, state }
1792+ | Insn :: ConcatStrings { strings : elements, state } => {
17821793 worklist. extend ( elements) ;
17831794 worklist. push_back ( state) ;
17841795 }
@@ -2939,6 +2950,16 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
29392950 let anytostring = fun. push_insn ( block, Insn :: AnyToString { val, str, state : exit_id } ) ;
29402951 state. stack_push ( anytostring) ;
29412952 }
2953+ YARVINSN_concatstrings => {
2954+ let num = get_arg ( pc, 0 ) . as_u32 ( ) ;
2955+ let mut strings = Vec :: with_capacity ( num. as_usize ( ) ) ;
2956+ for _ in 0 ..num {
2957+ strings. push ( state. stack_pop ( ) ?) ;
2958+ }
2959+ strings. reverse ( ) ;
2960+ let snapshot = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
2961+ state. stack_push ( fun. push_insn ( block, Insn :: ConcatStrings { state : snapshot, strings } ) ) ;
2962+ }
29422963 _ => {
29432964 // Unknown opcode; side-exit into the interpreter
29442965 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
@@ -4664,7 +4685,8 @@ mod tests {
46644685 v3:Fixnum[1] = Const Value(1)
46654686 v5:BasicObject = ObjToString v3
46664687 v7:String = AnyToString v3, str: v5
4667- SideExit UnknownOpcode(concatstrings)
4688+ v9:StringExact = ConcatStrings v2, v7
4689+ Return v9
46684690 "# ] ] ) ;
46694691 }
46704692
@@ -6305,7 +6327,8 @@ mod opt_tests {
63056327 v2:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
63066328 v3:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
63076329 v4:StringExact = StringCopy v3
6308- SideExit UnknownOpcode(concatstrings)
6330+ v10:StringExact = ConcatStrings v2, v4
6331+ Return v10
63096332 "# ] ] ) ;
63106333 }
63116334
@@ -6319,9 +6342,10 @@ mod opt_tests {
63196342 bb0(v0:BasicObject):
63206343 v2:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
63216344 v3:Fixnum[1] = Const Value(1)
6322- v10:BasicObject = SendWithoutBlock v3, :to_s
6323- v7:String = AnyToString v3, str: v10
6324- SideExit UnknownOpcode(concatstrings)
6345+ v11:BasicObject = SendWithoutBlock v3, :to_s
6346+ v7:String = AnyToString v3, str: v11
6347+ v9:StringExact = ConcatStrings v2, v7
6348+ Return v9
63256349 "# ] ] ) ;
63266350 }
63276351
0 commit comments