From: Vincent Pit Date: Fri, 6 Sep 2013 15:37:59 +0000 (+0200) Subject: Add support for padrange ops, introduced in perl 5.17.6 X-Git-Tag: v0.13~13 X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2FLexical-Types.git;a=commitdiff_plain;h=ac8fadd02eaa275485af784bc3a70fd2c666906c Add support for padrange ops, introduced in perl 5.17.6 This fixes RT #86112. --- diff --git a/Types.xs b/Types.xs index 69b92e2..6ead2eb 100644 --- a/Types.xs +++ b/Types.xs @@ -566,11 +566,58 @@ STATIC const lt_op_padxv_info *lt_padxv_map_fetch(const OP *o, lt_op_padxv_info return val; } +#if LT_HAS_PERL(5, 17, 6) + +STATIC ptable *lt_op_padrange_map = NULL; + +typedef struct { + OP *(*old_pp)(pTHX); + const OP *padxv_start; +} lt_op_padrange_info; + +STATIC void lt_padrange_map_store(pTHX_ const OP *o, const OP *s, OP *(*old_pp)(pTHX)) { +#define lt_padrange_map_store(O, S, PP) lt_padrange_map_store(aTHX_ (O), (S), (PP)) + lt_op_padrange_info *oi; + + LT_LOCK(<_op_map_mutex); + + if (!(oi = ptable_fetch(lt_op_padrange_map, o))) { + oi = PerlMemShared_malloc(sizeof *oi); + ptable_map_store(lt_op_padrange_map, o, oi); + } + + oi->old_pp = old_pp; + oi->padxv_start = s; + + LT_UNLOCK(<_op_map_mutex); +} + +STATIC const lt_op_padrange_info *lt_padrange_map_fetch(const OP *o, lt_op_padrange_info *oi) { + const lt_op_padrange_info *val; + + LT_LOCK(<_op_map_mutex); + + val = ptable_fetch(lt_op_padrange_map, o); + if (val) { + *oi = *val; + val = oi; + } + + LT_UNLOCK(<_op_map_mutex); + + return val; +} + +#endif + STATIC void lt_map_delete(pTHX_ const OP *o) { #define lt_map_delete(O) lt_map_delete(aTHX_ (O)) LT_LOCK(<_op_map_mutex); ptable_map_delete(lt_op_padxv_map, o); +#if LT_HAS_PERL(5, 17, 6) + ptable_map_delete(lt_op_padrange_map, o); +#endif LT_UNLOCK(<_op_map_mutex); } @@ -591,6 +638,34 @@ STATIC OP *lt_pp_padsv(pTHX) { return PL_op->op_ppaddr(aTHX); } +/* ... Our pp_padrange (on perl 5.17.6 and above) .......................... */ + +#if LT_HAS_PERL(5, 17, 6) + +STATIC OP *lt_pp_padrange(pTHX) { + lt_op_padrange_info roi; + + if (lt_padrange_map_fetch(PL_op, &roi)) { + PADOFFSET i, base, count; + const OP *p; + + base = PL_op->op_targ; + count = PL_op->op_private & OPpPADRANGE_COUNTMASK; + + for (i = 0, p = roi.padxv_start; i < count && p; ++i, p = p->op_sibling) { + lt_op_padxv_info oi; + if (p->op_type == OP_PADSV && lt_padxv_map_fetch(p, &oi)) + lt_op_padxv_info_call(&oi, PAD_SV(base + i)); + } + + return roi.old_pp(aTHX); + } + + return PL_op->op_ppaddr(aTHX); +} + +#endif + /* ... Our ck_pad{any,sv} .................................................. */ /* Sadly, the padsv OPs we are interested in don't trigger the padsv check @@ -687,6 +762,37 @@ STATIC OP *lt_ck_padsv(pTHX_ OP *o) { /* ... Our peephole optimizer .............................................. */ +#if LT_HAS_PERL(5, 17, 6) + +STATIC int lt_maybe_padrange_setup(pTHX_ OP *o, const OP *start) { +#define lt_maybe_padrange_setup(O, S) lt_maybe_padrange_setup(aTHX_ (O), (S)) + PADOFFSET i, count; + const OP *p; + + count = o->op_private & OPpPADRANGE_COUNTMASK; + + for (i = 0, p = start; i < count && p; ++i, p = p->op_sibling) { + if (p->op_type == OP_PADSV) { + /* In a padrange sequence, either all lexicals are typed, or none are. + * Thus we can stop at the first padsv op. However, note that these + * lexicals can need to call different methods in different packages. */ + LT_LOCK(<_op_map_mutex); + if (ptable_fetch(lt_op_padxv_map, p)) { + LT_UNLOCK(<_op_map_mutex); + lt_padrange_map_store(o, start, o->op_ppaddr); + o->op_ppaddr = lt_pp_padrange; + } else { + LT_UNLOCK(<_op_map_mutex); + } + return 1; + } + } + + return 0; +} + +#endif + STATIC peep_t lt_old_peep = 0; /* This is actually the rpeep past 5.13.5 */ STATIC void lt_peep_rec(pTHX_ OP *o, ptable *seen) { @@ -709,6 +815,34 @@ STATIC void lt_peep_rec(pTHX_ OP *o, ptable *seen) { LT_UNLOCK(<_op_map_mutex); } break; +#if LT_HAS_PERL(5, 17, 6) + case OP_PADRANGE: + /* We deal with special padrange ops later, in the aassign op they belong + * to. */ + if (o->op_ppaddr != lt_pp_padrange && o->op_private & OPpLVAL_INTRO + && !(o->op_flags & OPf_SPECIAL)) { + /* A padrange op is guaranteed to have previously been a pushmark. + * Moreover, for non-special padrange ops (i.e. that aren't for + * my (...) = @_), the original padxv ops are its siblings. */ + lt_maybe_padrange_setup(o, o->op_sibling); + } + break; + case OP_AASSIGN: { + OP *op; + if (cBINOPo->op_first && cBINOPo->op_first->op_flags & OPf_KIDS + && (op = cUNOPx(cBINOPo->op_first)->op_first) + && op->op_type == OP_PADRANGE + && op->op_ppaddr != lt_pp_padrange + && op->op_private & OPpLVAL_INTRO + && op->op_flags & OPf_SPECIAL) { + const OP *start = cUNOPx(cBINOPo->op_last)->op_first; + if (start->op_type == OP_PUSHMARK) + start = start->op_sibling; + lt_maybe_padrange_setup(op, start); + } + break; + } +#endif #if !LT_HAS_RPEEP case OP_MAPWHILE: case OP_GREPWHILE: @@ -846,6 +980,9 @@ BOOT: HV *stash; lt_op_padxv_map = ptable_new(); +#if LT_HAS_PERL(5, 17, 6) + lt_op_padrange_map = ptable_new(); +#endif #ifdef USE_ITHREADS MUTEX_INIT(<_op_map_mutex); #endif