]> git.vpit.fr Git - perl/modules/Lexical-Types.git/commitdiff
Add support for padrange ops, introduced in perl 5.17.6
authorVincent Pit <vince@profvince.com>
Fri, 6 Sep 2013 15:37:59 +0000 (17:37 +0200)
committerVincent Pit <vince@profvince.com>
Fri, 6 Sep 2013 15:37:59 +0000 (17:37 +0200)
This fixes RT #86112.

Types.xs

index 69b92e20137ff84771019adbdb5b862ca676e6fd..6ead2eb61321356b7f6336749e2def7bd224945b 100644 (file)
--- 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(&lt_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(&lt_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(&lt_op_map_mutex);
+
+ val = ptable_fetch(lt_op_padrange_map, o);
+ if (val) {
+  *oi = *val;
+  val = oi;
+ }
+
+ LT_UNLOCK(&lt_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(&lt_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(&lt_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(&lt_op_map_mutex);
+   if (ptable_fetch(lt_op_padxv_map, p)) {
+    LT_UNLOCK(&lt_op_map_mutex);
+    lt_padrange_map_store(o, start, o->op_ppaddr);
+    o->op_ppaddr = lt_pp_padrange;
+   } else {
+    LT_UNLOCK(&lt_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(&lt_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(&lt_op_map_mutex);
 #endif