@@ -457,6 +457,7 @@ impl PtrPrintMap {
457457#[ derive( Debug , Clone , Copy ) ]
458458pub enum SideExitReason {
459459 UnknownNewarraySend ( vm_opt_newarray_send_type ) ,
460+ UnknownDuparraySend ( u64 ) ,
460461 UnknownSpecialVariable ( u64 ) ,
461462 UnhandledHIRInsn ( InsnId ) ,
462463 UnhandledYARVInsn ( u32 ) ,
@@ -548,6 +549,7 @@ impl std::fmt::Display for SideExitReason {
548549 SideExitReason :: UnknownNewarraySend ( VM_OPT_NEWARRAY_SEND_PACK ) => write ! ( f, "UnknownNewarraySend(PACK)" ) ,
549550 SideExitReason :: UnknownNewarraySend ( VM_OPT_NEWARRAY_SEND_PACK_BUFFER ) => write ! ( f, "UnknownNewarraySend(PACK_BUFFER)" ) ,
550551 SideExitReason :: UnknownNewarraySend ( VM_OPT_NEWARRAY_SEND_INCLUDE_P ) => write ! ( f, "UnknownNewarraySend(INCLUDE_P)" ) ,
552+ SideExitReason :: UnknownDuparraySend ( method_id) => write ! ( f, "UnknownDuparraySend({})" , method_id) ,
551553 SideExitReason :: GuardType ( guard_type) => write ! ( f, "GuardType({guard_type})" ) ,
552554 SideExitReason :: GuardTypeNot ( guard_type) => write ! ( f, "GuardTypeNot({guard_type})" ) ,
553555 SideExitReason :: GuardBitEquals ( value) => write ! ( f, "GuardBitEquals({})" , value. print( & PtrPrintMap :: identity( ) ) ) ,
@@ -616,6 +618,8 @@ pub enum Insn {
616618 NewRangeFixnum { low : InsnId , high : InsnId , flag : RangeType , state : InsnId } ,
617619 ArrayDup { val : InsnId , state : InsnId } ,
618620 ArrayMax { elements : Vec < InsnId > , state : InsnId } ,
621+ ArrayInclude { elements : Vec < InsnId > , target : InsnId , state : InsnId } ,
622+ DupArrayInclude { ary : VALUE , target : InsnId , state : InsnId } ,
619623 /// Extend `left` with the elements from `right`. `left` and `right` must both be `Array`.
620624 ArrayExtend { left : InsnId , right : InsnId , state : InsnId } ,
621625 /// Push `val` onto `array`, where `array` is already `Array`.
@@ -988,6 +992,18 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
988992 }
989993 Ok ( ( ) )
990994 }
995+ Insn :: ArrayInclude { elements, target, .. } => {
996+ write ! ( f, "ArrayInclude" ) ?;
997+ let mut prefix = " " ;
998+ for element in elements {
999+ write ! ( f, "{prefix}{element}" ) ?;
1000+ prefix = ", " ;
1001+ }
1002+ write ! ( f, " | {target}" )
1003+ }
1004+ Insn :: DupArrayInclude { ary, target, .. } => {
1005+ write ! ( f, "DupArrayInclude {} | {}" , ary. print( self . ptr_map) , target)
1006+ }
9911007 Insn :: ArrayDup { val, .. } => { write ! ( f, "ArrayDup {val}" ) }
9921008 Insn :: HashDup { val, .. } => { write ! ( f, "HashDup {val}" ) }
9931009 Insn :: HashAref { hash, key, .. } => { write ! ( f, "HashAref {hash}, {key}" ) }
@@ -1789,6 +1805,8 @@ impl Function {
17891805 & ArrayPop { array, state } => ArrayPop { array : find ! ( array) , state : find ! ( state) } ,
17901806 & ArrayLength { array } => ArrayLength { array : find ! ( array) } ,
17911807 & ArrayMax { ref elements, state } => ArrayMax { elements : find_vec ! ( elements) , state : find ! ( state) } ,
1808+ & ArrayInclude { ref elements, target, state } => ArrayInclude { elements : find_vec ! ( elements) , target : find ! ( target) , state : find ! ( state) } ,
1809+ & DupArrayInclude { ary, target, state } => DupArrayInclude { ary, target : find ! ( target) , state : find ! ( state) } ,
17921810 & SetGlobal { id, val, state } => SetGlobal { id, val : find ! ( val) , state } ,
17931811 & GetIvar { self_val, id, state } => GetIvar { self_val : find ! ( self_val) , id, state } ,
17941812 & LoadField { recv, id, offset, return_type } => LoadField { recv : find ! ( recv) , id, offset, return_type } ,
@@ -1923,6 +1941,8 @@ impl Function {
19231941 Insn :: GetConstantPath { .. } => types:: BasicObject ,
19241942 Insn :: IsBlockGiven => types:: BoolExact ,
19251943 Insn :: ArrayMax { .. } => types:: BasicObject ,
1944+ Insn :: ArrayInclude { .. } => types:: BoolExact ,
1945+ Insn :: DupArrayInclude { .. } => types:: BoolExact ,
19261946 Insn :: GetGlobal { .. } => types:: BasicObject ,
19271947 Insn :: GetIvar { .. } => types:: BasicObject ,
19281948 Insn :: LoadPC => types:: CPtr ,
@@ -3211,6 +3231,15 @@ impl Function {
32113231 worklist. extend ( elements) ;
32123232 worklist. push_back ( state) ;
32133233 }
3234+ & Insn :: ArrayInclude { ref elements, target, state } => {
3235+ worklist. extend ( elements) ;
3236+ worklist. push_back ( target) ;
3237+ worklist. push_back ( state) ;
3238+ }
3239+ & Insn :: DupArrayInclude { target, state, .. } => {
3240+ worklist. push_back ( target) ;
3241+ worklist. push_back ( state) ;
3242+ }
32143243 & Insn :: NewRange { low, high, state, .. }
32153244 | & Insn :: NewRangeFixnum { low, high, state, .. } => {
32163245 worklist. push_back ( low) ;
@@ -4448,6 +4477,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
44484477 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
44494478 let ( bop, insn) = match method {
44504479 VM_OPT_NEWARRAY_SEND_MAX => ( BOP_MAX , Insn :: ArrayMax { elements, state : exit_id } ) ,
4480+ VM_OPT_NEWARRAY_SEND_INCLUDE_P => {
4481+ let target = elements[ elements. len ( ) - 1 ] ;
4482+ let array_elements = elements[ ..elements. len ( ) - 1 ] . to_vec ( ) ;
4483+ ( BOP_INCLUDE_P , Insn :: ArrayInclude { elements : array_elements, target, state : exit_id } )
4484+ } ,
44514485 _ => {
44524486 // Unknown opcode; side-exit into the interpreter
44534487 fun. push_insn ( block, Insn :: SideExit { state : exit_id, reason : SideExitReason :: UnknownNewarraySend ( method) } ) ;
@@ -4468,6 +4502,30 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
44684502 let insn_id = fun. push_insn ( block, Insn :: ArrayDup { val, state : exit_id } ) ;
44694503 state. stack_push ( insn_id) ;
44704504 }
4505+ YARVINSN_opt_duparray_send => {
4506+ let ary = get_arg ( pc, 0 ) ;
4507+ let method_id = get_arg ( pc, 1 ) . as_u64 ( ) ;
4508+ let argc = get_arg ( pc, 2 ) . as_usize ( ) ;
4509+ if argc != 1 {
4510+ break ;
4511+ }
4512+ let target = state. stack_pop ( ) ?;
4513+ let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
4514+ let bop = match method_id {
4515+ x if x == ID ! ( include_p) . 0 => BOP_INCLUDE_P ,
4516+ _ => {
4517+ fun. push_insn ( block, Insn :: SideExit { state : exit_id, reason : SideExitReason :: UnknownDuparraySend ( method_id) } ) ;
4518+ break ;
4519+ } ,
4520+ } ;
4521+ if !unsafe { rb_BASIC_OP_UNREDEFINED_P ( bop, ARRAY_REDEFINED_OP_FLAG ) } {
4522+ fun. push_insn ( block, Insn :: SideExit { state : exit_id, reason : SideExitReason :: PatchPoint ( Invariant :: BOPRedefined { klass : ARRAY_REDEFINED_OP_FLAG , bop } ) } ) ;
4523+ break ;
4524+ }
4525+ fun. push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: BOPRedefined { klass : ARRAY_REDEFINED_OP_FLAG , bop } , state : exit_id } ) ;
4526+ let insn_id = fun. push_insn ( block, Insn :: DupArrayInclude { ary, target, state : exit_id } ) ;
4527+ state. stack_push ( insn_id) ;
4528+ }
44714529 YARVINSN_newhash => {
44724530 let count = get_arg ( pc, 0 ) . as_usize ( ) ;
44734531 assert ! ( count % 2 == 0 , "newhash count should be even" ) ;
0 commit comments