Fix assertion failure on failed magic eval - eg FETCH {eval'('}
[p5sagit/p5-mst-13.2.git] / op.c
diff --git a/op.c b/op.c
index 6c9b53f..d0c1c8b 100644 (file)
--- a/op.c
+++ b/op.c
@@ -1,7 +1,7 @@
 /*    op.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -73,6 +73,28 @@ into peep() to do that code's portion of the 3rd pass.  It has to be
 recursive, but it's recursive on basic blocks, not on tree nodes.
 */
 
+/* To implement user lexical pragmas, there needs to be a way at run time to
+   get the compile time state of %^H for that block.  Storing %^H in every
+   block (or even COP) would be very expensive, so a different approach is
+   taken.  The (running) state of %^H is serialised into a tree of HE-like
+   structs.  Stores into %^H are chained onto the current leaf as a struct
+   refcounted_he * with the key and the value.  Deletes from %^H are saved
+   with a value of PL_sv_placeholder.  The state of %^H at any point can be
+   turned back into a regular HV by walking back up the tree from that point's
+   leaf, ignoring any key you've already seen (placeholder or not), storing
+   the rest into the HV structure, then removing the placeholders. Hence
+   memory is only used to store the %^H deltas from the enclosing COP, rather
+   than the entire %^H on each COP.
+
+   To cause actions on %^H to write out the serialisation records, it has
+   magic type 'H'. This magic (itself) does nothing, but its presence causes
+   the values to gain magic type 'h', which has entries for set and clear.
+   C<Perl_magic_sethint> updates C<PL_compiling.cop_hints_hash> with a store
+   record, with deletes written by C<Perl_magic_clearhint>. C<SAVE_HINTS>
+   saves the current C<PL_compiling.cop_hints_hash> on the save stack, so that
+   it will be correctly restored when any inner compiling scope is exited.
+*/
+
 #include "EXTERN.h"
 #define PERL_IN_OP_C
 #include "perl.h"
@@ -82,12 +104,17 @@ recursive, but it's recursive on basic blocks, not on tree nodes.
 
 #if defined(PL_OP_SLAB_ALLOC)
 
+#ifdef PERL_DEBUG_READONLY_OPS
+#  define PERL_SLAB_SIZE 4096
+#  include <sys/mman.h>
+#endif
+
 #ifndef PERL_SLAB_SIZE
 #define PERL_SLAB_SIZE 2048
 #endif
 
 void *
-Perl_Slab_Alloc(pTHX_ int m, size_t sz)
+Perl_Slab_Alloc(pTHX_ size_t sz)
 {
     /*
      * To make incrementing use count easy PL_OpSlab is an I32 *
@@ -97,11 +124,26 @@ Perl_Slab_Alloc(pTHX_ int m, size_t sz)
      */
     sz = (sz + 2*sizeof(I32 *) -1)/sizeof(I32 *);
     if ((PL_OpSpace -= sz) < 0) {
-        PL_OpPtr = (I32 **) PerlMemShared_malloc(PERL_SLAB_SIZE*sizeof(I32*)); 
+#ifdef PERL_DEBUG_READONLY_OPS
+       /* We need to allocate chunk by chunk so that we can control the VM
+          mapping */
+       PL_OpPtr = mmap(0, PERL_SLAB_SIZE*sizeof(I32*), PROT_READ|PROT_WRITE,
+                       MAP_ANON|MAP_PRIVATE, -1, 0);
+
+       DEBUG_m(PerlIO_printf(Perl_debug_log, "mapped %lu at %p\n",
+                             (unsigned long) PERL_SLAB_SIZE*sizeof(I32*),
+                             PL_OpPtr));
+       if(PL_OpPtr == MAP_FAILED) {
+           perror("mmap failed");
+           abort();
+       }
+#else
+
+        PL_OpPtr = (I32 **) PerlMemShared_calloc(PERL_SLAB_SIZE,sizeof(I32*)); 
+#endif
        if (!PL_OpPtr) {
            return NULL;
        }
-       Zero(PL_OpPtr,PERL_SLAB_SIZE,I32 **);
        /* We reserve the 0'th I32 sized chunk as a use count */
        PL_OpSlab = (I32 *) PL_OpPtr;
        /* Reduce size by the use count word, and by the size we need.
@@ -113,6 +155,14 @@ Perl_Slab_Alloc(pTHX_ int m, size_t sz)
           means that at run time access is cache friendly upward
         */
        PL_OpPtr += PERL_SLAB_SIZE;
+
+#ifdef PERL_DEBUG_READONLY_OPS
+       /* We remember this slab.  */
+       /* This implementation isn't efficient, but it is simple. */
+       PL_slabs = realloc(PL_slabs, sizeof(I32**) * (PL_slab_count + 1));
+       PL_slabs[PL_slab_count++] = PL_OpSlab;
+       DEBUG_m(PerlIO_printf(Perl_debug_log, "Allocate %p\n", PL_OpSlab));
+#endif
     }
     assert( PL_OpSpace >= 0 );
     /* Move the allocation pointer down */
@@ -125,6 +175,70 @@ Perl_Slab_Alloc(pTHX_ int m, size_t sz)
     return (void *)(PL_OpPtr + 1);
 }
 
+#ifdef PERL_DEBUG_READONLY_OPS
+void
+Perl_pending_Slabs_to_ro(pTHX) {
+    /* Turn all the allocated op slabs read only.  */
+    U32 count = PL_slab_count;
+    I32 **const slabs = PL_slabs;
+
+    /* Reset the array of pending OP slabs, as we're about to turn this lot
+       read only. Also, do it ahead of the loop in case the warn triggers,
+       and a warn handler has an eval */
+
+    PL_slabs = NULL;
+    PL_slab_count = 0;
+
+    /* Force a new slab for any further allocation.  */
+    PL_OpSpace = 0;
+
+    while (count--) {
+       void *const start = slabs[count];
+       const size_t size = PERL_SLAB_SIZE* sizeof(I32*);
+       if(mprotect(start, size, PROT_READ)) {
+           Perl_warn(aTHX_ "mprotect for %p %lu failed with %d",
+                     start, (unsigned long) size, errno);
+       }
+    }
+
+    free(slabs);
+}
+
+STATIC void
+S_Slab_to_rw(pTHX_ void *op)
+{
+    I32 * const * const ptr = (I32 **) op;
+    I32 * const slab = ptr[-1];
+    assert( ptr-1 > (I32 **) slab );
+    assert( ptr < ( (I32 **) slab + PERL_SLAB_SIZE) );
+    assert( *slab > 0 );
+    if(mprotect(slab, PERL_SLAB_SIZE*sizeof(I32*), PROT_READ|PROT_WRITE)) {
+       Perl_warn(aTHX_ "mprotect RW for %p %lu failed with %d",
+                 slab, (unsigned long) PERL_SLAB_SIZE*sizeof(I32*), errno);
+    }
+}
+
+OP *
+Perl_op_refcnt_inc(pTHX_ OP *o)
+{
+    if(o) {
+       Slab_to_rw(o);
+       ++o->op_targ;
+    }
+    return o;
+
+}
+
+PADOFFSET
+Perl_op_refcnt_dec(pTHX_ OP *o)
+{
+    Slab_to_rw(o);
+    return --o->op_targ;
+}
+#else
+#  define Slab_to_rw(op)
+#endif
+
 void
 Perl_Slab_Free(pTHX_ void *op)
 {
@@ -133,12 +247,38 @@ Perl_Slab_Free(pTHX_ void *op)
     assert( ptr-1 > (I32 **) slab );
     assert( ptr < ( (I32 **) slab + PERL_SLAB_SIZE) );
     assert( *slab > 0 );
+    Slab_to_rw(op);
     if (--(*slab) == 0) {
 #  ifdef NETWARE
 #    define PerlMemShared PerlMem
 #  endif
        
+#ifdef PERL_DEBUG_READONLY_OPS
+       U32 count = PL_slab_count;
+       /* Need to remove this slab from our list of slabs */
+       if (count) {
+           while (count--) {
+               if (PL_slabs[count] == slab) {
+                   /* Found it. Move the entry at the end to overwrite it.  */
+                   DEBUG_m(PerlIO_printf(Perl_debug_log,
+                                         "Deallocate %p by moving %p from %lu to %lu\n",
+                                         PL_OpSlab,
+                                         PL_slabs[PL_slab_count - 1],
+                                         PL_slab_count, count));
+                   PL_slabs[count] = PL_slabs[--PL_slab_count];
+                   /* Could realloc smaller at this point, but probably not
+                      worth it.  */
+                   if(munmap(slab, PERL_SLAB_SIZE*sizeof(I32*))) {
+                       perror("munmap failed");
+                       abort();
+                   }
+                   break;
+               }
+           }
+       }
+#else
     PerlMemShared_free(slab);
+#endif
        if (slab == PL_OpSlab) {
            PL_OpSpace = 0;
        }
@@ -146,14 +286,14 @@ Perl_Slab_Free(pTHX_ void *op)
 }
 #endif
 /*
- * In the following definition, the ", Nullop" is just to make the compiler
+ * In the following definition, the ", (OP*)0" is just to make the compiler
  * think the expression is of the right type: croak actually does a Siglongjmp.
  */
 #define CHECKOP(type,o) \
-    ((PL_op_mask && PL_op_mask[type])                                  \
+    ((PL_op_mask && PL_op_mask[type])                          \
      ? ( op_free((OP*)o),                                      \
         Perl_croak(aTHX_ "'%s' trapped by operation mask", PL_op_desc[type]),  \
-        Nullop )                                               \
+        (OP*)0 )                                               \
      : CALL_FPTR(PL_check[type])(aTHX_ (OP*)o))
 
 #define RETURN_UNLIMITED_NUMBER (PERL_INT_MAX / 2)
@@ -198,19 +338,21 @@ S_bad_type(pTHX_ I32 n, const char *t, const char *name, const OP *kid)
 STATIC void
 S_no_bareword_allowed(pTHX_ const OP *o)
 {
+    if (PL_madskills)
+       return;         /* various ok barewords are hidden in extra OP_NULL */
     qerror(Perl_mess(aTHX_
                     "Bareword \"%"SVf"\" not allowed while \"strict subs\" in use",
-                    cSVOPo_sv));
+                    SVfARG(cSVOPo_sv)));
 }
 
 /* "register" allocation */
 
 PADOFFSET
-Perl_allocmy(pTHX_ char *name)
+Perl_allocmy(pTHX_ const char *const name)
 {
     dVAR;
     PADOFFSET off;
-    const bool is_our = (PL_in_my == KEY_our);
+    const bool is_our = (PL_parser->in_my == KEY_our);
 
     /* complain about "my $<special_var>" etc etc */
     if (*name &&
@@ -221,50 +363,58 @@ Perl_allocmy(pTHX_ char *name)
     {
        /* name[2] is true if strlen(name) > 2  */
        if (!isPRINT(name[1]) || strchr("\t\n\r\f", name[1])) {
-           /* 1999-02-27 mjd@plover.com */
-           char *p;
-           p = strchr(name, '\0');
-           /* The next block assumes the buffer is at least 205 chars
-              long.  At present, it's always at least 256 chars. */
-           if (p-name > 200) {
-               strcpy(name+200, "...");
-               p = name+199;
-           }
-           else {
-               p[1] = '\0';
-           }
-           /* Move everything else down one character */
-           for (; p-name > 2; p--)
-               *p = *(p-1);
-           name[2] = toCTRL(name[1]);
-           name[1] = '^';
+           yyerror(Perl_form(aTHX_ "Can't use global %c^%c%s in \"my\"",
+                             name[0], toCTRL(name[1]), name + 2));
+       } else {
+           yyerror(Perl_form(aTHX_ "Can't use global %s in \"my\"",name));
        }
-       yyerror(Perl_form(aTHX_ "Can't use global %s in \"my\"",name));
     }
 
     /* check for duplicate declaration */
     pad_check_dup(name, is_our, (PL_curstash ? PL_curstash : PL_defstash));
 
-    if (PL_in_my_stash && *name != '$') {
+    if (PL_parser->in_my_stash && *name != '$') {
        yyerror(Perl_form(aTHX_
                    "Can't declare class for non-scalar %s in \"%s\"",
-                    name, is_our ? "our" : "my"));
+                    name,
+                    is_our ? "our"
+                           : PL_parser->in_my == KEY_state ? "state" : "my"));
     }
 
     /* allocate a spare slot and store the name in that slot */
 
     off = pad_add_name(name,
-                   PL_in_my_stash,
+                   PL_parser->in_my_stash,
                    (is_our
                        /* $_ is always in main::, even with our */
                        ? (PL_curstash && !strEQ(name,"$_") ? PL_curstash : PL_defstash)
                        : NULL
                    ),
-                   0 /*  not fake */
+                   0, /*  not fake */
+                   PL_parser->in_my == KEY_state
     );
     return off;
 }
 
+/* free the body of an op without examining its contents.
+ * Always use this rather than FreeOp directly */
+
+static void
+S_op_destroy(pTHX_ OP *o)
+{
+    if (o->op_latefree) {
+       o->op_latefreed = 1;
+       return;
+    }
+    FreeOp(o);
+}
+
+#ifdef USE_ITHREADS
+#  define forget_pmop(a,b)     S_forget_pmop(aTHX_ a,b)
+#else
+#  define forget_pmop(a,b)     S_forget_pmop(aTHX_ a)
+#endif
+
 /* Destructor */
 
 void
@@ -272,24 +422,36 @@ Perl_op_free(pTHX_ OP *o)
 {
     dVAR;
     OPCODE type;
-    PADOFFSET refcnt;
 
-    if (!o || o->op_static)
+    if (!o)
        return;
+    if (o->op_latefreed) {
+       if (o->op_latefree)
+           return;
+       goto do_free;
+    }
 
+    type = o->op_type;
     if (o->op_private & OPpREFCOUNTED) {
-       switch (o->op_type) {
+       switch (type) {
        case OP_LEAVESUB:
        case OP_LEAVESUBLV:
        case OP_LEAVEEVAL:
        case OP_LEAVE:
        case OP_SCOPE:
        case OP_LEAVEWRITE:
+           {
+           PADOFFSET refcnt;
            OP_REFCNT_LOCK;
            refcnt = OpREFCNT_dec(o);
            OP_REFCNT_UNLOCK;
-           if (refcnt)
+           if (refcnt) {
+               /* Need to find and remove any pattern match ops from the list
+                  we maintain for reset().  */
+               find_and_forget_pmops(o);
                return;
+           }
+           }
            break;
        default:
            break;
@@ -303,20 +465,29 @@ Perl_op_free(pTHX_ OP *o)
            op_free(kid);
        }
     }
-    type = o->op_type;
     if (type == OP_NULL)
        type = (OPCODE)o->op_targ;
 
+#ifdef PERL_DEBUG_READONLY_OPS
+    Slab_to_rw(o);
+#endif
+
     /* COP* is not cleared by op_clear() so that we may track line
      * numbers etc even after null() */
-    if (type == OP_NEXTSTATE || type == OP_SETSTATE || type == OP_DBSTATE)
+    if (type == OP_NEXTSTATE || type == OP_SETSTATE || type == OP_DBSTATE) {
        cop_free((COP*)o);
+    }
 
     op_clear(o);
+    if (o->op_latefree) {
+       o->op_latefreed = 1;
+       return;
+    }
+  do_free:
     FreeOp(o);
 #ifdef DEBUG_LEAKING_SCALARS
     if (PL_op == o)
-       PL_op = Nullop;
+       PL_op = NULL;
 #endif
 }
 
@@ -325,8 +496,29 @@ Perl_op_clear(pTHX_ OP *o)
 {
 
     dVAR;
+#ifdef PERL_MAD
+    /* if (o->op_madprop && o->op_madprop->mad_next)
+       abort(); */
+    /* FIXME for MAD - if I uncomment these two lines t/op/pack.t fails with
+       "modification of a read only value" for a reason I can't fathom why.
+       It's the "" stringification of $_, where $_ was set to '' in a foreach
+       loop, but it defies simplification into a small test case.
+       However, commenting them out has caused ext/List/Util/t/weak.t to fail
+       the last test.  */
+    /*
+      mad_free(o->op_madprop);
+      o->op_madprop = 0;
+    */
+#endif    
+
+ retry:
     switch (o->op_type) {
     case OP_NULL:      /* Was holding old type, if any. */
+       if (PL_madskills && o->op_targ != OP_NULL) {
+           o->op_type = o->op_targ;
+           o->op_targ = 0;
+           goto retry;
+       }
     case OP_ENTEREVAL: /* Was holding hints. */
        o->op_targ = 0;
        break;
@@ -349,14 +541,14 @@ Perl_op_clear(pTHX_ OP *o)
            }
 #else
            SvREFCNT_dec(cSVOPo->op_sv);
-           cSVOPo->op_sv = Nullsv;
+           cSVOPo->op_sv = NULL;
 #endif
        }
        break;
     case OP_METHOD_NAMED:
     case OP_CONST:
        SvREFCNT_dec(cSVOPo->op_sv);
-       cSVOPo->op_sv = Nullsv;
+       cSVOPo->op_sv = NULL;
 #ifdef USE_ITHREADS
        /** Bug #15654
          Even if op_clear does a pad_free for the target of the op,
@@ -379,54 +571,40 @@ Perl_op_clear(pTHX_ OP *o)
        /* FALL THROUGH */
     case OP_TRANS:
        if (o->op_private & (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF)) {
+#ifdef USE_ITHREADS
+           if (cPADOPo->op_padix > 0) {
+               pad_swipe(cPADOPo->op_padix, TRUE);
+               cPADOPo->op_padix = 0;
+           }
+#else
            SvREFCNT_dec(cSVOPo->op_sv);
-           cSVOPo->op_sv = Nullsv;
+           cSVOPo->op_sv = NULL;
+#endif
        }
        else {
-           Safefree(cPVOPo->op_pv);
+           PerlMemShared_free(cPVOPo->op_pv);
            cPVOPo->op_pv = NULL;
        }
        break;
     case OP_SUBST:
-       op_free(cPMOPo->op_pmreplroot);
+       op_free(cPMOPo->op_pmreplrootu.op_pmreplroot);
        goto clear_pmop;
     case OP_PUSHRE:
 #ifdef USE_ITHREADS
-        if (INT2PTR(PADOFFSET, cPMOPo->op_pmreplroot)) {
+        if (cPMOPo->op_pmreplrootu.op_pmtargetoff) {
            /* No GvIN_PAD_off here, because other references may still
             * exist on the pad */
-           pad_swipe(INT2PTR(PADOFFSET, cPMOPo->op_pmreplroot), TRUE);
+           pad_swipe(cPMOPo->op_pmreplrootu.op_pmtargetoff, TRUE);
        }
 #else
-       SvREFCNT_dec((SV*)cPMOPo->op_pmreplroot);
+       SvREFCNT_dec((SV*)cPMOPo->op_pmreplrootu.op_pmtargetgv);
 #endif
        /* FALL THROUGH */
     case OP_MATCH:
     case OP_QR:
 clear_pmop:
-       {
-           HV * const pmstash = PmopSTASH(cPMOPo);
-           if (pmstash && !SvIS_FREED(pmstash)) {
-               MAGIC * const mg = mg_find((SV*)pmstash, PERL_MAGIC_symtab);
-               if (mg) {
-                   PMOP *pmop = (PMOP*) mg->mg_obj;
-                   PMOP *lastpmop = NULL;
-                   while (pmop) {
-                       if (cPMOPo == pmop) {
-                           if (lastpmop)
-                               lastpmop->op_pmnext = pmop->op_pmnext;
-                           else
-                               mg->mg_obj = (SV*) pmop->op_pmnext;
-                           break;
-                       }
-                       lastpmop = pmop;
-                       pmop = pmop->op_pmnext;
-                   }
-               }
-           }
-           PmopSTASH_free(cPMOPo);
-       }
-       cPMOPo->op_pmreplroot = Nullop;
+       forget_pmop(cPMOPo, 1);
+       cPMOPo->op_pmreplrootu.op_pmreplroot = NULL;
         /* we use the "SAFE" version of the PM_ macros here
          * since sv_clean_all might release some PMOPs
          * after PL_regex_padav has been cleared
@@ -434,10 +612,11 @@ clear_pmop:
          * happen before sv_clean_all
          */
        ReREFCNT_dec(PM_GETRE_SAFE(cPMOPo));
-       PM_SETRE_SAFE(cPMOPo, (REGEXP*)NULL);
+       PM_SETRE_SAFE(cPMOPo, NULL);
 #ifdef USE_ITHREADS
        if(PL_regex_pad) {        /* We could be in destruction */
             av_push((AV*) PL_regex_pad[0],(SV*) PL_regex_pad[(cPMOPo)->op_pmoffset]);
+            SvREADONLY_off(PL_regex_pad[(cPMOPo)->op_pmoffset]);
            SvREPADTMP_on(PL_regex_pad[(cPMOPo)->op_pmoffset]);
             PM_SETRE(cPMOPo, (cPMOPo)->op_pmoffset);
         }
@@ -455,21 +634,70 @@ clear_pmop:
 STATIC void
 S_cop_free(pTHX_ COP* cop)
 {
-    Safefree(cop->cop_label);   /* FIXME: treaddead ??? */
+    CopLABEL_free(cop);
     CopFILE_free(cop);
     CopSTASH_free(cop);
     if (! specialWARN(cop->cop_warnings))
-       SvREFCNT_dec(cop->cop_warnings);
-    if (! specialCopIO(cop->cop_io)) {
+       PerlMemShared_free(cop->cop_warnings);
+    Perl_refcounted_he_free(aTHX_ cop->cop_hints_hash);
+}
+
+STATIC void
+S_forget_pmop(pTHX_ PMOP *const o
 #ifdef USE_ITHREADS
-#if 0
-       STRLEN len;
-        char *s = SvPV(cop->cop_io,len);
-       Perl_warn(aTHX_ "io='%.*s'",(int) len,s); /* ??? --jhi */
+             , U32 flags
 #endif
-#else
-       SvREFCNT_dec(cop->cop_io);
+             )
+{
+    HV * const pmstash = PmopSTASH(o);
+    if (pmstash && !SvIS_FREED(pmstash)) {
+       MAGIC * const mg = mg_find((SV*)pmstash, PERL_MAGIC_symtab);
+       if (mg) {
+           PMOP **const array = (PMOP**) mg->mg_ptr;
+           U32 count = mg->mg_len / sizeof(PMOP**);
+           U32 i = count;
+
+           while (i--) {
+               if (array[i] == o) {
+                   /* Found it. Move the entry at the end to overwrite it.  */
+                   array[i] = array[--count];
+                   mg->mg_len = count * sizeof(PMOP**);
+                   /* Could realloc smaller at this point always, but probably
+                      not worth it. Probably worth free()ing if we're the
+                      last.  */
+                   if(!count) {
+                       Safefree(mg->mg_ptr);
+                       mg->mg_ptr = NULL;
+                   }
+                   break;
+               }
+           }
+       }
+    }
+    if (PL_curpm == o) 
+       PL_curpm = NULL;
+#ifdef USE_ITHREADS
+    if (flags)
+       PmopSTASH_free(o);
 #endif
+}
+
+STATIC void
+S_find_and_forget_pmops(pTHX_ OP *o)
+{
+    if (o->op_flags & OPf_KIDS) {
+        OP *kid = cUNOPo->op_first;
+       while (kid) {
+           switch (kid->op_type) {
+           case OP_SUBST:
+           case OP_PUSHRE:
+           case OP_MATCH:
+           case OP_QR:
+               forget_pmop((PMOP*)kid, 0);
+           }
+           find_and_forget_pmops(kid);
+           kid = kid->op_sibling;
+       }
     }
 }
 
@@ -479,7 +707,8 @@ Perl_op_null(pTHX_ OP *o)
     dVAR;
     if (o->op_type == OP_NULL)
        return;
-    op_clear(o);
+    if (!PL_madskills)
+       op_clear(o);
     o->op_targ = o->op_type;
     o->op_type = OP_NULL;
     o->op_ppaddr = PL_ppaddr[OP_NULL];
@@ -489,6 +718,7 @@ void
 Perl_op_refcnt_lock(pTHX)
 {
     dVAR;
+    PERL_UNUSED_CONTEXT;
     OP_REFCNT_LOCK;
 }
 
@@ -496,6 +726,7 @@ void
 Perl_op_refcnt_unlock(pTHX)
 {
     dVAR;
+    PERL_UNUSED_CONTEXT;
     OP_REFCNT_UNLOCK;
 }
 
@@ -552,8 +783,8 @@ S_scalarboolean(pTHX_ OP *o)
        if (ckWARN(WARN_SYNTAX)) {
            const line_t oldline = CopLINE(PL_curcop);
 
-           if (PL_copline != NOLINE)
-               CopLINE_set(PL_curcop, PL_copline);
+           if (PL_parser && PL_parser->copline != NOLINE)
+               CopLINE_set(PL_curcop, PL_parser->copline);
            Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Found = in conditional, should be ==");
            CopLINE_set(PL_curcop, oldline);
        }
@@ -568,7 +799,8 @@ Perl_scalar(pTHX_ OP *o)
     OP *kid;
 
     /* assumes no premature commitment */
-    if (!o || PL_error_count || (o->op_flags & OPf_WANT)
+    if (!o || (PL_parser && PL_parser->error_count)
+        || (o->op_flags & OPf_WANT)
         || o->op_type == OP_RETURN)
     {
        return o;
@@ -588,7 +820,7 @@ Perl_scalar(pTHX_ OP *o)
        break;
     case OP_SPLIT:
        if ((kid = cLISTOPo->op_first) && kid->op_type == OP_PUSHRE) {
-           if (!kPMOP->op_pmreplroot)
+           if (!kPMOP->op_pmreplrootu.op_pmreplroot)
                deprecate_old("implicit split to @_");
        }
        /* FALL THROUGH */
@@ -612,7 +844,7 @@ Perl_scalar(pTHX_ OP *o)
            else
                scalar(kid);
        }
-       WITH_THR(PL_curcop = &PL_compiling);
+       PL_curcop = &PL_compiling;
        break;
     case OP_SCOPE:
     case OP_LINESEQ:
@@ -623,7 +855,7 @@ Perl_scalar(pTHX_ OP *o)
            else
                scalar(kid);
        }
-       WITH_THR(PL_curcop = &PL_compiling);
+       PL_curcop = &PL_compiling;
        break;
     case OP_SORT:
        if (ckWARN(WARN_VOID))
@@ -641,6 +873,21 @@ Perl_scalarvoid(pTHX_ OP *o)
     SV* sv;
     U8 want;
 
+    /* trailing mad null ops don't count as "there" for void processing */
+    if (PL_madskills &&
+       o->op_type != OP_NULL &&
+       o->op_sibling &&
+       o->op_sibling->op_type == OP_NULL)
+    {
+       OP *sib;
+       for (sib = o->op_sibling;
+               sib && sib->op_type == OP_NULL;
+               sib = sib->op_sibling) ;
+       
+       if (!sib)
+           return o;
+    }
+
     if (o->op_type == OP_NEXTSTATE
        || o->op_type == OP_SETSTATE
        || o->op_type == OP_DBSTATE
@@ -651,7 +898,8 @@ Perl_scalarvoid(pTHX_ OP *o)
 
     /* assumes no premature commitment */
     want = o->op_flags & OPf_WANT;
-    if ((want && want != OPf_WANT_SCALAR) || PL_error_count
+    if ((want && want != OPf_WANT_SCALAR)
+        || (PL_parser && PL_parser->error_count)
         || o->op_type == OP_RETURN)
     {
        return o;
@@ -776,15 +1024,17 @@ Perl_scalarvoid(pTHX_ OP *o)
        else {
            if (ckWARN(WARN_VOID)) {
                useless = "a constant";
+               if (o->op_private & OPpCONST_ARYBASE)
+                   useless = NULL;
                /* don't warn on optimised away booleans, eg 
                 * use constant Foo, 5; Foo || print; */
                if (cSVOPo->op_private & OPpCONST_SHORTCIRCUIT)
-                   useless = 0;
+                   useless = NULL;
                /* the constants 0 and 1 are permitted as they are
                   conventionally used as dummies in constructs like
                        1 while some_condition_with_side_effects;  */
                else if (SvNIOK(sv) && (SvNV(sv) == 0.0 || SvNV(sv) == 1.0))
-                   useless = 0;
+                   useless = NULL;
                else if (SvPOK(sv)) {
                   /* perl4's way of mixing documentation and code
                      (before the invention of POD) was based on a
@@ -796,7 +1046,7 @@ Perl_scalarvoid(pTHX_ OP *o)
                    if (strnEQ(maybe_macro, "di", 2) ||
                        strnEQ(maybe_macro, "ds", 2) ||
                        strnEQ(maybe_macro, "ig", 2))
-                           useless = 0;
+                           useless = NULL;
                }
            }
        }
@@ -866,7 +1116,7 @@ Perl_scalarvoid(pTHX_ OP *o)
        return scalar(o);
     case OP_SPLIT:
        if ((kid = cLISTOPo->op_first) && kid->op_type == OP_PUSHRE) {
-           if (!kPMOP->op_pmreplroot)
+           if (!kPMOP->op_pmreplrootu.op_pmreplroot)
                deprecate_old("implicit split to @_");
        }
        break;
@@ -894,7 +1144,8 @@ Perl_list(pTHX_ OP *o)
     OP *kid;
 
     /* assumes no premature commitment */
-    if (!o || (o->op_flags & OPf_WANT) || PL_error_count
+    if (!o || (o->op_flags & OPf_WANT)
+        || (PL_parser && PL_parser->error_count)
         || o->op_type == OP_RETURN)
     {
        return o;
@@ -943,7 +1194,7 @@ Perl_list(pTHX_ OP *o)
            else
                list(kid);
        }
-       WITH_THR(PL_curcop = &PL_compiling);
+       PL_curcop = &PL_compiling;
        break;
     case OP_SCOPE:
     case OP_LINESEQ:
@@ -953,7 +1204,7 @@ Perl_list(pTHX_ OP *o)
            else
                list(kid);
        }
-       WITH_THR(PL_curcop = &PL_compiling);
+       PL_curcop = &PL_compiling;
        break;
     case OP_REQUIRE:
        /* all requires must return a boolean value */
@@ -968,10 +1219,10 @@ Perl_scalarseq(pTHX_ OP *o)
 {
     dVAR;
     if (o) {
-       if (o->op_type == OP_LINESEQ ||
-            o->op_type == OP_SCOPE ||
-            o->op_type == OP_LEAVE ||
-            o->op_type == OP_LEAVETRY)
+       const OPCODE type = o->op_type;
+
+       if (type == OP_LINESEQ || type == OP_SCOPE ||
+           type == OP_LEAVE || type == OP_LEAVETRY)
        {
             OP *kid;
            for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) {
@@ -1020,7 +1271,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
     /* -1 = error on localize, 0 = ignore localize, 1 = ok to localize */
     int localize = -1;
 
-    if (!o || PL_error_count)
+    if (!o || (PL_parser && PL_parser->error_count))
        return o;
 
     if ((o->op_private & OPpTARGET_MY)
@@ -1035,16 +1286,17 @@ Perl_mod(pTHX_ OP *o, I32 type)
        PL_modcount++;
        return o;
     case OP_CONST:
-       if (!(o->op_private & (OPpCONST_ARYBASE)))
+       if (!(o->op_private & OPpCONST_ARYBASE))
            goto nomod;
        localize = 0;
        if (PL_eval_start && PL_eval_start->op_type == OP_CONST) {
-           PL_compiling.cop_arybase = (I32)SvIV(cSVOPx(PL_eval_start)->op_sv);
+           CopARYBASE_set(&PL_compiling,
+                          (I32)SvIV(cSVOPx(PL_eval_start)->op_sv));
            PL_eval_start = 0;
        }
        else if (!type) {
-           SAVEI32(PL_compiling.cop_arybase);
-           PL_compiling.cop_arybase = 0;
+           SAVECOPARYBASE(&PL_compiling);
+           CopARYBASE_set(&PL_compiling, 0);
        }
        else if (type == OP_REFGEN)
            goto nomod;
@@ -1052,7 +1304,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
            Perl_croak(aTHX_ "That use of $[ is unsupported");
        break;
     case OP_STUB:
-       if (o->op_flags & OPf_PARENS)
+       if ((o->op_flags & OPf_PARENS) || PL_madskills)
            break;
        goto nomod;
     case OP_ENTERSUB:
@@ -1083,15 +1335,14 @@ Perl_mod(pTHX_ OP *o, I32 type)
                CV *cv;
                OP *okid;
 
-               if (kid->op_type == OP_PUSHMARK)
-                   goto skip_kids;
-               if (kid->op_type != OP_NULL || kid->op_targ != OP_LIST)
-                   Perl_croak(aTHX_
-                              "panic: unexpected lvalue entersub "
-                              "args: type/targ %ld:%"UVuf,
-                              (long)kid->op_type, (UV)kid->op_targ);
-               kid = kLISTOP->op_first;
-             skip_kids:
+               if (kid->op_type != OP_PUSHMARK) {
+                   if (kid->op_type != OP_NULL || kid->op_targ != OP_LIST)
+                       Perl_croak(aTHX_
+                               "panic: unexpected lvalue entersub "
+                               "args: type/targ %ld:%"UVuf,
+                               (long)kid->op_type, (UV)kid->op_targ);
+                   kid = kLISTOP->op_first;
+               }
                while (kid->op_sibling)
                    kid = kid->op_sibling;
                if (!(kid->op_type == OP_NULL && kid->op_targ == OP_RV2CV)) {
@@ -1104,7 +1355,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
                        NewOp(1101, newop, 1, UNOP);
                        newop->op_type = OP_RV2CV;
                        newop->op_ppaddr = PL_ppaddr[OP_RV2CV];
-                       newop->op_first = Nullop;
+                       newop->op_first = NULL;
                         newop->op_next = (OP*)newop;
                        kid->op_sibling = (OP*)newop;
                        newop->op_private |= OPpLVAL_INTRO;
@@ -1138,7 +1389,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
                        kid->op_next = okid;
                    }
                    else
-                       okid->op_next = Nullop;
+                       okid->op_next = NULL;
                    okid->op_type = OP_RV2CV;
                    okid->op_targ = 0;
                    okid->op_ppaddr = PL_ppaddr[OP_RV2CV];
@@ -1362,7 +1613,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
 }
 
 STATIC bool
-S_scalar_mod_type(pTHX_ const OP *o, I32 type)
+S_scalar_mod_type(const OP *o, I32 type)
 {
     switch (type) {
     case OP_SASSIGN:
@@ -1402,6 +1653,7 @@ S_scalar_mod_type(pTHX_ const OP *o, I32 type)
     case OP_RECV:
     case OP_ANDASSIGN:
     case OP_ORASSIGN:
+    case OP_DORASSIGN:
        return TRUE;
     default:
        return FALSE;
@@ -1409,7 +1661,7 @@ S_scalar_mod_type(pTHX_ const OP *o, I32 type)
 }
 
 STATIC bool
-S_is_handle_constructor(pTHX_ const OP *o, I32 numargs)
+S_is_handle_constructor(const OP *o, I32 numargs)
 {
     switch (o->op_type) {
     case OP_PIPE_OP:
@@ -1425,7 +1677,7 @@ S_is_handle_constructor(pTHX_ const OP *o, I32 numargs)
     case OP_ACCEPT:
        if (numargs == 1)
            return TRUE;
-       /* FALL THROUGH */
+       /* FALLTHROUGH */
     default:
        return FALSE;
     }
@@ -1448,7 +1700,7 @@ Perl_doref(pTHX_ OP *o, I32 type, bool set_op_ref)
     dVAR;
     OP *kid;
 
-    if (!o || PL_error_count)
+    if (!o || (PL_parser && PL_parser->error_count))
        return o;
 
     switch (o->op_type) {
@@ -1482,10 +1734,6 @@ Perl_doref(pTHX_ OP *o, I32 type, bool set_op_ref)
        }
        break;
 
-    case OP_THREADSV:
-       o->op_flags |= OPf_MOD;         /* XXX ??? */
-       break;
-
     case OP_RV2AV:
     case OP_RV2HV:
        if (set_op_ref)
@@ -1548,15 +1796,19 @@ S_dup_attrlist(pTHX_ OP *o)
      * are OP_CONST.  We need to push the OP_CONST values.
      */
     if (o->op_type == OP_CONST)
-       rop = newSVOP(OP_CONST, o->op_flags, SvREFCNT_inc(cSVOPo->op_sv));
+       rop = newSVOP(OP_CONST, o->op_flags, SvREFCNT_inc_NN(cSVOPo->op_sv));
+#ifdef PERL_MAD
+    else if (o->op_type == OP_NULL)
+       rop = NULL;
+#endif
     else {
        assert((o->op_type == OP_LIST) && (o->op_flags & OPf_KIDS));
-       rop = Nullop;
+       rop = NULL;
        for (o = cLISTOPo->op_first; o; o=o->op_sibling) {
            if (o->op_type == OP_CONST)
                rop = append_elem(OP_LIST, rop,
                                  newSVOP(OP_CONST, o->op_flags,
-                                         SvREFCNT_inc(cSVOPo->op_sv)));
+                                         SvREFCNT_inc_NN(cSVOPo->op_sv)));
        }
     }
     return rop;
@@ -1570,7 +1822,6 @@ S_apply_attrs(pTHX_ HV *stash, SV *target, OP *attrs, bool for_my)
 
     /* fake up C<use attributes $pkg,$rv,@attrs> */
     ENTER;             /* need to protect against side-effects of 'use' */
-    SAVEINT(PL_expect);
     stashsv = stash ? newSVhek(HvNAME_HEK(stash)) : &PL_sv_no;
 
 #define ATTRSMODULE "attributes"
@@ -1580,7 +1831,7 @@ S_apply_attrs(pTHX_ HV *stash, SV *target, OP *attrs, bool for_my)
        /* Don't force the C<use> if we don't need it. */
        SV * const * const svp = hv_fetchs(GvHVn(PL_incgv), ATTRSMODULE_PM, FALSE);
        if (svp && *svp != &PL_sv_undef)
-           ;           /* already in %INC */
+           NOOP;       /* already in %INC */
        else
            Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT,
                             newSVpvs(ATTRSMODULE), NULL);
@@ -1664,7 +1915,7 @@ void
 Perl_apply_attrs_string(pTHX_ const char *stashpv, CV *cv,
                         const char *attrstr, STRLEN len)
 {
-    OP *attrs = Nullop;
+    OP *attrs = NULL;
 
     if (!len) {
         len = strlen(attrstr);
@@ -1683,7 +1934,7 @@ Perl_apply_attrs_string(pTHX_ const char *stashpv, CV *cv,
 
     Perl_load_module(aTHX_ PERL_LOADMOD_IMPORT_OPS,
                     newSVpvs(ATTRSMODULE),
-                     Nullsv, prepend_elem(OP_LIST,
+                     NULL, prepend_elem(OP_LIST,
                                  newSVOP(OP_CONST, 0, newSVpv(stashpv,0)),
                                  prepend_elem(OP_LIST,
                                               newSVOP(OP_CONST, 0,
@@ -1697,26 +1948,38 @@ S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp)
     dVAR;
     I32 type;
 
-    if (!o || PL_error_count)
+    if (!o || (PL_parser && PL_parser->error_count))
        return o;
 
     type = o->op_type;
+    if (PL_madskills && type == OP_NULL && o->op_flags & OPf_KIDS) {
+       (void)my_kid(cUNOPo->op_first, attrs, imopsp);
+       return o;
+    }
+
     if (type == OP_LIST) {
         OP *kid;
        for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
            my_kid(kid, attrs, imopsp);
-    } else if (type == OP_UNDEF) {
+    } else if (type == OP_UNDEF
+#ifdef PERL_MAD
+              || type == OP_STUB
+#endif
+              ) {
        return o;
     } else if (type == OP_RV2SV ||     /* "our" declaration */
               type == OP_RV2AV ||
               type == OP_RV2HV) { /* XXX does this let anything illegal in? */
        if (cUNOPo->op_first->op_type != OP_GV) { /* MJD 20011224 */
-           yyerror(Perl_form(aTHX_ "Can't declare %s in %s",
-                       OP_DESC(o), PL_in_my == KEY_our ? "our" : "my"));
+           yyerror(Perl_form(aTHX_ "Can't declare %s in \"%s\"",
+                       OP_DESC(o),
+                       PL_parser->in_my == KEY_our
+                           ? "our"
+                           : PL_parser->in_my == KEY_state ? "state" : "my"));
        } else if (attrs) {
            GV * const gv = cGVOPx_gv(cUNOPo->op_first);
-           PL_in_my = FALSE;
-           PL_in_my_stash = NULL;
+           PL_parser->in_my = FALSE;
+           PL_parser->in_my_stash = NULL;
            apply_attrs(GvSTASH(gv),
                        (type == OP_RV2SV ? GvSV(gv) :
                         type == OP_RV2AV ? (SV*)GvAV(gv) :
@@ -1733,14 +1996,16 @@ S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp)
     {
        yyerror(Perl_form(aTHX_ "Can't declare %s in \"%s\"",
                          OP_DESC(o),
-                         PL_in_my == KEY_our ? "our" : "my"));
+                         PL_parser->in_my == KEY_our
+                           ? "our"
+                           : PL_parser->in_my == KEY_state ? "state" : "my"));
        return o;
     }
     else if (attrs && type != OP_PUSHMARK) {
        HV *stash;
 
-       PL_in_my = FALSE;
-       PL_in_my_stash = NULL;
+       PL_parser->in_my = FALSE;
+       PL_parser->in_my_stash = NULL;
 
        /* check for C<my Dog $spot> when deciding package */
        stash = PAD_COMPNAME_TYPE(o->op_targ);
@@ -1750,6 +2015,8 @@ S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp)
     }
     o->op_flags |= OPf_MOD;
     o->op_private |= OPpLVAL_INTRO;
+    if (PL_parser->in_my == KEY_state)
+       o->op_private |= OPpPAD_STATE;
     return o;
 }
 
@@ -1772,7 +2039,7 @@ Perl_my_attrs(pTHX_ OP *o, OP *attrs)
 #endif
     if (attrs)
        SAVEFREEOP(attrs);
-    rops = Nullop;
+    rops = NULL;
     o = my_kid(o, attrs, &rops);
     if (rops) {
        if (maybe_scalar && o->op_type == OP_PADSV) {
@@ -1782,20 +2049,21 @@ Perl_my_attrs(pTHX_ OP *o, OP *attrs)
        else
            o = append_list(OP_LIST, (LISTOP*)o, (LISTOP*)rops);
     }
-    PL_in_my = FALSE;
-    PL_in_my_stash = NULL;
+    PL_parser->in_my = FALSE;
+    PL_parser->in_my_stash = NULL;
     return o;
 }
 
 OP *
 Perl_my(pTHX_ OP *o)
 {
-    return my_attrs(o, Nullop);
+    return my_attrs(o, NULL);
 }
 
 OP *
 Perl_sawparens(pTHX_ OP *o)
 {
+    PERL_UNUSED_CONTEXT;
     if (o)
        o->op_flags |= OPf_PARENS;
     return o;
@@ -1806,48 +2074,50 @@ Perl_bind_match(pTHX_ I32 type, OP *left, OP *right)
 {
     OP *o;
     bool ismatchop = 0;
+    const OPCODE ltype = left->op_type;
+    const OPCODE rtype = right->op_type;
 
-    if ( (left->op_type == OP_RV2AV ||
-       left->op_type == OP_RV2HV ||
-       left->op_type == OP_PADAV ||
-       left->op_type == OP_PADHV)
-       && ckWARN(WARN_MISC))
+    if ( (ltype == OP_RV2AV || ltype == OP_RV2HV || ltype == OP_PADAV
+         || ltype == OP_PADHV) && ckWARN(WARN_MISC))
     {
-      const char * const desc = PL_op_desc[(right->op_type == OP_SUBST ||
-                            right->op_type == OP_TRANS)
-                           ? right->op_type : OP_MATCH];
-      const char * const sample = ((left->op_type == OP_RV2AV ||
-                            left->op_type == OP_PADAV)
-                           ? "@array" : "%hash");
+      const char * const desc
+         = PL_op_desc[(rtype == OP_SUBST || rtype == OP_TRANS)
+                      ? (int)rtype : OP_MATCH];
+      const char * const sample = ((ltype == OP_RV2AV || ltype == OP_PADAV)
+            ? "@array" : "%hash");
       Perl_warner(aTHX_ packWARN(WARN_MISC),
              "Applying %s to %s will act on scalar(%s)",
              desc, sample, sample);
     }
 
-    if (right->op_type == OP_CONST &&
+    if (rtype == OP_CONST &&
        cSVOPx(right)->op_private & OPpCONST_BARE &&
        cSVOPx(right)->op_private & OPpCONST_STRICT)
     {
        no_bareword_allowed(right);
     }
 
-    ismatchop = right->op_type == OP_MATCH ||
-               right->op_type == OP_SUBST ||
-               right->op_type == OP_TRANS;
+    ismatchop = rtype == OP_MATCH ||
+               rtype == OP_SUBST ||
+               rtype == OP_TRANS;
     if (ismatchop && right->op_private & OPpTARGET_MY) {
        right->op_targ = 0;
        right->op_private &= ~OPpTARGET_MY;
     }
     if (!(right->op_flags & OPf_STACKED) && ismatchop) {
+       OP *newleft;
+
        right->op_flags |= OPf_STACKED;
-       if (right->op_type != OP_MATCH &&
-            ! (right->op_type == OP_TRANS &&
+       if (rtype != OP_MATCH &&
+            ! (rtype == OP_TRANS &&
                right->op_private & OPpTRANS_IDENTICAL))
-           left = mod(left, right->op_type);
+           newleft = mod(left, rtype);
+       else
+           newleft = left;
        if (right->op_type == OP_TRANS)
-           o = newBINOP(OP_NULL, OPf_STACKED, scalar(left), right);
+           o = newBINOP(OP_NULL, OPf_STACKED, scalar(newleft), right);
        else
-           o = prepend_elem(right->op_type, scalar(left), right);
+           o = prepend_elem(rtype, scalar(newleft), right);
        if (type == OP_NOT)
            return newUNOP(OP_NOT, 0, scalar(o));
        return o;
@@ -1861,8 +2131,7 @@ OP *
 Perl_invert(pTHX_ OP *o)
 {
     if (!o)
-       return o;
-    /* XXX need to optimize away NOT NOT here?  Or do we let optimizer do it? */
+       return NULL;
     return newUNOP(OP_NOT, OPf_SPECIAL, scalar(o));
 }
 
@@ -1892,11 +2161,11 @@ Perl_scope(pTHX_ OP *o)
            }
        }
        else
-           o = newLISTOP(OP_SCOPE, 0, o, Nullop);
+           o = newLISTOP(OP_SCOPE, 0, o, NULL);
     }
     return o;
 }
-
+       
 int
 Perl_block_start(pTHX_ int full)
 {
@@ -1905,16 +2174,8 @@ Perl_block_start(pTHX_ int full)
     pad_block_start(full);
     SAVEHINTS();
     PL_hints &= ~HINT_BLOCK_SCOPE;
-    SAVESPTR(PL_compiling.cop_warnings);
-    if (! specialWARN(PL_compiling.cop_warnings)) {
-        PL_compiling.cop_warnings = newSVsv(PL_compiling.cop_warnings) ;
-        SAVEFREESV(PL_compiling.cop_warnings) ;
-    }
-    SAVESPTR(PL_compiling.cop_io);
-    if (! specialCopIO(PL_compiling.cop_io)) {
-        PL_compiling.cop_io = newSVsv(PL_compiling.cop_io) ;
-        SAVEFREESV(PL_compiling.cop_io) ;
-    }
+    SAVECOMPILEWARNINGS();
+    PL_compiling.cop_warnings = DUP_WARNINGS(PL_compiling.cop_warnings);
     return retval;
 }
 
@@ -1925,7 +2186,7 @@ Perl_block_end(pTHX_ I32 floor, OP *seq)
     const int needblockscope = PL_hints & HINT_BLOCK_SCOPE;
     OP* const retval = scalarseq(seq);
     LEAVE_SCOPE(floor);
-    PL_compiling.op_private = (U8)(PL_hints & HINT_PRIVATE_MASK);
+    CopHINTS_set(&PL_compiling, PL_hints);
     if (needblockscope)
        PL_hints |= HINT_BLOCK_SCOPE; /* propagate out */
     pad_leavemy();
@@ -1936,8 +2197,8 @@ STATIC OP *
 S_newDEFSVOP(pTHX)
 {
     dVAR;
-    const I32 offset = pad_findmy("$_");
-    if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS(offset) & SVpad_OUR) {
+    const PADOFFSET offset = pad_findmy("$_");
+    if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS_isOUR(offset)) {
        return newSVREF(newGVOP(OP_GV, 0, PL_defgv));
     }
     else {
@@ -1967,7 +2228,7 @@ Perl_newPROG(pTHX_ OP *o)
        if (o->op_type == OP_STUB) {
            PL_comppad_name = 0;
            PL_compcv = 0;
-           FreeOp(o);
+           S_op_destroy(aTHX_ o);
            return;
        }
        PL_main_root = scope(sawparens(scalarvoid(o)));
@@ -1981,7 +2242,8 @@ Perl_newPROG(pTHX_ OP *o)
 
        /* Register with debugger */
        if (PERLDB_INTER) {
-           CV * const cv = get_cv("DB::postponed", FALSE);
+           CV * const cv
+               = Perl_get_cvn_flags(aTHX_ STR_WITH_LEN("DB::postponed"), 0);
            if (cv) {
                dSP;
                PUSHMARK(SP);
@@ -2003,13 +2265,14 @@ Perl_localize(pTHX_ OP *o, I32 lex)
 #if 0
        list(o);
 #else
-       ;
+       NOOP;
 #endif
     else {
-       if ( PL_bufptr > PL_oldbufptr && PL_bufptr[-1] == ','
+       if ( PL_parser->bufptr > PL_parser->oldbufptr
+           && PL_parser->bufptr[-1] == ','
            && ckWARN(WARN_PARENTHESIS))
        {
-           char *s = PL_bufptr;
+           char *s = PL_parser->bufptr;
            bool sigil = FALSE;
 
            /* some heuristics to detect a potential error */
@@ -2032,8 +2295,13 @@ Perl_localize(pTHX_ OP *o, I32 lex)
            if (sigil && (*s == ';' || *s == '=')) {
                Perl_warner(aTHX_ packWARN(WARN_PARENTHESIS),
                                "Parentheses missing around \"%s\" list",
-                               lex ? (PL_in_my == KEY_our ? "our" : "my")
-                               : "local");
+                               lex
+                                   ? (PL_parser->in_my == KEY_our
+                                       ? "our"
+                                       : PL_parser->in_my == KEY_state
+                                           ? "state"
+                                           : "my")
+                                   : "local");
            }
        }
     }
@@ -2041,8 +2309,8 @@ Perl_localize(pTHX_ OP *o, I32 lex)
        o = my(o);
     else
        o = mod(o, OP_NULL);            /* a bit kludgey */
-    PL_in_my = FALSE;
-    PL_in_my_stash = NULL;
+    PL_parser->in_my = FALSE;
+    PL_parser->in_my_stash = NULL;
     return o;
 }
 
@@ -2051,8 +2319,7 @@ Perl_jmaybe(pTHX_ OP *o)
 {
     if (o->op_type == OP_LIST) {
        OP * const o2
-           = newSVREF(newGVOP(OP_GV, 0, gv_fetchpvs(";", GV_ADD|GV_NOTQUAL,
-                                                    SVt_PV)));
+           = newSVREF(newGVOP(OP_GV, 0, gv_fetchpvs(";", GV_ADD|GV_NOTQUAL, SVt_PV)));
        o = convert(OP_JOIN, 0, prepend_elem(OP_LIST, o2, o));
     }
     return o;
@@ -2063,8 +2330,15 @@ Perl_fold_constants(pTHX_ register OP *o)
 {
     dVAR;
     register OP *curop;
-    I32 type = o->op_type;
-    SV *sv;
+    OP *newop;
+    VOL I32 type = o->op_type;
+    SV * VOL sv = NULL;
+    int ret = 0;
+    I32 oldscope;
+    OP *old_next;
+    SV * const oldwarnhook = PL_warnhook;
+    SV * const olddiehook  = PL_diehook;
+    dJMPENV;
 
     if (PL_opargs[type] & OA_RETSCALAR)
        scalar(o);
@@ -2102,38 +2376,81 @@ Perl_fold_constants(pTHX_ register OP *o)
            goto nope;
     }
 
-    if (PL_error_count)
+    if (PL_parser && PL_parser->error_count)
        goto nope;              /* Don't try to run w/ errors */
 
     for (curop = LINKLIST(o); curop != o; curop = LINKLIST(curop)) {
-       if ((curop->op_type != OP_CONST ||
-            (curop->op_private & OPpCONST_BARE)) &&
-           curop->op_type != OP_LIST &&
-           curop->op_type != OP_SCALAR &&
-           curop->op_type != OP_NULL &&
-           curop->op_type != OP_PUSHMARK)
+       const OPCODE type = curop->op_type;
+       if ((type != OP_CONST || (curop->op_private & OPpCONST_BARE)) &&
+           type != OP_LIST &&
+           type != OP_SCALAR &&
+           type != OP_NULL &&
+           type != OP_PUSHMARK)
        {
            goto nope;
        }
     }
 
     curop = LINKLIST(o);
+    old_next = o->op_next;
     o->op_next = 0;
     PL_op = curop;
-    CALLRUNOPS(aTHX);
-    sv = *(PL_stack_sp--);
-    if (o->op_targ && sv == PAD_SV(o->op_targ))        /* grab pad temp? */
-       pad_swipe(o->op_targ,  FALSE);
-    else if (SvTEMP(sv)) {                     /* grab mortal temp? */
-       (void)SvREFCNT_inc(sv);
-       SvTEMP_off(sv);
-    }
+
+    oldscope = PL_scopestack_ix;
+    create_eval_scope(G_FAKINGEVAL);
+
+    PL_warnhook = PERL_WARNHOOK_FATAL;
+    PL_diehook  = NULL;
+    JMPENV_PUSH(ret);
+
+    switch (ret) {
+    case 0:
+       CALLRUNOPS(aTHX);
+       sv = *(PL_stack_sp--);
+       if (o->op_targ && sv == PAD_SV(o->op_targ))     /* grab pad temp? */
+           pad_swipe(o->op_targ,  FALSE);
+       else if (SvTEMP(sv)) {                  /* grab mortal temp? */
+           SvREFCNT_inc_simple_void(sv);
+           SvTEMP_off(sv);
+       }
+       break;
+    case 3:
+       /* Something tried to die.  Abandon constant folding.  */
+       /* Pretend the error never happened.  */
+       sv_setpvn(ERRSV,"",0);
+       o->op_next = old_next;
+       break;
+    default:
+       JMPENV_POP;
+       /* Don't expect 1 (setjmp failed) or 2 (something called my_exit)  */
+       PL_warnhook = oldwarnhook;
+       PL_diehook  = olddiehook;
+       /* XXX note that this croak may fail as we've already blown away
+        * the stack - eg any nested evals */
+       Perl_croak(aTHX_ "panic: fold_constants JMPENV_PUSH returned %d", ret);
+    }
+    JMPENV_POP;
+    PL_warnhook = oldwarnhook;
+    PL_diehook  = olddiehook;
+
+    if (PL_scopestack_ix > oldscope)
+       delete_eval_scope();
+
+    if (ret)
+       goto nope;
+
+#ifndef PERL_MAD
     op_free(o);
+#endif
+    assert(sv);
     if (type == OP_RV2GV)
-       return newGVOP(OP_GV, 0, (GV*)sv);
-    return newSVOP(OP_CONST, 0, sv);
+       newop = newGVOP(OP_GV, 0, (GV*)sv);
+    else
+       newop = newSVOP(OP_CONST, 0, (SV*)sv);
+    op_getmad(o,newop,'f');
+    return newop;
 
-  nope:
+ nope:
     return o;
 }
 
@@ -2145,7 +2462,7 @@ Perl_gen_constant_list(pTHX_ register OP *o)
     const I32 oldtmps_floor = PL_tmps_floor;
 
     list(o);
-    if (PL_error_count)
+    if (PL_parser && PL_parser->error_count)
        return o;               /* Don't attempt to run with errors */
 
     PL_op = curop = LINKLIST(o);
@@ -2154,6 +2471,8 @@ Perl_gen_constant_list(pTHX_ register OP *o)
     pp_pushmark();
     CALLRUNOPS(aTHX);
     PL_op = curop;
+    assert (!(curop->op_flags & OPf_SPECIAL));
+    assert(curop->op_type == OP_RANGE);
     pp_anonlist();
     PL_tmps_floor = oldtmps_floor;
 
@@ -2163,8 +2482,12 @@ Perl_gen_constant_list(pTHX_ register OP *o)
     o->op_flags |= OPf_PARENS; /* and flatten \(1..2,3) */
     o->op_opt = 0;             /* needs to be revisited in peep() */
     curop = ((UNOP*)o)->op_first;
-    ((UNOP*)o)->op_first = newSVOP(OP_CONST, 0, SvREFCNT_inc(*PL_stack_sp--));
+    ((UNOP*)o)->op_first = newSVOP(OP_CONST, 0, SvREFCNT_inc_NN(*PL_stack_sp--));
+#ifdef PERL_MAD
+    op_getmad(curop,o,'O');
+#else
     op_free(curop);
+#endif
     linklist(o);
     return list(o);
 }
@@ -2174,7 +2497,7 @@ Perl_convert(pTHX_ I32 type, I32 flags, OP *o)
 {
     dVAR;
     if (!o || o->op_type != OP_LIST)
-       o = newLISTOP(OP_LIST, 0, o, Nullop);
+       o = newLISTOP(OP_LIST, 0, o, NULL);
     else
        o->op_flags &= ~OPf_WANT;
 
@@ -2238,7 +2561,23 @@ Perl_append_list(pTHX_ I32 type, LISTOP *first, LISTOP *last)
     first->op_last = last->op_last;
     first->op_flags |= (last->op_flags & OPf_KIDS);
 
-    FreeOp(last);
+#ifdef PERL_MAD
+    if (last->op_first && first->op_madprop) {
+       MADPROP *mp = last->op_first->op_madprop;
+       if (mp) {
+           while (mp->mad_next)
+               mp = mp->mad_next;
+           mp->mad_next = first->op_madprop;
+       }
+       else {
+           last->op_first->op_madprop = first->op_madprop;
+       }
+    }
+    first->op_madprop = last->op_madprop;
+    last->op_madprop = 0;
+#endif
+
+    S_op_destroy(aTHX_ (OP*)last);
 
     return (OP*)first;
 }
@@ -2276,6 +2615,246 @@ Perl_prepend_elem(pTHX_ I32 type, OP *first, OP *last)
 
 /* Constructors */
 
+#ifdef PERL_MAD
+TOKEN *
+Perl_newTOKEN(pTHX_ I32 optype, YYSTYPE lval, MADPROP* madprop)
+{
+    TOKEN *tk;
+    Newxz(tk, 1, TOKEN);
+    tk->tk_type = (OPCODE)optype;
+    tk->tk_type = 12345;
+    tk->tk_lval = lval;
+    tk->tk_mad = madprop;
+    return tk;
+}
+
+void
+Perl_token_free(pTHX_ TOKEN* tk)
+{
+    if (tk->tk_type != 12345)
+       return;
+    mad_free(tk->tk_mad);
+    Safefree(tk);
+}
+
+void
+Perl_token_getmad(pTHX_ TOKEN* tk, OP* o, char slot)
+{
+    MADPROP* mp;
+    MADPROP* tm;
+    if (tk->tk_type != 12345) {
+       Perl_warner(aTHX_ packWARN(WARN_MISC),
+            "Invalid TOKEN object ignored");
+       return;
+    }
+    tm = tk->tk_mad;
+    if (!tm)
+       return;
+
+    /* faked up qw list? */
+    if (slot == '(' &&
+       tm->mad_type == MAD_SV &&
+       SvPVX((SV*)tm->mad_val)[0] == 'q')
+           slot = 'x';
+
+    if (o) {
+       mp = o->op_madprop;
+       if (mp) {
+           for (;;) {
+               /* pretend constant fold didn't happen? */
+               if (mp->mad_key == 'f' &&
+                   (o->op_type == OP_CONST ||
+                    o->op_type == OP_GV) )
+               {
+                   token_getmad(tk,(OP*)mp->mad_val,slot);
+                   return;
+               }
+               if (!mp->mad_next)
+                   break;
+               mp = mp->mad_next;
+           }
+           mp->mad_next = tm;
+           mp = mp->mad_next;
+       }
+       else {
+           o->op_madprop = tm;
+           mp = o->op_madprop;
+       }
+       if (mp->mad_key == 'X')
+           mp->mad_key = slot; /* just change the first one */
+
+       tk->tk_mad = 0;
+    }
+    else
+       mad_free(tm);
+    Safefree(tk);
+}
+
+void
+Perl_op_getmad_weak(pTHX_ OP* from, OP* o, char slot)
+{
+    MADPROP* mp;
+    if (!from)
+       return;
+    if (o) {
+       mp = o->op_madprop;
+       if (mp) {
+           for (;;) {
+               /* pretend constant fold didn't happen? */
+               if (mp->mad_key == 'f' &&
+                   (o->op_type == OP_CONST ||
+                    o->op_type == OP_GV) )
+               {
+                   op_getmad(from,(OP*)mp->mad_val,slot);
+                   return;
+               }
+               if (!mp->mad_next)
+                   break;
+               mp = mp->mad_next;
+           }
+           mp->mad_next = newMADPROP(slot,MAD_OP,from,0);
+       }
+       else {
+           o->op_madprop = newMADPROP(slot,MAD_OP,from,0);
+       }
+    }
+}
+
+void
+Perl_op_getmad(pTHX_ OP* from, OP* o, char slot)
+{
+    MADPROP* mp;
+    if (!from)
+       return;
+    if (o) {
+       mp = o->op_madprop;
+       if (mp) {
+           for (;;) {
+               /* pretend constant fold didn't happen? */
+               if (mp->mad_key == 'f' &&
+                   (o->op_type == OP_CONST ||
+                    o->op_type == OP_GV) )
+               {
+                   op_getmad(from,(OP*)mp->mad_val,slot);
+                   return;
+               }
+               if (!mp->mad_next)
+                   break;
+               mp = mp->mad_next;
+           }
+           mp->mad_next = newMADPROP(slot,MAD_OP,from,1);
+       }
+       else {
+           o->op_madprop = newMADPROP(slot,MAD_OP,from,1);
+       }
+    }
+    else {
+       PerlIO_printf(PerlIO_stderr(),
+                     "DESTROYING op = %0"UVxf"\n", PTR2UV(from));
+       op_free(from);
+    }
+}
+
+void
+Perl_prepend_madprops(pTHX_ MADPROP* mp, OP* o, char slot)
+{
+    MADPROP* tm;
+    if (!mp || !o)
+       return;
+    if (slot)
+       mp->mad_key = slot;
+    tm = o->op_madprop;
+    o->op_madprop = mp;
+    for (;;) {
+       if (!mp->mad_next)
+           break;
+       mp = mp->mad_next;
+    }
+    mp->mad_next = tm;
+}
+
+void
+Perl_append_madprops(pTHX_ MADPROP* tm, OP* o, char slot)
+{
+    if (!o)
+       return;
+    addmad(tm, &(o->op_madprop), slot);
+}
+
+void
+Perl_addmad(pTHX_ MADPROP* tm, MADPROP** root, char slot)
+{
+    MADPROP* mp;
+    if (!tm || !root)
+       return;
+    if (slot)
+       tm->mad_key = slot;
+    mp = *root;
+    if (!mp) {
+       *root = tm;
+       return;
+    }
+    for (;;) {
+       if (!mp->mad_next)
+           break;
+       mp = mp->mad_next;
+    }
+    mp->mad_next = tm;
+}
+
+MADPROP *
+Perl_newMADsv(pTHX_ char key, SV* sv)
+{
+    return newMADPROP(key, MAD_SV, sv, 0);
+}
+
+MADPROP *
+Perl_newMADPROP(pTHX_ char key, char type, void* val, I32 vlen)
+{
+    MADPROP *mp;
+    Newxz(mp, 1, MADPROP);
+    mp->mad_next = 0;
+    mp->mad_key = key;
+    mp->mad_vlen = vlen;
+    mp->mad_type = type;
+    mp->mad_val = val;
+/*    PerlIO_printf(PerlIO_stderr(), "NEW  mp = %0x\n", mp);  */
+    return mp;
+}
+
+void
+Perl_mad_free(pTHX_ MADPROP* mp)
+{
+/*    PerlIO_printf(PerlIO_stderr(), "FREE mp = %0x\n", mp); */
+    if (!mp)
+       return;
+    if (mp->mad_next)
+       mad_free(mp->mad_next);
+/*    if (PL_parser && PL_parser->lex_state != LEX_NOTPARSING && mp->mad_vlen)
+       PerlIO_printf(PerlIO_stderr(), "DESTROYING '%c'=<%s>\n", mp->mad_key & 255, mp->mad_val); */
+    switch (mp->mad_type) {
+    case MAD_NULL:
+       break;
+    case MAD_PV:
+       Safefree((char*)mp->mad_val);
+       break;
+    case MAD_OP:
+       if (mp->mad_vlen)       /* vlen holds "strong/weak" boolean */
+           op_free((OP*)mp->mad_val);
+       break;
+    case MAD_SV:
+       sv_free((SV*)mp->mad_val);
+       break;
+    default:
+       PerlIO_printf(PerlIO_stderr(), "Unrecognized mad\n");
+       break;
+    }
+    Safefree(mp);
+}
+
+#endif
+
 OP *
 Perl_newNULLLIST(pTHX)
 {
@@ -2286,7 +2865,7 @@ OP *
 Perl_force_list(pTHX_ OP *o)
 {
     if (!o || o->op_type != OP_LIST)
-       o = newLISTOP(OP_LIST, 0, o, Nullop);
+       o = newLISTOP(OP_LIST, 0, o, NULL);
     op_null(o);
     return o;
 }
@@ -2334,6 +2913,9 @@ Perl_newOP(pTHX_ I32 type, I32 flags)
     o->op_type = (OPCODE)type;
     o->op_ppaddr = PL_ppaddr[type];
     o->op_flags = (U8)flags;
+    o->op_latefree = 0;
+    o->op_latefreed = 0;
+    o->op_attached = 0;
 
     o->op_next = o;
     o->op_private = (U8)(0 | (flags >> 8));
@@ -2400,7 +2982,10 @@ Perl_newBINOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
     return fold_constants((OP *)binop);
 }
 
-static int uvcompare(const void *a, const void *b) __attribute__nonnull__(1) __attribute__nonnull__(2) __attribute__pure__;
+static int uvcompare(const void *a, const void *b)
+    __attribute__nonnull__(1)
+    __attribute__nonnull__(2)
+    __attribute__pure__;
 static int uvcompare(const void *a, const void *b)
 {
     if (*((const UV *)a) < (*(const UV *)b))
@@ -2419,7 +3004,12 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
 {
     dVAR;
     SV * const tstr = ((SVOP*)expr)->op_sv;
-    SV * const rstr = ((SVOP*)repl)->op_sv;
+    SV * const rstr =
+#ifdef PERL_MAD
+                       (repl->op_type == OP_NULL)
+                           ? ((SVOP*)((LISTOP*)repl)->op_first)->op_sv :
+#endif
+                             ((SVOP*)repl)->op_sv;
     STRLEN tlen;
     STRLEN rlen;
     const U8 *t = (U8*)SvPV_const(tstr, tlen);
@@ -2432,6 +3022,7 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
     const I32 complement = o->op_private & OPpTRANS_COMPLEMENT;
     const I32 squash     = o->op_private & OPpTRANS_SQUASH;
     I32 del              = o->op_private & OPpTRANS_DELETE;
+    SV* swash;
     PL_hints |= HINT_BLOCK_SCOPE;
 
     if (SvUTF8(tstr))
@@ -2462,6 +3053,7 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
        const I32 to_utf    = o->op_private & OPpTRANS_TO_UTF;
        U8* tsave = NULL;
        U8* rsave = NULL;
+       const U32 flags = UTF8_ALLOW_DEFAULT;
 
        if (!from_utf) {
            STRLEN len = tlen;
@@ -2488,11 +3080,11 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
            i = 0;
            transv = newSVpvs("");
            while (t < tend) {
-               cp[2*i] = utf8n_to_uvuni(t, tend-t, &ulen, 0);
+               cp[2*i] = utf8n_to_uvuni(t, tend-t, &ulen, flags);
                t += ulen;
                if (t < tend && NATIVE_TO_UTF(*t) == 0xff) {
                    t++;
-                   cp[2*i+1] = utf8n_to_uvuni(t, tend-t, &ulen, 0);
+                   cp[2*i+1] = utf8n_to_uvuni(t, tend-t, &ulen, flags);
                    t += ulen;
                }
                else {
@@ -2546,11 +3138,11 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
        while (t < tend || tfirst <= tlast) {
            /* see if we need more "t" chars */
            if (tfirst > tlast) {
-               tfirst = (I32)utf8n_to_uvuni(t, tend - t, &ulen, 0);
+               tfirst = (I32)utf8n_to_uvuni(t, tend - t, &ulen, flags);
                t += ulen;
                if (t < tend && NATIVE_TO_UTF(*t) == 0xff) {    /* illegal utf8 val indicates range */
                    t++;
-                   tlast = (I32)utf8n_to_uvuni(t, tend - t, &ulen, 0);
+                   tlast = (I32)utf8n_to_uvuni(t, tend - t, &ulen, flags);
                    t += ulen;
                }
                else
@@ -2560,11 +3152,11 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
            /* now see if we need more "r" chars */
            if (rfirst > rlast) {
                if (r < rend) {
-                   rfirst = (I32)utf8n_to_uvuni(r, rend - r, &ulen, 0);
+                   rfirst = (I32)utf8n_to_uvuni(r, rend - r, &ulen, flags);
                    r += ulen;
                    if (r < rend && NATIVE_TO_UTF(*r) == 0xff) {        /* illegal utf8 val indicates range */
                        r++;
-                       rlast = (I32)utf8n_to_uvuni(r, rend - r, &ulen, 0);
+                       rlast = (I32)utf8n_to_uvuni(r, rend - r, &ulen, flags);
                        r += ulen;
                    }
                    else
@@ -2624,26 +3216,38 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
        else
            bits = 8;
 
-       Safefree(cPVOPo->op_pv);
-       cSVOPo->op_sv = (SV*)swash_init("utf8", "", listsv, bits, none);
+       PerlMemShared_free(cPVOPo->op_pv);
+       cPVOPo->op_pv = NULL;
+
+       swash = (SV*)swash_init("utf8", "", listsv, bits, none);
+#ifdef USE_ITHREADS
+       cPADOPo->op_padix = pad_alloc(OP_TRANS, SVs_PADTMP);
+       SvREFCNT_dec(PAD_SVl(cPADOPo->op_padix));
+       PAD_SETSV(cPADOPo->op_padix, swash);
+       SvPADTMP_on(swash);
+#else
+       cSVOPo->op_sv = swash;
+#endif
        SvREFCNT_dec(listsv);
-       if (transv)
-           SvREFCNT_dec(transv);
+       SvREFCNT_dec(transv);
 
        if (!del && havefinal && rlen)
-           (void)hv_store((HV*)SvRV((cSVOPo->op_sv)), "FINAL", 5,
+           (void)hv_store((HV*)SvRV(swash), "FINAL", 5,
                           newSVuv((UV)final), 0);
 
        if (grows)
            o->op_private |= OPpTRANS_GROWS;
 
-       if (tsave)
-           Safefree(tsave);
-       if (rsave)
-           Safefree(rsave);
+       Safefree(tsave);
+       Safefree(rsave);
 
+#ifdef PERL_MAD
+       op_getmad(expr,o,'e');
+       op_getmad(repl,o,'r');
+#else
        op_free(expr);
        op_free(repl);
+#endif
        return o;
     }
 
@@ -2677,8 +3281,13 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
            }
            else if (j >= (I32)rlen)
                j = rlen - 1;
-           else
-               cPVOPo->op_pv = (char*)Renew(tbl, 0x101+rlen-j, short);
+           else {
+               tbl = 
+                   (short *)
+                   PerlMemShared_realloc(tbl,
+                                         (0x101+rlen-j) * sizeof(short));
+               cPVOPo->op_pv = (char*)tbl;
+           }
            tbl[0x100] = (short)(rlen - j);
            for (i=0; i < (I32)rlen - j; i++)
                tbl[0x101+i] = r[j+i];
@@ -2713,8 +3322,13 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
     }
     if (grows)
        o->op_private |= OPpTRANS_GROWS;
+#ifdef PERL_MAD
+    op_getmad(expr,o,'e');
+    op_getmad(repl,o,'r');
+#else
     op_free(expr);
     op_free(repl);
+#endif
 
     return o;
 }
@@ -2732,10 +3346,10 @@ Perl_newPMOP(pTHX_ I32 type, I32 flags)
     pmop->op_private = (U8)(0 | (flags >> 8));
 
     if (PL_hints & HINT_RE_TAINT)
-       pmop->op_pmpermflags |= PMf_RETAINT;
+       pmop->op_pmflags |= PMf_RETAINT;
     if (PL_hints & HINT_LOCALE)
-       pmop->op_pmpermflags |= PMf_LOCALE;
-    pmop->op_pmflags = pmop->op_pmpermflags;
+       pmop->op_pmflags |= PMf_LOCALE;
+
 
 #ifdef USE_ITHREADS
     if (av_len((AV*) PL_regex_pad[0]) > -1) {
@@ -2745,24 +3359,12 @@ Perl_newPMOP(pTHX_ I32 type, I32 flags)
        sv_setiv(repointer,0);
     } else {
        SV * const repointer = newSViv(0);
-       av_push(PL_regex_padav,SvREFCNT_inc(repointer));
+       av_push(PL_regex_padav, SvREFCNT_inc_simple_NN(repointer));
        pmop->op_pmoffset = av_len(PL_regex_padav);
        PL_regex_pad = AvARRAY(PL_regex_padav);
     }
 #endif
 
-        /* link into pm list */
-    if (type != OP_TRANS && PL_curstash) {
-       MAGIC *mg = mg_find((SV*)PL_curstash, PERL_MAGIC_symtab);
-
-       if (!mg) {
-           mg = sv_magicext((SV*)PL_curstash, 0, PERL_MAGIC_symtab, 0, 0, 0);
-       }
-       pmop->op_pmnext = (PMOP*)mg->mg_obj;
-       mg->mg_obj = (SV*)pmop;
-       PmopSTASH_set(pmop,PL_curstash);
-    }
-
     return CHECKOP(type, pmop);
 }
 
@@ -2785,7 +3387,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
     PMOP *pm;
     LOGOP *rcop;
     I32 repl_has_vars = 0;
-    OP* repl  = Nullop;
+    OP* repl = NULL;
     bool reglist;
 
     if (o->op_type == OP_SUBST || o->op_type == OP_TRANS) {
@@ -2795,7 +3397,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
        kid = cLISTOPx(expr)->op_first;
        while (kid->op_sibling != repl)
            kid = kid->op_sibling;
-       kid->op_sibling = Nullop;
+       kid->op_sibling = NULL;
        cLISTOPx(expr)->op_last = kid;
     }
 
@@ -2805,8 +3407,8 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
        /* convert single element list to element */
        OP* const oe = expr;
        expr = cLISTOPx(oe)->op_first->op_sibling;
-       cLISTOPx(oe)->op_first->op_sibling = Nullop;
-       cLISTOPx(oe)->op_last = Nullop;
+       cLISTOPx(oe)->op_first->op_sibling = NULL;
+       cLISTOPx(oe)->op_last = NULL;
        op_free(oe);
     }
 
@@ -2822,36 +3424,22 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
     pm = (PMOP*)o;
 
     if (expr->op_type == OP_CONST) {
-       STRLEN plen;
        SV * const pat = ((SVOP*)expr)->op_sv;
-       const char *p = SvPV_const(pat, plen);
-       if ((o->op_flags & OPf_SPECIAL) && (*p == ' ' && p[1] == '\0')) {
-           U32 was_readonly = SvREADONLY(pat);
+       U32 pm_flags = pm->op_pmflags & PMf_COMPILETIME;
 
-           if (was_readonly) {
-               if (SvFAKE(pat)) {
-                   sv_force_normal_flags(pat, 0);
-                   assert(!SvREADONLY(pat));
-                   was_readonly = 0;
-               } else {
-                   SvREADONLY_off(pat);
-               }
-           }   
+       if (o->op_flags & OPf_SPECIAL)
+           pm_flags |= RXf_SPLIT;
 
-           sv_setpvn(pat, "\\s+", 3);
+       if (DO_UTF8(pat))
+           pm_flags |= RXf_UTF8;
 
-           SvFLAGS(pat) |= was_readonly;
+       PM_SETRE(pm, CALLREGCOMP(pat, pm_flags));
 
-           p = SvPV_const(pat, plen);
-           pm->op_pmflags |= PMf_SKIPWHITE;
-       }
-        if (DO_UTF8(pat))
-           pm->op_pmdynflags |= PMdf_UTF8;
-       /* FIXME - can we make this function take const char * args?  */
-       PM_SETRE(pm, CALLREGCOMP(aTHX_ (char*)p, (char*)p + plen, pm));
-       if (strEQ("\\s+", PM_GETRE(pm)->precomp))
-           pm->op_pmflags |= PMf_WHITE;
+#ifdef PERL_MAD
+       op_getmad(expr,(OP*)pm,'e');
+#else
        op_free(expr);
+#endif
     }
     else {
        if (pm->op_pmflags & PMf_KEEP || !(PL_hints & HINT_RE_EVAL))
@@ -2892,15 +3480,17 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
        OP *curop;
        if (pm->op_pmflags & PMf_EVAL) {
            curop = NULL;
-           if (CopLINE(PL_curcop) < (line_t)PL_multi_end)
-               CopLINE_set(PL_curcop, (line_t)PL_multi_end);
+           if (CopLINE(PL_curcop) < (line_t)PL_parser->multi_end)
+               CopLINE_set(PL_curcop, (line_t)PL_parser->multi_end);
        }
        else if (repl->op_type == OP_CONST)
            curop = repl;
        else {
            OP *lastop = NULL;
            for (curop = LINKLIST(repl); curop!=repl; curop = LINKLIST(curop)) {
-               if (PL_opargs[curop->op_type] & OA_DANGEROUS) {
+               if (curop->op_type == OP_SCOPE
+                       || curop->op_type == OP_LEAVE
+                       || (PL_opargs[curop->op_type] & OA_DANGEROUS)) {
                    if (curop->op_type == OP_GV) {
                        GV * const gv = cGVOPx_gv(curop);
                        repl_has_vars = 1;
@@ -2919,11 +3509,12 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
                    else if (curop->op_type == OP_PADSV ||
                             curop->op_type == OP_PADAV ||
                             curop->op_type == OP_PADHV ||
-                            curop->op_type == OP_PADANY) {
+                            curop->op_type == OP_PADANY)
+                   {
                        repl_has_vars = 1;
                    }
                    else if (curop->op_type == OP_PUSHRE)
-                       ; /* Okay here, dangerous in newASSIGNOP */
+                       NOOP; /* Okay here, dangerous in newASSIGNOP */
                    else
                        break;
                }
@@ -2933,15 +3524,14 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
        if (curop == repl
            && !(repl_has_vars
                 && (!PM_GETRE(pm)
-                    || PM_GETRE(pm)->reganch & ROPT_EVAL_SEEN))) {
+                    || PM_GETRE(pm)->extflags & RXf_EVAL_SEEN)))
+       {
            pm->op_pmflags |= PMf_CONST;        /* const for long enough */
-           pm->op_pmpermflags |= PMf_CONST;    /* const for long enough */
            prepend_elem(o->op_type, scalar(repl), o);
        }
        else {
            if (curop == repl && !PM_GETRE(pm)) { /* Has variables. */
                pm->op_pmflags |= PMf_MAYBE_CONST;
-               pm->op_pmpermflags |= PMf_MAYBE_CONST;
            }
            NewOp(1101, rcop, 1, LOGOP);
            rcop->op_type = OP_SUBSTCONT;
@@ -2955,8 +3545,9 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
            rcop->op_next = LINKLIST(repl);
            repl->op_next = (OP*)rcop;
 
-           pm->op_pmreplroot = scalar((OP*)rcop);
-           pm->op_pmreplstart = LINKLIST(rcop);
+           pm->op_pmreplrootu.op_pmreplroot = scalar((OP*)rcop);
+           assert(!(pm->op_pmflags & PMf_ONCE));
+           pm->op_pmstashstartu.op_pmreplstart = LINKLIST(rcop);
            rcop->op_next = 0;
        }
     }
@@ -2982,6 +3573,7 @@ Perl_newSVOP(pTHX_ I32 type, I32 flags, SV *sv)
     return CHECKOP(type, svop);
 }
 
+#ifdef USE_ITHREADS
 OP *
 Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
 {
@@ -2993,8 +3585,8 @@ Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
     padop->op_padix = pad_alloc(type, SVs_PADTMP);
     SvREFCNT_dec(PAD_SVl(padop->op_padix));
     PAD_SETSV(padop->op_padix, sv);
-    if (sv)
-       SvPADTMP_on(sv);
+    assert(sv);
+    SvPADTMP_on(sv);
     padop->op_next = (OP*)padop;
     padop->op_flags = (U8)flags;
     if (PL_opargs[type] & OA_RETSCALAR)
@@ -3003,17 +3595,18 @@ Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
        padop->op_targ = pad_alloc(type, SVs_PADTMP);
     return CHECKOP(type, padop);
 }
+#endif
 
 OP *
 Perl_newGVOP(pTHX_ I32 type, I32 flags, GV *gv)
 {
     dVAR;
+    assert(gv);
 #ifdef USE_ITHREADS
-    if (gv)
-       GvIN_PAD_on(gv);
-    return newPADOP(type, flags, SvREFCNT_inc(gv));
+    GvIN_PAD_on(gv);
+    return newPADOP(type, flags, SvREFCNT_inc_simple_NN(gv));
 #else
-    return newSVOP(type, flags, SvREFCNT_inc(gv));
+    return newSVOP(type, flags, SvREFCNT_inc_simple_NN(gv));
 #endif
 }
 
@@ -3035,42 +3628,72 @@ Perl_newPVOP(pTHX_ I32 type, I32 flags, char *pv)
     return CHECKOP(type, pvop);
 }
 
+#ifdef PERL_MAD
+OP*
+#else
 void
+#endif
 Perl_package(pTHX_ OP *o)
 {
     dVAR;
-    const char *name;
-    STRLEN len;
+    SV *const sv = cSVOPo->op_sv;
+#ifdef PERL_MAD
+    OP *pegop;
+#endif
 
     save_hptr(&PL_curstash);
     save_item(PL_curstname);
 
-    name = SvPV_const(cSVOPo->op_sv, len);
-    PL_curstash = gv_stashpvn(name, len, TRUE);
-    sv_setpvn(PL_curstname, name, len);
-    op_free(o);
+    PL_curstash = gv_stashsv(sv, GV_ADD);
+
+    sv_setsv(PL_curstname, sv);
 
     PL_hints |= HINT_BLOCK_SCOPE;
-    PL_copline = NOLINE;
-    PL_expect = XSTATE;
+    PL_parser->copline = NOLINE;
+    PL_parser->expect = XSTATE;
+
+#ifndef PERL_MAD
+    op_free(o);
+#else
+    if (!PL_madskills) {
+       op_free(o);
+       return NULL;
+    }
+
+    pegop = newOP(OP_NULL,0);
+    op_getmad(o,pegop,'P');
+    return pegop;
+#endif
 }
 
+#ifdef PERL_MAD
+OP*
+#else
 void
+#endif
 Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *idop, OP *arg)
 {
     dVAR;
     OP *pack;
     OP *imop;
     OP *veop;
+#ifdef PERL_MAD
+    OP *pegop = newOP(OP_NULL,0);
+#endif
 
     if (idop->op_type != OP_CONST)
        Perl_croak(aTHX_ "Module name must be constant");
 
-    veop = Nullop;
+    if (PL_madskills)
+       op_getmad(idop,pegop,'U');
+
+    veop = NULL;
 
     if (version) {
        SV * const vesv = ((SVOP*)version)->op_sv;
 
+       if (PL_madskills)
+           op_getmad(version,pegop,'V');
        if (!arg && !SvNIOKp(vesv)) {
            arg = version;
        }
@@ -3094,16 +3717,22 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *idop, OP *arg)
     }
 
     /* Fake up an import/unimport */
-    if (arg && arg->op_type == OP_STUB)
+    if (arg && arg->op_type == OP_STUB) {
+       if (PL_madskills)
+           op_getmad(arg,pegop,'S');
        imop = arg;             /* no import on explicit () */
+    }
     else if (SvNIOKp(((SVOP*)idop)->op_sv)) {
-       imop = Nullop;          /* use 5.0; */
+       imop = NULL;            /* use 5.0; */
        if (!aver)
            idop->op_private |= OPpCONST_NOVER;
     }
     else {
        SV *meth;
 
+       if (PL_madskills)
+           op_getmad(arg,pegop,'A');
+
        /* Make copy of idop so we don't free it twice */
        pack = newSVOP(OP_CONST, 0, newSVsv(((SVOP*)idop)->op_sv));
 
@@ -3119,8 +3748,8 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *idop, OP *arg)
     /* Fake up the BEGIN {}, which does its thing immediately. */
     newATTRSUB(floor,
        newSVOP(OP_CONST, 0, newSVpvs_share("BEGIN")),
-       Nullop,
-       Nullop,
+       NULL,
+       NULL,
        append_elem(OP_LINESEQ,
            append_elem(OP_LINESEQ,
                newSTATEOP(0, NULL, newUNOP(OP_REQUIRE, 0, idop)),
@@ -3145,9 +3774,18 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *idop, OP *arg)
      */
 
     PL_hints |= HINT_BLOCK_SCOPE;
-    PL_copline = NOLINE;
-    PL_expect = XSTATE;
+    PL_parser->copline = NOLINE;
+    PL_parser->expect = XSTATE;
     PL_cop_seqmax++; /* Purely for B::*'s benefit */
+
+#ifdef PERL_MAD
+    if (!PL_madskills) {
+       /* FIXME - don't allocate pegop if !PL_madskills */
+       op_free(pegop);
+       return NULL;
+    }
+    return pegop;
+#endif
 }
 
 /*
@@ -3199,7 +3837,7 @@ Perl_vload_module(pTHX_ U32 flags, SV *name, SV *ver, va_list *args)
        veop = newSVOP(OP_CONST, 0, ver);
     }
     else
-       veop = Nullop;
+       veop = NULL;
     if (flags & PERL_LOADMOD_NOIMPORT) {
        imop = sawparens(newNULLLIST());
     }
@@ -3208,24 +3846,26 @@ Perl_vload_module(pTHX_ U32 flags, SV *name, SV *ver, va_list *args)
     }
     else {
        SV *sv;
-       imop = Nullop;
+       imop = NULL;
        sv = va_arg(*args, SV*);
        while (sv) {
            imop = append_elem(OP_LIST, imop, newSVOP(OP_CONST, 0, sv));
            sv = va_arg(*args, SV*);
        }
     }
-    {
-       const line_t ocopline = PL_copline;
-       COP * const ocurcop = PL_curcop;
-       const int oexpect = PL_expect;
 
-       utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0),
-               veop, modname, imop);
-       PL_expect = oexpect;
-       PL_copline = ocopline;
-       PL_curcop = ocurcop;
-    }
+    /* utilize() fakes up a BEGIN { require ..; import ... }, so make sure
+     * that it has a PL_parser to play with while doing that, and also
+     * that it doesn't mess with any existing parser, by creating a tmp
+     * new parser with lex_start(). This won't actually be used for much,
+     * since pp_require() will create another parser for the real work. */
+
+    ENTER;
+    SAVEVPTR(PL_curcop);
+    lex_start(NULL, NULL, FALSE);
+    utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0),
+           veop, modname, imop);
+    LEAVE;
 }
 
 OP *
@@ -3233,13 +3873,13 @@ Perl_dofile(pTHX_ OP *term, I32 force_builtin)
 {
     dVAR;
     OP *doop;
-    GV *gv = Nullgv;
+    GV *gv = NULL;
 
     if (!force_builtin) {
        gv = gv_fetchpvs("do", GV_NOTQUAL, SVt_PVCV);
        if (!(gv && GvCVu(gv) && GvIMPORTED_CV(gv))) {
            GV * const * const gvp = (GV**)hv_fetchs(PL_globalstash, "do", FALSE);
-           gv = gvp ? *gvp : Nullgv;
+           gv = gvp ? *gvp : NULL;
        }
     }
 
@@ -3247,8 +3887,7 @@ Perl_dofile(pTHX_ OP *term, I32 force_builtin)
        doop = ck_subr(newUNOP(OP_ENTERSUB, OPf_STACKED,
                               append_elem(OP_LIST, term,
                                           scalar(newUNOP(OP_RV2CV, 0,
-                                                         newGVOP(OP_GV, 0,
-                                                                 gv))))));
+                                                         newGVOP(OP_GV, 0, gv))))));
     }
     else {
        doop = newUNOP(OP_DOFILE, 0, scalar(term));
@@ -3267,13 +3906,18 @@ Perl_newSLICEOP(pTHX_ I32 flags, OP *subscript, OP *listval)
 STATIC I32
 S_is_list_assignment(pTHX_ register const OP *o)
 {
+    unsigned type;
+    U8 flags;
+
     if (!o)
        return TRUE;
 
-    if (o->op_type == OP_NULL && o->op_flags & OPf_KIDS)
+    if ((o->op_type == OP_NULL) && (o->op_flags & OPf_KIDS))
        o = cUNOPo->op_first;
 
-    if (o->op_type == OP_COND_EXPR) {
+    flags = o->op_flags;
+    type = o->op_type;
+    if (type == OP_COND_EXPR) {
         const I32 t = is_list_assignment(cLOGOPo->op_first->op_sibling);
         const I32 f = is_list_assignment(cLOGOPo->op_first->op_sibling->op_sibling);
 
@@ -3284,20 +3928,20 @@ S_is_list_assignment(pTHX_ register const OP *o)
        return FALSE;
     }
 
-    if (o->op_type == OP_LIST &&
-       (o->op_flags & OPf_WANT) == OPf_WANT_SCALAR &&
+    if (type == OP_LIST &&
+       (flags & OPf_WANT) == OPf_WANT_SCALAR &&
        o->op_private & OPpLVAL_INTRO)
        return FALSE;
 
-    if (o->op_type == OP_LIST || o->op_flags & OPf_PARENS ||
-       o->op_type == OP_RV2AV || o->op_type == OP_RV2HV ||
-       o->op_type == OP_ASLICE || o->op_type == OP_HSLICE)
+    if (type == OP_LIST || flags & OPf_PARENS ||
+       type == OP_RV2AV || type == OP_RV2HV ||
+       type == OP_ASLICE || type == OP_HSLICE)
        return TRUE;
 
-    if (o->op_type == OP_PADAV || o->op_type == OP_PADHV)
+    if (type == OP_PADAV || type == OP_PADHV)
        return TRUE;
 
-    if (o->op_type == OP_RV2SV)
+    if (type == OP_RV2SV)
        return FALSE;
 
     return FALSE;
@@ -3332,6 +3976,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
        if (PL_eval_start)
            PL_eval_start = 0;
        else if (left->op_type == OP_CONST) {
+           /* FIXME for MAD */
            /* Result of assignment is always 1 (or we'd be dead already) */
            return newSVOP(OP_CONST, 0, newSViv(1));
        }
@@ -3350,19 +3995,20 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
         * that value, we know we've got commonality.  We could use a
         * single bit marker, but then we'd have to make 2 passes, first
         * to clear the flag, then to test and set it.  To find somewhere
-        * to store these values, evil chicanery is done with SvCUR().
+        * to store these values, evil chicanery is done with SvUVX().
         */
 
-       if (!(left->op_private & OPpLVAL_INTRO)) {
+       {
            OP *lastop = o;
            PL_generation++;
            for (curop = LINKLIST(o); curop != o; curop = LINKLIST(curop)) {
                if (PL_opargs[curop->op_type] & OA_DANGEROUS) {
                    if (curop->op_type == OP_GV) {
                        GV *gv = cGVOPx_gv(curop);
-                       if (gv == PL_defgv || (int)SvCUR(gv) == PL_generation)
+                       if (gv == PL_defgv
+                           || (int)GvASSIGN_GENERATION(gv) == PL_generation)
                            break;
-                       SvCUR_set(gv, PL_generation);
+                       GvASSIGN_GENERATION_set(gv, PL_generation);
                    }
                    else if (curop->op_type == OP_PADSV ||
                             curop->op_type == OP_PADAV ||
@@ -3385,17 +4031,24 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                            break;
                    }
                    else if (curop->op_type == OP_PUSHRE) {
-                       if (((PMOP*)curop)->op_pmreplroot) {
 #ifdef USE_ITHREADS
-                           GV *gv = (GV*)PAD_SVl(INT2PTR(PADOFFSET,
-                                       ((PMOP*)curop)->op_pmreplroot));
+                       if (((PMOP*)curop)->op_pmreplrootu.op_pmtargetoff) {
+                           GV *const gv = (GV*)PAD_SVl(((PMOP*)curop)->op_pmreplrootu.op_pmtargetoff);
+                           if (gv == PL_defgv
+                               || (int)GvASSIGN_GENERATION(gv) == PL_generation)
+                               break;
+                           GvASSIGN_GENERATION_set(gv, PL_generation);
+                       }
 #else
-                           GV *gv = (GV*)((PMOP*)curop)->op_pmreplroot;
-#endif
-                           if (gv == PL_defgv || (int)SvCUR(gv) == PL_generation)
+                       GV *const gv
+                           = ((PMOP*)curop)->op_pmreplrootu.op_pmtargetgv;
+                       if (gv) {
+                           if (gv == PL_defgv
+                               || (int)GvASSIGN_GENERATION(gv) == PL_generation)
                                break;
-                           SvCUR_set(gv, PL_generation);
+                           GvASSIGN_GENERATION_set(gv, PL_generation);
                        }
+#endif
                    }
                    else
                        break;
@@ -3405,29 +4058,36 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
            if (curop != o)
                o->op_private |= OPpASSIGN_COMMON;
        }
-       if (right && right->op_type == OP_SPLIT) {
-           OP* tmpop;
-           if ((tmpop = ((LISTOP*)right)->op_first) &&
-               tmpop->op_type == OP_PUSHRE)
-           {
+
+       if (right && right->op_type == OP_SPLIT && !PL_madskills) {
+           OP* tmpop = ((LISTOP*)right)->op_first;
+           if (tmpop && (tmpop->op_type == OP_PUSHRE)) {
                PMOP * const pm = (PMOP*)tmpop;
                if (left->op_type == OP_RV2AV &&
                    !(left->op_private & OPpLVAL_INTRO) &&
                    !(o->op_private & OPpASSIGN_COMMON) )
                {
                    tmpop = ((UNOP*)left)->op_first;
-                   if (tmpop->op_type == OP_GV && !pm->op_pmreplroot) {
+                   if (tmpop->op_type == OP_GV
 #ifdef USE_ITHREADS
-                       pm->op_pmreplroot = INT2PTR(OP*, cPADOPx(tmpop)->op_padix);
+                       && !pm->op_pmreplrootu.op_pmtargetoff
+#else
+                       && !pm->op_pmreplrootu.op_pmtargetgv
+#endif
+                       ) {
+#ifdef USE_ITHREADS
+                       pm->op_pmreplrootu.op_pmtargetoff
+                           = cPADOPx(tmpop)->op_padix;
                        cPADOPx(tmpop)->op_padix = 0;   /* steal it */
 #else
-                       pm->op_pmreplroot = (OP*)cSVOPx(tmpop)->op_sv;
-                       cSVOPx(tmpop)->op_sv = Nullsv;  /* steal it */
+                       pm->op_pmreplrootu.op_pmtargetgv
+                           = (GV*)cSVOPx(tmpop)->op_sv;
+                       cSVOPx(tmpop)->op_sv = NULL;    /* steal it */
 #endif
                        pm->op_pmflags |= PMf_ONCE;
                        tmpop = cUNOPo->op_first;       /* to list (nulled) */
                        tmpop = ((UNOP*)tmpop)->op_first; /* to pushmark */
-                       tmpop->op_sibling = Nullop;     /* don't free split */
+                       tmpop->op_sibling = NULL;       /* don't free split */
                        right->op_next = tmpop->op_next;  /* fix starting loc */
                        op_free(o);                     /* blow off assign */
                        right->op_flags &= ~OPf_WANT;
@@ -3461,7 +4121,10 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
        if (PL_eval_start)
            PL_eval_start = 0;
        else {
-           o = newSVOP(OP_CONST, 0, newSViv(PL_compiling.cop_arybase));
+           /* FIXME for MAD */
+           op_free(o);
+           o = newSVOP(OP_CONST, 0, newSViv(CopARYBASE_get(&PL_compiling)));
+           o->op_private |= OPpCONST_ARYBASE;
        }
     }
     return o;
@@ -3484,34 +4147,35 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o)
        cop->op_ppaddr = PL_ppaddr[ OP_NEXTSTATE ];
     }
     cop->op_flags = (U8)flags;
-    cop->op_private = (U8)(PL_hints & HINT_PRIVATE_MASK);
+    CopHINTS_set(cop, PL_hints);
 #ifdef NATIVE_HINTS
     cop->op_private |= NATIVE_HINTS;
 #endif
-    PL_compiling.op_private = cop->op_private;
+    CopHINTS_set(&PL_compiling, CopHINTS_get(cop));
     cop->op_next = (OP*)cop;
 
     if (label) {
-       cop->cop_label = label;
+       CopLABEL_set(cop, label);
        PL_hints |= HINT_BLOCK_SCOPE;
     }
     cop->cop_seq = seq;
-    cop->cop_arybase = PL_curcop->cop_arybase;
-    if (specialWARN(PL_curcop->cop_warnings))
-        cop->cop_warnings = PL_curcop->cop_warnings ;
-    else
-        cop->cop_warnings = newSVsv(PL_curcop->cop_warnings) ;
-    if (specialCopIO(PL_curcop->cop_io))
-        cop->cop_io = PL_curcop->cop_io;
-    else
-        cop->cop_io = newSVsv(PL_curcop->cop_io) ;
-
-
-    if (PL_copline == NOLINE)
+    /* CopARYBASE is now "virtual", in that it's stored as a flag bit in
+       CopHINTS and a possible value in cop_hints_hash, so no need to copy it.
+    */
+    cop->cop_warnings = DUP_WARNINGS(PL_curcop->cop_warnings);
+    cop->cop_hints_hash = PL_curcop->cop_hints_hash;
+    if (cop->cop_hints_hash) {
+       HINTS_REFCNT_LOCK;
+       cop->cop_hints_hash->refcounted_he_refcnt++;
+       HINTS_REFCNT_UNLOCK;
+    }
+
+    if (PL_parser && PL_parser->copline == NOLINE)
         CopLINE_set(cop, CopLINE(PL_curcop));
     else {
-       CopLINE_set(cop, PL_copline);
-        PL_copline = NOLINE;
+       CopLINE_set(cop, PL_parser->copline);
+       if (PL_parser)
+           PL_parser->copline = NOLINE;
     }
 #ifdef USE_ITHREADS
     CopFILE_set(cop, CopFILE(PL_curcop));      /* XXX share in a pvtable? */
@@ -3521,10 +4185,13 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o)
     CopSTASH_set(cop, PL_curstash);
 
     if (PERLDB_LINE && PL_curstash != PL_debstash) {
-       SV * const * const svp = av_fetch(CopFILEAVx(PL_curcop), (I32)CopLINE(cop), FALSE);
-       if (svp && *svp != &PL_sv_undef ) {
-           (void)SvIOK_on(*svp);
-           SvIV_set(*svp, PTR2IV(cop));
+       AV *av = CopFILEAVx(PL_curcop);
+       if (av) {
+           SV * const * const svp = av_fetch(av, (I32)CopLINE(cop), FALSE);
+           if (svp && *svp != &PL_sv_undef ) {
+               (void)SvIOK_on(*svp);
+               SvIV_set(*svp, PTR2IV(cop));
+           }
        }
     }
 
@@ -3553,7 +4220,10 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
 
     scalarboolean(first);
     /* optimize "!a && b" to "a || b", and "!a || b" to "a && b" */
-    if (first->op_type == OP_NOT && (first->op_flags & OPf_SPECIAL)) {
+    if (first->op_type == OP_NOT
+       && (first->op_flags & OPf_SPECIAL)
+       && (first->op_flags & OPf_KIDS)
+       && !PL_madskills) {
        if (type == OP_AND || type == OP_OR) {
            if (type == OP_AND)
                type = OP_OR;
@@ -3563,7 +4233,7 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
            first = *firstp = cUNOPo->op_first;
            if (o->op_next)
                first->op_next = o->op_next;
-           cUNOPo->op_first = Nullop;
+           cUNOPo->op_first = NULL;
            op_free(o);
        }
     }
@@ -3575,10 +4245,16 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
        if ((type == OP_AND &&  SvTRUE(((SVOP*)first)->op_sv)) ||
            (type == OP_OR  && !SvTRUE(((SVOP*)first)->op_sv)) ||
            (type == OP_DOR && !SvOK(((SVOP*)first)->op_sv))) {
-           op_free(first);
-           *firstp = Nullop;
+           *firstp = NULL;
            if (other->op_type == OP_CONST)
                other->op_private |= OPpCONST_SHORTCIRCUIT;
+           if (PL_madskills) {
+               OP *newop = newUNOP(OP_NULL, 0, other);
+               op_getmad(first, newop, '1');
+               newop->op_targ = type;  /* set "was" field */
+               return newop;
+           }
+           op_free(first);
            return other;
        }
        else {
@@ -3599,10 +4275,16 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
                            "Deprecated use of my() in false conditional");
            }
 
-           op_free(other);
-           *otherp = Nullop;
+           *otherp = NULL;
            if (first->op_type == OP_CONST)
                first->op_private |= OPpCONST_SHORTCIRCUIT;
+           if (PL_madskills) {
+               first = newUNOP(OP_NULL, 0, first);
+               op_getmad(other, first, '2');
+               first->op_targ = type;  /* set "was" field */
+           }
+           else
+               op_free(other);
            return first;
        }
     }
@@ -3636,7 +4318,7 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
        }
        if (warnop) {
            const line_t oldline = CopLINE(PL_curcop);
-           CopLINE_set(PL_curcop, PL_copline);
+           CopLINE_set(PL_curcop, PL_parser->copline);
            Perl_warner(aTHX_ packWARN(WARN_MISC),
                 "Value of %s%s can be \"0\"; test with defined()",
                 PL_op_desc[warnop],
@@ -3689,20 +4371,24 @@ Perl_newCONDOP(pTHX_ I32 flags, OP *first, OP *trueop, OP *falseop)
 
     scalarboolean(first);
     if (first->op_type == OP_CONST) {
+       /* Left or right arm of the conditional?  */
+       const bool left = SvTRUE(((SVOP*)first)->op_sv);
+       OP *live = left ? trueop : falseop;
+       OP *const dead = left ? falseop : trueop;
         if (first->op_private & OPpCONST_BARE &&
            first->op_private & OPpCONST_STRICT) {
            no_bareword_allowed(first);
        }
-       if (SvTRUE(((SVOP*)first)->op_sv)) {
-           op_free(first);
-           op_free(falseop);
-           return trueop;
-       }
-       else {
+       if (PL_madskills) {
+           /* This is all dead code when PERL_MAD is not defined.  */
+           live = newUNOP(OP_NULL, 0, live);
+           op_getmad(first, live, 'C');
+           op_getmad(dead, live, left ? 'e' : 't');
+       } else {
            op_free(first);
-           op_free(trueop);
-           return falseop;
+           op_free(dead);
        }
+       return live;
     }
     NewOp(1101, logop, 1, LOGOP);
     logop->op_type = OP_COND_EXPR;
@@ -3807,10 +4493,10 @@ Perl_newLOOPOP(pTHX_ I32 flags, I32 debuggable, OP *expr, OP *block)
                break;
 
              case OP_SASSIGN:
-               if (k1->op_type == OP_READDIR
+               if (k1 && (k1->op_type == OP_READDIR
                      || k1->op_type == OP_GLOB
                      || (k1->op_type == OP_NULL && k1->op_targ == OP_GLOB)
-                     || k1->op_type == OP_EACH)
+                     || k1->op_type == OP_EACH))
                    expr = newUNOP(OP_DEFINED, 0, expr);
                break;
            }
@@ -3869,10 +4555,10 @@ whileline, OP *expr, OP *block, OP *cont, I32 has_my)
                break;
 
              case OP_SASSIGN:
-               if (k1->op_type == OP_READDIR
+               if (k1 && (k1->op_type == OP_READDIR
                      || k1->op_type == OP_GLOB
                      || (k1->op_type == OP_NULL && k1->op_targ == OP_GLOB)
-                     || k1->op_type == OP_EACH)
+                     || k1->op_type == OP_EACH))
                    expr = newUNOP(OP_DEFINED, 0, expr);
                break;
            }
@@ -3895,17 +4581,19 @@ whileline, OP *expr, OP *block, OP *cont, I32 has_my)
        cont = append_elem(OP_LINESEQ, cont, unstack);
     }
 
+    assert(block);
     listop = append_list(OP_LINESEQ, (LISTOP*)block, (LISTOP*)cont);
+    assert(listop);
     redo = LINKLIST(listop);
 
     if (expr) {
-       PL_copline = (line_t)whileline;
+       PL_parser->copline = (line_t)whileline;
        scalar(listop);
        o = new_logop(OP_AND, 0, &expr, &listop);
        if (o == expr && o->op_type == OP_CONST && !SvTRUE(cSVOPo->op_sv)) {
            op_free(expr);              /* oops, it's a while (0) */
            op_free((OP*)loop);
-           return Nullop;              /* listop already freed by new_logop */
+           return NULL;                /* listop already freed by new_logop */
        }
        if (listop)
            ((LISTOP*)listop)->op_last->op_next =
@@ -3947,37 +4635,49 @@ Perl_newFOROP(pTHX_ I32 flags, char *label, line_t forline, OP *sv, OP *expr, OP
     PADOFFSET padoff = 0;
     I32 iterflags = 0;
     I32 iterpflags = 0;
+    OP *madsv = NULL;
 
     if (sv) {
        if (sv->op_type == OP_RV2SV) {  /* symbol table variable */
            iterpflags = sv->op_private & OPpOUR_INTRO; /* for our $x () */
            sv->op_type = OP_RV2GV;
            sv->op_ppaddr = PL_ppaddr[OP_RV2GV];
-           if (cGVOPx_gv(cUNOPx(sv)->op_first) == PL_defgv)
+
+           /* The op_type check is needed to prevent a possible segfault
+            * if the loop variable is undeclared and 'strict vars' is in
+            * effect. This is illegal but is nonetheless parsed, so we
+            * may reach this point with an OP_CONST where we're expecting
+            * an OP_GV.
+            */
+           if (cUNOPx(sv)->op_first->op_type == OP_GV
+            && cGVOPx_gv(cUNOPx(sv)->op_first) == PL_defgv)
                iterpflags |= OPpITER_DEF;
        }
        else if (sv->op_type == OP_PADSV) { /* private variable */
            iterpflags = sv->op_private & OPpLVAL_INTRO; /* for my $x () */
            padoff = sv->op_targ;
-           sv->op_targ = 0;
-           op_free(sv);
-           sv = Nullop;
-       }
-       else if (sv->op_type == OP_THREADSV) { /* per-thread variable */
-           padoff = sv->op_targ;
-           sv->op_targ = 0;
-           iterflags |= OPf_SPECIAL;
-           op_free(sv);
-           sv = Nullop;
+           if (PL_madskills)
+               madsv = sv;
+           else {
+               sv->op_targ = 0;
+               op_free(sv);
+           }
+           sv = NULL;
        }
        else
            Perl_croak(aTHX_ "Can't use %s for loop variable", PL_op_desc[sv->op_type]);
-       if (padoff && strEQ(PAD_COMPNAME_PV(padoff), "$_"))
-           iterpflags |= OPpITER_DEF;
+       if (padoff) {
+           SV *const namesv = PAD_COMPNAME_SV(padoff);
+           STRLEN len;
+           const char *const name = SvPV_const(namesv, len);
+
+           if (len == 2 && name[0] == '$' && name[1] == '_')
+               iterpflags |= OPpITER_DEF;
+       }
     }
     else {
-        const I32 offset = pad_findmy("$_");
-       if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS(offset) & SVpad_OUR) {
+        const PADOFFSET offset = pad_findmy("$_");
+       if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS_isOUR(offset)) {
            sv = newGVOP(OP_GV, 0, PL_defgv);
        }
        else {
@@ -3997,14 +4697,14 @@ Perl_newFOROP(pTHX_ I32 flags, char *label, line_t forline, OP *sv, OP *expr, OP
         * set the STACKED flag to indicate that these values are to be
         * treated as min/max values by 'pp_iterinit'.
         */
-       UNOP* const flip = (UNOP*)((UNOP*)((BINOP*)expr)->op_first)->op_first;
+       const UNOP* const flip = (UNOP*)((UNOP*)((BINOP*)expr)->op_first)->op_first;
        LOGOP* const range = (LOGOP*) flip->op_first;
        OP* const left  = range->op_first;
        OP* const right = left->op_sibling;
        LISTOP* listop;
 
        range->op_flags &= ~OPf_KIDS;
-       range->op_first = Nullop;
+       range->op_first = NULL;
 
        listop = (LISTOP*)newLISTOP(OP_LIST, 0, left, right);
        listop->op_first->op_next = range->op_next;
@@ -4012,7 +4712,11 @@ Perl_newFOROP(pTHX_ I32 flags, char *label, line_t forline, OP *sv, OP *expr, OP
        right->op_next = (OP*)listop;
        listop->op_next = listop->op_first;
 
+#ifdef PERL_MAD
+       op_getmad(expr,(OP*)listop,'O');
+#else
        op_free(expr);
+#endif
        expr = (OP*)(listop);
         op_null(expr);
        iterflags |= OPf_STACKED;
@@ -4032,15 +4736,17 @@ Perl_newFOROP(pTHX_ I32 flags, char *label, line_t forline, OP *sv, OP *expr, OP
        LOOP *tmp;
        NewOp(1234,tmp,1,LOOP);
        Copy(loop,tmp,1,LISTOP);
-       FreeOp(loop);
+       S_op_destroy(aTHX_ (OP*)loop);
        loop = tmp;
     }
 #else
-    Renew(loop, 1, LOOP);
+    loop = (LOOP*)PerlMemShared_realloc(loop, sizeof(LOOP));
 #endif
     loop->op_targ = padoff;
     wop = newWHILEOP(flags, 1, loop, forline, newOP(OP_ITER, 0), block, cont, 0);
-    PL_copline = forline;
+    if (madsv)
+       op_getmad(madsv, (OP*)loop, 'v');
+    PL_parser->copline = forline;
     return newSTATEOP(0, label, wop);
 }
 
@@ -4055,11 +4761,15 @@ Perl_newLOOPEX(pTHX_ I32 type, OP *label)
        if (label->op_type == OP_STUB && (label->op_flags & OPf_PARENS))
            o = newOP(type, OPf_SPECIAL);
        else {
-           o = newPVOP(type, 0, savepv(label->op_type == OP_CONST
-                                       ? SvPVx_nolen_const(((SVOP*)label)->op_sv)
+           o = newPVOP(type, 0, savesharedpv(label->op_type == OP_CONST
+                                       ? SvPV_nolen_const(((SVOP*)label)->op_sv)
                                        : ""));
        }
+#ifdef PERL_MAD
+       op_getmad(label,o,'L');
+#else
        op_free(label);
+#endif
     }
     else {
        /* Check whether it's going to be a goto &function */
@@ -4101,8 +4811,7 @@ S_ref_array_or_hash(pTHX_ OP *cond)
    op_other if the match fails.)
  */
 
-STATIC
-OP *
+STATIC OP *
 S_newGIVWHENOP(pTHX_ OP *cond, OP *block,
                   I32 enter_opcode, I32 leave_opcode,
                   PADOFFSET entertarg)
@@ -4156,9 +4865,8 @@ S_newGIVWHENOP(pTHX_ OP *cond, OP *block,
    
    [*] possibly surprising
  */
-STATIC
-bool
-S_looks_like_bool(pTHX_ OP *o)
+STATIC bool
+S_looks_like_bool(pTHX_ const OP *o)
 {
     dVAR;
     switch(o->op_type) {
@@ -4229,7 +4937,7 @@ Perl_newGIVENOP(pTHX_ OP *cond, OP *block, PADOFFSET defsv_off)
 OP *
 Perl_newWHENOP(pTHX_ OP *cond, OP *block)
 {
-    bool cond_llb = (!cond || looks_like_bool(cond));
+    const bool cond_llb = (!cond || looks_like_bool(cond));
     OP *cond_op;
 
     if (cond_llb)
@@ -4262,27 +4970,27 @@ Perl_cv_undef(pTHX_ CV *cv)
 {
     dVAR;
 #ifdef USE_ITHREADS
-    if (CvFILE(cv) && !CvXSUB(cv)) {
+    if (CvFILE(cv) && !CvISXSUB(cv)) {
        /* for XSUBs CvFILE point directly to static memory; __FILE__ */
        Safefree(CvFILE(cv));
     }
-    CvFILE(cv) = 0;
+    CvFILE(cv) = NULL;
 #endif
 
-    if (!CvXSUB(cv) && CvROOT(cv)) {
-       if (CvDEPTH(cv))
+    if (!CvISXSUB(cv) && CvROOT(cv)) {
+       if (SvTYPE(cv) == SVt_PVCV && CvDEPTH(cv))
            Perl_croak(aTHX_ "Can't undef active subroutine");
        ENTER;
 
        PAD_SAVE_SETNULLPAD();
 
        op_free(CvROOT(cv));
-       CvROOT(cv) = Nullop;
-       CvSTART(cv) = Nullop;
+       CvROOT(cv) = NULL;
+       CvSTART(cv) = NULL;
        LEAVE;
     }
     SvPOK_off((SV*)cv);                /* forget prototype */
-    CvGV(cv) = Nullgv;
+    CvGV(cv) = NULL;
 
     pad_undef(cv);
 
@@ -4290,41 +4998,47 @@ Perl_cv_undef(pTHX_ CV *cv)
     if (!SvREFCNT(cv) && CvOUTSIDE(cv)) {
        if (!CvWEAKOUTSIDE(cv))
            SvREFCNT_dec(CvOUTSIDE(cv));
-       CvOUTSIDE(cv) = Nullcv;
+       CvOUTSIDE(cv) = NULL;
     }
     if (CvCONST(cv)) {
        SvREFCNT_dec((SV*)CvXSUBANY(cv).any_ptr);
        CvCONST_off(cv);
     }
-    if (CvXSUB(cv)) {
-        CvXSUB(cv) = 0;
+    if (CvISXSUB(cv) && CvXSUB(cv)) {
+       CvXSUB(cv) = NULL;
     }
     /* delete all flags except WEAKOUTSIDE */
     CvFLAGS(cv) &= CVf_WEAKOUTSIDE;
 }
 
 void
-Perl_cv_ckproto(pTHX_ const CV *cv, const GV *gv, const char *p)
-{
-    if (((!p != !SvPOK(cv)) || (p && strNE(p, SvPVX_const(cv)))) && ckWARN_d(WARN_PROTOTYPE)) {
+Perl_cv_ckproto_len(pTHX_ const CV *cv, const GV *gv, const char *p,
+                   const STRLEN len)
+{
+    /* Can't just use a strcmp on the prototype, as CONSTSUBs "cheat" by
+       relying on SvCUR, and doubling up the buffer to hold CvFILE().  */
+    if (((!p != !SvPOK(cv)) /* One has prototype, one has not.  */
+        || (p && (len != SvCUR(cv) /* Not the same length.  */
+                  || memNE(p, SvPVX_const(cv), len))))
+        && ckWARN_d(WARN_PROTOTYPE)) {
        SV* const msg = sv_newmortal();
-       SV* name = Nullsv;
+       SV* name = NULL;
 
        if (gv)
            gv_efullname3(name = sv_newmortal(), gv, NULL);
-       sv_setpv(msg, "Prototype mismatch:");
+       sv_setpvs(msg, "Prototype mismatch:");
        if (name)
-           Perl_sv_catpvf(aTHX_ msg, " sub %"SVf, name);
+           Perl_sv_catpvf(aTHX_ msg, " sub %"SVf, SVfARG(name));
        if (SvPOK(cv))
-           Perl_sv_catpvf(aTHX_ msg, " (%"SVf")", (const SV *)cv);
+           Perl_sv_catpvf(aTHX_ msg, " (%"SVf")", SVfARG(cv));
        else
            sv_catpvs(msg, ": none");
        sv_catpvs(msg, " vs ");
        if (p)
-           Perl_sv_catpvf(aTHX_ msg, "(%s)", p);
+           Perl_sv_catpvf(aTHX_ msg, "(%.*s)", (int) len, p);
        else
            sv_catpvs(msg, "none");
-       Perl_warner(aTHX_ packWARN(WARN_PROTOTYPE), "%"SVf, msg);
+       Perl_warner(aTHX_ packWARN(WARN_PROTOTYPE), "%"SVf, SVfARG(msg));
     }
 }
 
@@ -4347,6 +5061,7 @@ L<perlsub/"Constant Functions">.
 SV *
 Perl_cv_const_sv(pTHX_ CV *cv)
 {
+    PERL_UNUSED_CONTEXT;
     if (!cv)
        return NULL;
     if (!(SvTYPE(cv) == SVt_PVCV || SvTYPE(cv) == SVt_PVFM))
@@ -4378,10 +5093,13 @@ SV *
 Perl_op_const_sv(pTHX_ const OP *o, CV *cv)
 {
     dVAR;
-    SV *sv = Nullsv;
+    SV *sv = NULL;
+
+    if (PL_madskills)
+       return NULL;
 
     if (!o)
-       return Nullsv;
+       return NULL;
 
     if (o->op_type == OP_LINESEQ && cLISTOPo->op_first)
        o = cLISTOPo->op_first->op_sibling;
@@ -4400,13 +5118,13 @@ Perl_op_const_sv(pTHX_ const OP *o, CV *cv)
        if (type == OP_LEAVESUB || type == OP_RETURN)
            break;
        if (sv)
-           return Nullsv;
+           return NULL;
        if (type == OP_CONST && cSVOPo->op_sv)
            sv = cSVOPo->op_sv;
        else if (cv && type == OP_CONST) {
            sv = PAD_BASE_SV(CvPADLIST(cv), o->op_targ);
            if (!sv)
-               return Nullsv;
+               return NULL;
        }
        else if (cv && type == OP_PADSV) {
            if (CvCONST(cv)) { /* newly cloned anon */
@@ -4414,7 +5132,7 @@ Perl_op_const_sv(pTHX_ const OP *o, CV *cv)
                /* the candidate should have 1 ref from this pad and 1 ref
                 * from the parent */
                if (!sv || SvREFCNT(sv) != 2)
-                   return Nullsv;
+                   return NULL;
                sv = newSVsv(sv);
                SvREADONLY_on(sv);
                return sv;
@@ -4425,15 +5143,24 @@ Perl_op_const_sv(pTHX_ const OP *o, CV *cv)
            }
        }
        else {
-           return Nullsv;
+           return NULL;
        }
     }
     return sv;
 }
 
+#ifdef PERL_MAD
+OP *
+#else
 void
+#endif
 Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
 {
+#if 0
+    /* This would be the return value, but the return cannot be reached.  */
+    OP* pegop = newOP(OP_NULL, 0);
+#endif
+
     PERL_UNUSED_ARG(floor);
 
     if (o)
@@ -4445,12 +5172,15 @@ Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
     if (block)
        SAVEFREEOP(block);
     Perl_croak(aTHX_ "\"my sub\" not yet implemented");
+#ifdef PERL_MAD
+    NORETURN_FUNCTION_END;
+#endif
 }
 
 CV *
 Perl_newSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *block)
 {
-    return Perl_newATTRSUB(aTHX_ floor, o, proto, Nullop, block);
+    return Perl_newATTRSUB(aTHX_ floor, o, proto, NULL, block);
 }
 
 CV *
@@ -4469,13 +5199,14 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        full GV and CV.  If anything is present then it will take a full CV to
        store it.  */
     const I32 gv_fetch_flags
-       = (block || attrs || (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS))
+       = (block || attrs || (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS)
+          || PL_madskills)
        ? GV_ADDMULTI : GV_ADDMULTI | GV_NOINIT;
-    const char * const name = o ? SvPVx_nolen_const(cSVOPo->op_sv) : NULL;
+    const char * const name = o ? SvPV_nolen_const(cSVOPo->op_sv) : NULL;
 
     if (proto) {
        assert(proto->op_type == OP_CONST);
-       ps = SvPVx_const(((SVOP*)proto)->op_sv, ps_len);
+       ps = SvPV_const(((SVOP*)proto)->op_sv, ps_len);
     }
     else
        ps = NULL;
@@ -4495,12 +5226,14 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                     : (PL_curstash ? "__ANON__" : "__ANON__::__ANON__"),
                     gv_fetch_flags, SVt_PVCV);
 
-    if (o)
-       SAVEFREEOP(o);
-    if (proto)
-       SAVEFREEOP(proto);
-    if (attrs)
-       SAVEFREEOP(attrs);
+    if (!PL_madskills) {
+       if (o)
+           SAVEFREEOP(o);
+       if (proto)
+           SAVEFREEOP(proto);
+       if (attrs)
+           SAVEFREEOP(attrs);
+    }
 
     if (SvTYPE(gv) != SVt_PVGV) {      /* Maybe prototype now, and had at
                                           maximum a prototype before. */
@@ -4510,19 +5243,19 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            {
                Perl_warner(aTHX_ packWARN(WARN_PROTOTYPE), "Runaway prototype");
            }
-           cv_ckproto((CV*)gv, NULL, ps);
+           cv_ckproto_len((CV*)gv, NULL, ps, ps_len);
        }
        if (ps)
            sv_setpvn((SV*)gv, ps, ps_len);
        else
            sv_setiv((SV*)gv, -1);
+
        SvREFCNT_dec(PL_compcv);
        cv = PL_compcv = NULL;
-       PL_sub_generation++;
        goto done;
     }
 
-    cv = (!name || GvCVGEN(gv)) ? Nullcv : GvCV(gv);
+    cv = (!name || GvCVGEN(gv)) ? NULL : GvCV(gv);
 
 #ifdef GV_UNIQUE_CHECK
     if (cv && GvUNIQUE(gv) && SvREADONLY(cv)) {
@@ -4530,10 +5263,15 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
     }
 #endif
 
-    if (!block || !ps || *ps || attrs || (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS))
-       const_sv = Nullsv;
+    if (!block || !ps || *ps || attrs
+       || (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS)
+#ifdef PERL_MAD
+       || block->op_type == OP_NULL
+#endif
+       )
+       const_sv = NULL;
     else
-       const_sv = op_const_sv(block, Nullcv);
+       const_sv = op_const_sv(block, NULL);
 
     if (cv) {
         const bool exists = CvROOT(cv) || CvXSUB(cv);
@@ -4549,10 +5287,14 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
          * skipping the prototype check
          */
         if (exists || SvPOK(cv))
-           cv_ckproto(cv, gv, ps);
+           cv_ckproto_len(cv, gv, ps, ps_len);
        /* already defined (or promised)? */
        if (exists || GvASSUMECV(gv)) {
-           if (!block && !attrs) {
+           if ((!block
+#ifdef PERL_MAD
+                || block->op_type == OP_NULL
+#endif
+                )&& !attrs) {
                if (CvFLAGS(PL_compcv)) {
                    /* might have had built-in attrs applied */
                    CvFLAGS(cv) |= (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS);
@@ -4561,41 +5303,60 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                SAVEFREESV(PL_compcv);
                goto done;
            }
-           if (block) {
+           if (block
+#ifdef PERL_MAD
+               && block->op_type != OP_NULL
+#endif
+               ) {
                if (ckWARN(WARN_REDEFINE)
                    || (CvCONST(cv)
                        && (!const_sv || sv_cmp(cv_const_sv(cv), const_sv))))
                {
                    const line_t oldline = CopLINE(PL_curcop);
-                   if (PL_copline != NOLINE)
-                       CopLINE_set(PL_curcop, PL_copline);
+                   if (PL_parser && PL_parser->copline != NOLINE)
+                       CopLINE_set(PL_curcop, PL_parser->copline);
                    Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
                        CvCONST(cv) ? "Constant subroutine %s redefined"
                                    : "Subroutine %s redefined", name);
                    CopLINE_set(PL_curcop, oldline);
                }
-               SvREFCNT_dec(cv);
-               cv = Nullcv;
+#ifdef PERL_MAD
+               if (!PL_minus_c)        /* keep old one around for madskills */
+#endif
+                   {
+                       /* (PL_madskills unset in used file.) */
+                       SvREFCNT_dec(cv);
+                   }
+               cv = NULL;
            }
        }
     }
     if (const_sv) {
-       (void)SvREFCNT_inc(const_sv);
+       SvREFCNT_inc_simple_void_NN(const_sv);
        if (cv) {
            assert(!CvROOT(cv) && !CvCONST(cv));
            sv_setpvn((SV*)cv, "", 0);  /* prototype is "" */
            CvXSUBANY(cv).any_ptr = const_sv;
            CvXSUB(cv) = const_sv_xsub;
            CvCONST_on(cv);
+           CvISXSUB_on(cv);
        }
        else {
-           GvCV(gv) = Nullcv;
+           GvCV(gv) = NULL;
            cv = newCONSTSUB(NULL, name, const_sv);
        }
+        mro_method_changed_in( /* sub Foo::Bar () { 123 } */
+            (CvGV(cv) && GvSTASH(CvGV(cv)))
+                ? GvSTASH(CvGV(cv))
+                : CvSTASH(cv)
+                    ? CvSTASH(cv)
+                    : PL_curstash
+        );
+       if (PL_madskills)
+           goto install_block;
        op_free(block);
        SvREFCNT_dec(PL_compcv);
        PL_compcv = NULL;
-       PL_sub_generation++;
        goto done;
     }
     if (attrs) {
@@ -4605,7 +5366,11 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        /* Need to do a C<use attributes $stash_of_cv,\&cv,@attrs>
         * before we clobber PL_compcv.
         */
-       if (cv && !block) {
+       if (cv && (!block
+#ifdef PERL_MAD
+                   || block->op_type == OP_NULL
+#endif
+                   )) {
            rcv = (SV*)cv;
            /* Might have had built-in attributes applied -- propagate them. */
            CvFLAGS(cv) |= (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS);
@@ -4627,7 +5392,15 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        apply_attrs(stash, rcv, attrs, FALSE);
     }
     if (cv) {                          /* must reuse cv if autoloaded */
-       if (!block) {
+       if (
+#ifdef PERL_MAD
+           (
+#endif
+            !block
+#ifdef PERL_MAD
+            || block->op_type == OP_NULL) && !PL_madskills
+#endif
+            ) {
            /* got here with just attrs -- work done, so bug out */
            SAVEFREESV(PL_compcv);
            goto done;
@@ -4654,8 +5427,14 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        cv = PL_compcv;
        if (name) {
            GvCV(gv) = cv;
+           if (PL_madskills) {
+               if (strEQ(name, "import")) {
+                   PL_formfeed = (SV*)cv;
+                   Perl_warner(aTHX_ packWARN(WARN_VOID), "%lx\n", (long)cv);
+               }
+           }
            GvCVGEN(gv) = 0;
-           PL_sub_generation++;
+            mro_method_changed_in(GvSTASH(gv)); /* sub Foo::bar { (shift)+1 } */
        }
     }
     CvGV(cv) = gv;
@@ -4665,9 +5444,9 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
     if (ps)
        sv_setpvn((SV*)cv, ps, ps_len);
 
-    if (PL_error_count) {
+    if (PL_parser && PL_parser->error_count) {
        op_free(block);
-       block = Nullop;
+       block = NULL;
        if (name) {
            const char *s = strrchr(name, ':');
            s = s ? s+1 : name;
@@ -4679,24 +5458,33 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                else {
                    /* force display of errors found but not reported */
                    sv_catpv(ERRSV, not_safe);
-                   Perl_croak(aTHX_ "%"SVf, ERRSV);
+                   Perl_croak(aTHX_ "%"SVf, SVfARG(ERRSV));
                }
            }
        }
     }
+ install_block:
     if (!block)
        goto done;
 
     if (CvLVALUE(cv)) {
        CvROOT(cv) = newUNOP(OP_LEAVESUBLV, 0,
                             mod(scalarseq(block), OP_LEAVESUBLV));
+       block->op_attached = 1;
     }
     else {
        /* This makes sub {}; work as expected.  */
        if (block->op_type == OP_STUB) {
+           OP* const newblock = newSTATEOP(0, NULL, 0);
+#ifdef PERL_MAD
+           op_getmad(block,newblock,'B');
+#else
            op_free(block);
-           block = newSTATEOP(0, NULL, 0);
+#endif
+           block = newblock;
        }
+       else
+           block->op_attached = 1;
        CvROOT(cv) = newUNOP(OP_LEAVESUB, 0, scalarseq(block));
     }
     CvROOT(cv)->op_private |= OPpREFCOUNTED;
@@ -4716,9 +5504,6 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
     }
 
     if (name || aname) {
-       const char *s;
-       const char * const tname = (name ? name : aname);
-
        if (PERLDB_SUBLINE && PL_curstash != PL_debstash) {
            SV * const sv = newSV(0);
            SV * const tmpstr = sv_newmortal();
@@ -4744,67 +5529,81 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            }
        }
 
-       if ((s = strrchr(tname,':')))
-           s++;
-       else
-           s = tname;
+       if (name && ! (PL_parser && PL_parser->error_count))
+           process_special_blocks(name, gv, cv);
+    }
 
-       if (*s != 'B' && *s != 'E' && *s != 'C' && *s != 'I')
-           goto done;
+  done:
+    if (PL_parser)
+       PL_parser->copline = NOLINE;
+    LEAVE_SCOPE(floor);
+    return cv;
+}
+
+STATIC void
+S_process_special_blocks(pTHX_ const char *const fullname, GV *const gv,
+                        CV *const cv)
+{
+    const char *const colon = strrchr(fullname,':');
+    const char *const name = colon ? colon + 1 : fullname;
 
-       if (strEQ(s, "BEGIN") && !PL_error_count) {
+    if (*name == 'B') {
+       if (strEQ(name, "BEGIN")) {
            const I32 oldscope = PL_scopestack_ix;
            ENTER;
            SAVECOPFILE(&PL_compiling);
            SAVECOPLINE(&PL_compiling);
 
-           if (!PL_beginav)
-               PL_beginav = newAV();
            DEBUG_x( dump_sub(gv) );
-           av_push(PL_beginav, (SV*)cv);
+           Perl_av_create_and_push(aTHX_ &PL_beginav, (SV*)cv);
            GvCV(gv) = 0;               /* cv has been hijacked */
            call_list(oldscope, PL_beginav);
 
            PL_curcop = &PL_compiling;
-           PL_compiling.op_private = (U8)(PL_hints & HINT_PRIVATE_MASK);
+           CopHINTS_set(&PL_compiling, PL_hints);
            LEAVE;
        }
-       else if (strEQ(s, "END") && !PL_error_count) {
-           if (!PL_endav)
-               PL_endav = newAV();
-           DEBUG_x( dump_sub(gv) );
-           av_unshift(PL_endav, 1);
-           av_store(PL_endav, 0, (SV*)cv);
-           GvCV(gv) = 0;               /* cv has been hijacked */
-       }
-       else if (strEQ(s, "CHECK") && !PL_error_count) {
-           if (!PL_checkav)
-               PL_checkav = newAV();
-           DEBUG_x( dump_sub(gv) );
-           if (PL_main_start && ckWARN(WARN_VOID))
-               Perl_warner(aTHX_ packWARN(WARN_VOID), "Too late to run CHECK block");
-           av_unshift(PL_checkav, 1);
-           av_store(PL_checkav, 0, (SV*)cv);
-           GvCV(gv) = 0;               /* cv has been hijacked */
-       }
-       else if (strEQ(s, "INIT") && !PL_error_count) {
-           if (!PL_initav)
-               PL_initav = newAV();
-           DEBUG_x( dump_sub(gv) );
-           if (PL_main_start && ckWARN(WARN_VOID))
-               Perl_warner(aTHX_ packWARN(WARN_VOID), "Too late to run INIT block");
-           av_push(PL_initav, (SV*)cv);
-           GvCV(gv) = 0;               /* cv has been hijacked */
-       }
+       else
+           return;
+    } else {
+       if (*name == 'E') {
+           if strEQ(name, "END") {
+               DEBUG_x( dump_sub(gv) );
+               Perl_av_create_and_unshift_one(aTHX_ &PL_endav, (SV*)cv);
+           } else
+               return;
+       } else if (*name == 'U') {
+           if (strEQ(name, "UNITCHECK")) {
+               /* It's never too late to run a unitcheck block */
+               Perl_av_create_and_unshift_one(aTHX_ &PL_unitcheckav, (SV*)cv);
+           }
+           else
+               return;
+       } else if (*name == 'C') {
+           if (strEQ(name, "CHECK")) {
+               if (PL_main_start && ckWARN(WARN_VOID))
+                   Perl_warner(aTHX_ packWARN(WARN_VOID),
+                               "Too late to run CHECK block");
+               Perl_av_create_and_unshift_one(aTHX_ &PL_checkav, (SV*)cv);
+           }
+           else
+               return;
+       } else if (*name == 'I') {
+           if (strEQ(name, "INIT")) {
+               if (PL_main_start && ckWARN(WARN_VOID))
+                   Perl_warner(aTHX_ packWARN(WARN_VOID),
+                               "Too late to run INIT block");
+               Perl_av_create_and_push(aTHX_ &PL_initav, (SV*)cv);
+           }
+           else
+               return;
+       } else
+           return;
+       DEBUG_x( dump_sub(gv) );
+       GvCV(gv) = 0;           /* cv has been hijacked */
     }
-
-  done:
-    PL_copline = NOLINE;
-    LEAVE_SCOPE(floor);
-    return cv;
 }
 
-/* XXX unsafe for threads if eval_owner isn't held */
 /*
 =for apidoc newCONSTSUB
 
@@ -4819,11 +5618,20 @@ Perl_newCONSTSUB(pTHX_ HV *stash, const char *name, SV *sv)
 {
     dVAR;
     CV* cv;
+#ifdef USE_ITHREADS
+    const char *const temp_p = CopFILE(PL_curcop);
+    const STRLEN len = temp_p ? strlen(temp_p) : 0;
+#else
+    SV *const temp_sv = CopFILESV(PL_curcop);
+    STRLEN len;
+    const char *const temp_p = temp_sv ? SvPV_const(temp_sv, len) : NULL;
+#endif
+    char *const file = savepvn(temp_p, temp_p ? len : 0);
 
     ENTER;
 
     SAVECOPLINE(PL_curcop);
-    CopLINE_set(PL_curcop, PL_copline);
+    CopLINE_set(PL_curcop, PL_parser ? PL_parser->copline : NOLINE);
 
     SAVEHINTS();
     PL_hints &= ~HINT_BLOCK_SCOPE;
@@ -4835,10 +5643,14 @@ Perl_newCONSTSUB(pTHX_ HV *stash, const char *name, SV *sv)
        CopSTASH_set(PL_curcop,stash);
     }
 
-    cv = newXS(name, const_sv_xsub, savepv(CopFILE(PL_curcop)));
+    /* file becomes the CvFILE. For an XS, it's supposed to be static storage,
+       and so doesn't get free()d.  (It's expected to be from the C pre-
+       processor __FILE__ directive). But we need a dynamically allocated one,
+       and we need it to get freed.  */
+    cv = newXS_flags(name, const_sv_xsub, file, "", XS_DYNAMIC_FILENAME);
     CvXSUBANY(cv).any_ptr = sv;
     CvCONST_on(cv);
-    sv_setpvn((SV*)cv, "", 0);  /* prototype is "" */
+    Safefree(file);
 
 #ifdef USE_ITHREADS
     if (stash)
@@ -4849,10 +5661,56 @@ Perl_newCONSTSUB(pTHX_ HV *stash, const char *name, SV *sv)
     return cv;
 }
 
+CV *
+Perl_newXS_flags(pTHX_ const char *name, XSUBADDR_t subaddr,
+                const char *const filename, const char *const proto,
+                U32 flags)
+{
+    CV *cv = newXS(name, subaddr, filename);
+
+    if (flags & XS_DYNAMIC_FILENAME) {
+       /* We need to "make arrangements" (ie cheat) to ensure that the
+          filename lasts as long as the PVCV we just created, but also doesn't
+          leak  */
+       STRLEN filename_len = strlen(filename);
+       STRLEN proto_and_file_len = filename_len;
+       char *proto_and_file;
+       STRLEN proto_len;
+
+       if (proto) {
+           proto_len = strlen(proto);
+           proto_and_file_len += proto_len;
+
+           Newx(proto_and_file, proto_and_file_len + 1, char);
+           Copy(proto, proto_and_file, proto_len, char);
+           Copy(filename, proto_and_file + proto_len, filename_len + 1, char);
+       } else {
+           proto_len = 0;
+           proto_and_file = savepvn(filename, filename_len);
+       }
+
+       /* This gets free()d.  :-)  */
+       sv_usepvn_flags((SV*)cv, proto_and_file, proto_and_file_len,
+                       SV_HAS_TRAILING_NUL);
+       if (proto) {
+           /* This gives us the correct prototype, rather than one with the
+              file name appended.  */
+           SvCUR_set(cv, proto_len);
+       } else {
+           SvPOK_off(cv);
+       }
+       CvFILE(cv) = proto_and_file + proto_len;
+    } else {
+       sv_setpv((SV *)cv, proto);
+    }
+    return cv;
+}
+
 /*
 =for apidoc U||newXS
 
-Used by C<xsubpp> to hook up XSUBs as Perl subs.
+Used by C<xsubpp> to hook up XSUBs as Perl subs.  I<filename> needs to be
+static storage, as it is used directly as CvFILE(), without a copy being made.
 
 =cut
 */
@@ -4869,11 +5727,11 @@ Perl_newXS(pTHX_ const char *name, XSUBADDR_t subaddr, const char *filename)
     if (!subaddr)
        Perl_croak(aTHX_ "panic: no address for '%s' in '%s'", name, filename);
 
-    if ((cv = (name ? GvCV(gv) : Nullcv))) {
+    if ((cv = (name ? GvCV(gv) : NULL))) {
        if (GvCVGEN(gv)) {
            /* just a cached method */
            SvREFCNT_dec(cv);
-           cv = Nullcv;
+           cv = NULL;
        }
        else if (CvROOT(cv) || CvXSUB(cv) || GvASSUMECV(gv)) {
            /* already defined (or promised) */
@@ -4883,11 +5741,11 @@ Perl_newXS(pTHX_ const char *name, XSUBADDR_t subaddr, const char *filename)
                if (gvcv) {
                    HV * const stash = GvSTASH(gvcv);
                    if (stash) {
-                       const char *name = HvNAME_get(stash);
-                       if ( strEQ(name,"autouse") ) {
+                       const char *redefined_name = HvNAME_get(stash);
+                       if ( strEQ(redefined_name,"autouse") ) {
                            const line_t oldline = CopLINE(PL_curcop);
-                           if (PL_copline != NOLINE)
-                               CopLINE_set(PL_curcop, PL_copline);
+                           if (PL_parser && PL_parser->copline != NOLINE)
+                               CopLINE_set(PL_curcop, PL_parser->copline);
                            Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
                                        CvCONST(cv) ? "Constant subroutine %s redefined"
                                                    : "Subroutine %s redefined"
@@ -4898,80 +5756,47 @@ Perl_newXS(pTHX_ const char *name, XSUBADDR_t subaddr, const char *filename)
                }
            }
            SvREFCNT_dec(cv);
-           cv = Nullcv;
+           cv = NULL;
        }
     }
 
     if (cv)                            /* must reuse cv if autoloaded */
        cv_undef(cv);
     else {
-       cv = (CV*)newSV(0);
-       sv_upgrade((SV *)cv, SVt_PVCV);
+       cv = (CV*)newSV_type(SVt_PVCV);
        if (name) {
            GvCV(gv) = cv;
            GvCVGEN(gv) = 0;
-           PL_sub_generation++;
+            mro_method_changed_in(GvSTASH(gv)); /* newXS */
        }
     }
     CvGV(cv) = gv;
     (void)gv_fetchfile(filename);
     CvFILE(cv) = (char *)filename; /* NOTE: not copied, as it is expected to be
                                   an external constant string */
+    CvISXSUB_on(cv);
     CvXSUB(cv) = subaddr;
 
-    if (name) {
-       const char *s = strrchr(name,':');
-       if (s)
-           s++;
-       else
-           s = name;
-
-       if (*s != 'B' && *s != 'E' && *s != 'C' && *s != 'I')
-           goto done;
-
-       if (strEQ(s, "BEGIN")) {
-           if (!PL_beginav)
-               PL_beginav = newAV();
-           av_push(PL_beginav, (SV*)cv);
-           GvCV(gv) = 0;               /* cv has been hijacked */
-       }
-       else if (strEQ(s, "END")) {
-           if (!PL_endav)
-               PL_endav = newAV();
-           av_unshift(PL_endav, 1);
-           av_store(PL_endav, 0, (SV*)cv);
-           GvCV(gv) = 0;               /* cv has been hijacked */
-       }
-       else if (strEQ(s, "CHECK")) {
-           if (!PL_checkav)
-               PL_checkav = newAV();
-           if (PL_main_start && ckWARN(WARN_VOID))
-               Perl_warner(aTHX_ packWARN(WARN_VOID), "Too late to run CHECK block");
-           av_unshift(PL_checkav, 1);
-           av_store(PL_checkav, 0, (SV*)cv);
-           GvCV(gv) = 0;               /* cv has been hijacked */
-       }
-       else if (strEQ(s, "INIT")) {
-           if (!PL_initav)
-               PL_initav = newAV();
-           if (PL_main_start && ckWARN(WARN_VOID))
-               Perl_warner(aTHX_ packWARN(WARN_VOID), "Too late to run INIT block");
-           av_push(PL_initav, (SV*)cv);
-           GvCV(gv) = 0;               /* cv has been hijacked */
-       }
-    }
+    if (name)
+       process_special_blocks(name, gv, cv);
     else
        CvANON_on(cv);
 
-done:
     return cv;
 }
 
+#ifdef PERL_MAD
+OP *
+#else
 void
+#endif
 Perl_newFORM(pTHX_ I32 floor, OP *o, OP *block)
 {
     dVAR;
     register CV *cv;
+#ifdef PERL_MAD
+    OP* pegop = newOP(OP_NULL, 0);
+#endif
 
     GV * const gv = o
        ? gv_fetchsv(cSVOPo->op_sv, GV_ADD, SVt_PVFM)
@@ -4986,11 +5811,11 @@ Perl_newFORM(pTHX_ I32 floor, OP *o, OP *block)
     if ((cv = GvFORM(gv))) {
        if (ckWARN(WARN_REDEFINE)) {
            const line_t oldline = CopLINE(PL_curcop);
-           if (PL_copline != NOLINE)
-               CopLINE_set(PL_curcop, PL_copline);
+           if (PL_parser && PL_parser->copline != NOLINE)
+               CopLINE_set(PL_curcop, PL_parser->copline);
            Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
                        o ? "Format %"SVf" redefined"
-                       : "Format STDOUT redefined" ,cSVOPo->op_sv);
+                       : "Format STDOUT redefined", SVfARG(cSVOPo->op_sv));
            CopLINE_set(PL_curcop, oldline);
        }
        SvREFCNT_dec(cv);
@@ -5008,29 +5833,36 @@ Perl_newFORM(pTHX_ I32 floor, OP *o, OP *block)
     CvSTART(cv) = LINKLIST(CvROOT(cv));
     CvROOT(cv)->op_next = 0;
     CALL_PEEP(CvSTART(cv));
+#ifdef PERL_MAD
+    op_getmad(o,pegop,'n');
+    op_getmad_weak(block, pegop, 'b');
+#else
     op_free(o);
-    PL_copline = NOLINE;
+#endif
+    if (PL_parser)
+       PL_parser->copline = NOLINE;
     LEAVE_SCOPE(floor);
+#ifdef PERL_MAD
+    return pegop;
+#endif
 }
 
 OP *
 Perl_newANONLIST(pTHX_ OP *o)
 {
-    return newUNOP(OP_REFGEN, 0,
-       mod(list(convert(OP_ANONLIST, 0, o)), OP_REFGEN));
+    return convert(OP_ANONLIST, OPf_SPECIAL, o);
 }
 
 OP *
 Perl_newANONHASH(pTHX_ OP *o)
 {
-    return newUNOP(OP_REFGEN, 0,
-       mod(list(convert(OP_ANONHASH, 0, o)), OP_REFGEN));
+    return convert(OP_ANONHASH, OPf_SPECIAL, o);
 }
 
 OP *
 Perl_newANONSUB(pTHX_ I32 floor, OP *proto, OP *block)
 {
-    return newANONATTRSUB(floor, proto, Nullop, block);
+    return newANONATTRSUB(floor, proto, NULL, block);
 }
 
 OP *
@@ -5148,10 +5980,6 @@ Perl_newSVREF(pTHX_ OP *o)
        o->op_ppaddr = PL_ppaddr[OP_PADSV];
        return o;
     }
-    else if (o->op_type == OP_THREADSV && !(o->op_flags & OPpDONE_SVREF)) {
-       o->op_flags |= OPpDONE_SVREF;
-       return o;
-    }
     return newUNOP(OP_RV2SV, 0, scalar(o));
 }
 
@@ -5162,7 +5990,8 @@ OP *
 Perl_ck_anoncode(pTHX_ OP *o)
 {
     cSVOPo->op_targ = pad_add_anon(cSVOPo->op_sv, o->op_type);
-    cSVOPo->op_sv = Nullsv;
+    if (!PL_madskills)
+       cSVOPo->op_sv = NULL;
     return o;
 }
 
@@ -5178,7 +6007,7 @@ Perl_ck_bitop(pTHX_ OP *o)
         (op) == OP_EQ   || (op) == OP_I_EQ || \
         (op) == OP_NE   || (op) == OP_I_NE || \
         (op) == OP_NCMP || (op) == OP_I_NCMP)
-    o->op_private = (U8)(PL_hints & HINT_PRIVATE_MASK);
+    o->op_private = (U8)(PL_hints & HINT_INTEGER);
     if (!(o->op_flags & OPf_STACKED) /* Not an assignment */
            && (o->op_type == OP_BIT_OR
             || o->op_type == OP_BIT_AND
@@ -5204,6 +6033,7 @@ OP *
 Perl_ck_concat(pTHX_ OP *o)
 {
     const OP * const kid = cUNOPo->op_first;
+    PERL_UNUSED_CONTEXT;
     if (kid->op_type == OP_CONCAT && !(kid->op_private & OPpTARGET_MY) &&
            !(kUNOP->op_first->op_flags & OPf_MOD))
         o->op_flags |= OPf_STACKED;
@@ -5221,15 +6051,18 @@ Perl_ck_spair(pTHX_ OP *o)
        o = modkids(ck_fun(o), type);
        kid = cUNOPo->op_first;
        newop = kUNOP->op_first->op_sibling;
-       if (newop &&
-           (newop->op_sibling ||
-            !(PL_opargs[newop->op_type] & OA_RETSCALAR) ||
-            newop->op_type == OP_PADAV || newop->op_type == OP_PADHV ||
-            newop->op_type == OP_RV2AV || newop->op_type == OP_RV2HV)) {
-
-           return o;
-       }
+       if (newop) {
+           const OPCODE type = newop->op_type;
+           if (newop->op_sibling || !(PL_opargs[type] & OA_RETSCALAR) ||
+                   type == OP_PADAV || type == OP_PADHV ||
+                   type == OP_RV2AV || type == OP_RV2HV)
+               return o;
+       }
+#ifdef PERL_MAD
+       op_getmad(kUNOP->op_first,newop,'K');
+#else
        op_free(kUNOP->op_first);
+#endif
        kUNOP->op_first = newop;
     }
     o->op_ppaddr = PL_ppaddr[++o->op_type];
@@ -5277,12 +6110,17 @@ OP *
 Perl_ck_eof(pTHX_ OP *o)
 {
     dVAR;
-    const I32 type = o->op_type;
 
     if (o->op_flags & OPf_KIDS) {
        if (cLISTOPo->op_first->op_type == OP_STUB) {
+           OP * const newop
+               = newUNOP(o->op_type, OPf_SPECIAL, newGVOP(OP_GV, 0, PL_argvgv));
+#ifdef PERL_MAD
+           op_getmad(o,newop,'O');
+#else
            op_free(o);
-           o = newUNOP(type, OPf_SPECIAL, newGVOP(OP_GV, 0, PL_argvgv));
+#endif
+           o = newop;
        }
        return ck_fun(o);
     }
@@ -5303,9 +6141,14 @@ Perl_ck_eval(pTHX_ OP *o)
        }
        else if (kid->op_type == OP_LINESEQ || kid->op_type == OP_STUB) {
            LOGOP *enter;
+#ifdef PERL_MAD
+           OP* const oldo = o;
+#endif
 
            cUNOPo->op_first = 0;
+#ifndef PERL_MAD
            op_free(o);
+#endif
 
            NewOp(1101, enter, 1, LOGOP);
            enter->op_type = OP_ENTERTRY;
@@ -5319,6 +6162,7 @@ Perl_ck_eval(pTHX_ OP *o)
            o->op_type = OP_LEAVETRY;
            o->op_ppaddr = PL_ppaddr[OP_LEAVETRY];
            enter->op_other = o;
+           op_getmad(oldo,o,'O');
            return o;
        }
        else {
@@ -5327,13 +6171,22 @@ Perl_ck_eval(pTHX_ OP *o)
        }
     }
     else {
+#ifdef PERL_MAD
+       OP* const oldo = o;
+#else
        op_free(o);
+#endif
        o = newUNOP(OP_ENTEREVAL, 0, newDEFSVOP());
+       op_getmad(oldo,o,'O');
     }
     o->op_targ = (PADOFFSET)PL_hints;
     if ((PL_hints & HINT_LOCALIZE_HH) != 0 && GvHV(PL_hintgv)) {
-       /* Store a copy of %^H that pp_entereval can pick up */
-       OP *hhop = newSVOP(OP_CONST, 0, (SV*)newHVhv(GvHV(PL_hintgv)));
+       /* Store a copy of %^H that pp_entereval can pick up.
+          OPf_SPECIAL flags the opcode as being for this purpose,
+          so that it in turn will return a copy at every
+          eval.*/
+       OP *hhop = newSVOP(OP_CONST, OPf_SPECIAL,
+                          (SV*)Perl_hv_copy_hints_hv(aTHX_ GvHV(PL_hintgv)));
        cUNOPo->op_first->op_sibling = hhop;
        o->op_private |= OPpEVAL_HAS_HH;
     }
@@ -5379,7 +6232,8 @@ Perl_ck_exists(pTHX_ OP *o)
        OP * const kid = cUNOPo->op_first;
        if (kid->op_type == OP_ENTERSUB) {
            (void) ref(kid, o->op_type);
-           if (kid->op_type != OP_RV2CV && !PL_error_count)
+           if (kid->op_type != OP_RV2CV
+                       && !(PL_parser && PL_parser->error_count))
                Perl_croak(aTHX_ "%s argument is not a subroutine name",
                            OP_DESC(o));
            o->op_private |= OPpEXISTS_SUB;
@@ -5412,24 +6266,24 @@ Perl_ck_rvconst(pTHX_ register OP *o)
        /* Is it a constant from cv_const_sv()? */
        if (SvROK(kidsv) && SvREADONLY(kidsv)) {
            SV * const rsv = SvRV(kidsv);
-           const int svtype = SvTYPE(rsv);
+           const svtype type = SvTYPE(rsv);
             const char *badtype = NULL;
 
            switch (o->op_type) {
            case OP_RV2SV:
-               if (svtype > SVt_PVMG)
+               if (type > SVt_PVMG)
                    badtype = "a SCALAR";
                break;
            case OP_RV2AV:
-               if (svtype != SVt_PVAV)
+               if (type != SVt_PVAV)
                    badtype = "an ARRAY";
                break;
            case OP_RV2HV:
-               if (svtype != SVt_PVHV)
+               if (type != SVt_PVHV)
                    badtype = "a HASH";
                break;
            case OP_RV2CV:
-               if (svtype != SVt_PVCV)
+               if (type != SVt_PVCV)
                    badtype = "a CODE";
                break;
            }
@@ -5449,7 +6303,7 @@ Perl_ck_rvconst(pTHX_ register OP *o)
                o->op_private &= ~HINT_STRICT_REFS;
        }
        if ((o->op_private & HINT_STRICT_REFS) && (kid->op_private & OPpCONST_BARE)) {
-            const char *badthing = NULL;
+           const char *badthing;
            switch (o->op_type) {
            case OP_RV2SV:
                badthing = "a SCALAR";
@@ -5460,11 +6314,14 @@ Perl_ck_rvconst(pTHX_ register OP *o)
            case OP_RV2HV:
                badthing = "a HASH";
                break;
+           default:
+               badthing = NULL;
+               break;
            }
            if (badthing)
                Perl_croak(aTHX_
-         "Can't use bareword (\"%"SVf"\") as %s ref while \"strict refs\" in use",
-                     kidsv, badthing);
+                          "Can't use bareword (\"%"SVf"\") as %s ref while \"strict refs\" in use",
+                          SVfARG(kidsv), badthing);
        }
        /*
         * This is a little tricky.  We only want to add the symbol if we
@@ -5496,9 +6353,9 @@ Perl_ck_rvconst(pTHX_ register OP *o)
            kPADOP->op_padix = pad_alloc(OP_GV, SVs_PADTMP);
            SvREFCNT_dec(PAD_SVl(kPADOP->op_padix));
            GvIN_PAD_on(gv);
-           PAD_SETSV(kPADOP->op_padix, (SV*) SvREFCNT_inc(gv));
+           PAD_SETSV(kPADOP->op_padix, (SV*) SvREFCNT_inc_simple_NN(gv));
 #else
-           kid->op_sv = SvREFCNT_inc(gv);
+           kid->op_sv = SvREFCNT_inc_simple_NN(gv);
 #endif
            kid->op_private = 0;
            kid->op_ppaddr = PL_ppaddr[OP_GV];
@@ -5514,33 +6371,39 @@ Perl_ck_ftst(pTHX_ OP *o)
     const I32 type = o->op_type;
 
     if (o->op_flags & OPf_REF) {
-       /* nothing */
+       NOOP;
     }
     else if (o->op_flags & OPf_KIDS && cUNOPo->op_first->op_type != OP_STUB) {
        SVOP * const kid = (SVOP*)cUNOPo->op_first;
+       const OPCODE kidtype = kid->op_type;
 
-       if (kid->op_type == OP_CONST && (kid->op_private & OPpCONST_BARE)) {
+       if (kidtype == OP_CONST && (kid->op_private & OPpCONST_BARE)) {
            OP * const newop = newGVOP(type, OPf_REF,
                gv_fetchsv(kid->op_sv, GV_ADD, SVt_PVIO));
+#ifdef PERL_MAD
+           op_getmad(o,newop,'O');
+#else
            op_free(o);
-           o = newop;
-           return o;
+#endif
+           return newop;
        }
-       else {
-         if ((PL_hints & HINT_FILETEST_ACCESS) &&
-             OP_IS_FILETEST_ACCESS(o))
+       if ((PL_hints & HINT_FILETEST_ACCESS) && OP_IS_FILETEST_ACCESS(o))
            o->op_private |= OPpFT_ACCESS;
-       }
-       if (PL_check[kid->op_type] == MEMBER_TO_FPTR(Perl_ck_ftst)
-               && kid->op_type != OP_STAT && kid->op_type != OP_LSTAT)
+       if (PL_check[kidtype] == MEMBER_TO_FPTR(Perl_ck_ftst)
+               && kidtype != OP_STAT && kidtype != OP_LSTAT)
            o->op_private |= OPpFT_STACKED;
     }
     else {
+#ifdef PERL_MAD
+       OP* const oldo = o;
+#else
        op_free(o);
+#endif
        if (type == OP_FTTTY)
            o = newGVOP(type, OPf_REF, PL_stdingv);
        else
            o = newUNOP(type, 0, newDEFSVOP());
+       op_getmad(oldo,o,'O');
     }
     return o;
 }
@@ -5577,6 +6440,12 @@ Perl_ck_fun(pTHX_ OP *o)
        while (oa && kid) {
            numargs++;
            sibl = kid->op_sibling;
+#ifdef PERL_MAD
+           if (!sibl && kid->op_type == OP_STUB) {
+               numargs--;
+               break;
+           }
+#endif
            switch (oa & 7) {
            case OA_SCALAR:
                /* list seen where single (scalar) arg expected? */
@@ -5610,8 +6479,12 @@ Perl_ck_fun(pTHX_ OP *o)
                    if (ckWARN2(WARN_DEPRECATED, WARN_SYNTAX))
                        Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
                            "Array @%"SVf" missing the @ in argument %"IVdf" of %s()",
-                           ((SVOP*)kid)->op_sv, (IV)numargs, PL_op_desc[type]);
+                           SVfARG(((SVOP*)kid)->op_sv), (IV)numargs, PL_op_desc[type]);
+#ifdef PERL_MAD
+                   op_getmad(kid,newop,'K');
+#else
                    op_free(kid);
+#endif
                    kid = newop;
                    kid->op_sibling = sibl;
                    *tokid = kid;
@@ -5629,8 +6502,12 @@ Perl_ck_fun(pTHX_ OP *o)
                    if (ckWARN2(WARN_DEPRECATED, WARN_SYNTAX))
                        Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
                            "Hash %%%"SVf" missing the %% in argument %"IVdf" of %s()",
-                           ((SVOP*)kid)->op_sv, (IV)numargs, PL_op_desc[type]);
+                           SVfARG(((SVOP*)kid)->op_sv), (IV)numargs, PL_op_desc[type]);
+#ifdef PERL_MAD
+                   op_getmad(kid,newop,'K');
+#else
                    op_free(kid);
+#endif
                    kid = newop;
                    kid->op_sibling = sibl;
                    *tokid = kid;
@@ -5660,7 +6537,11 @@ Perl_ck_fun(pTHX_ OP *o)
                        if (!(o->op_private & 1) && /* if not unop */
                            kid == cLISTOPo->op_last)
                            cLISTOPo->op_last = newop;
+#ifdef PERL_MAD
+                       op_getmad(kid,newop,'K');
+#else
                        op_free(kid);
+#endif
                        kid = newop;
                    }
                    else if (kid->op_type == OP_READLINE) {
@@ -5684,13 +6565,9 @@ Perl_ck_fun(pTHX_ OP *o)
                             */
                            priv = OPpDEREF;
                            if (kid->op_type == OP_PADSV) {
-                               name = PAD_COMPNAME_PV(kid->op_targ);
-                               /* SvCUR of a pad namesv can't be trusted
-                                * (see PL_generation), so calc its length
-                                * manually */
-                               if (name)
-                                   len = strlen(name);
-
+                               SV *const namesv
+                                   = PAD_COMPNAME_SV(kid->op_targ);
+                               name = SvPV_const(namesv, len);
                            }
                            else if (kid->op_type == OP_RV2SV
                                     && kUNOP->op_first->op_type == OP_GV)
@@ -5702,19 +6579,20 @@ Perl_ck_fun(pTHX_ OP *o)
                            else if (kid->op_type == OP_AELEM
                                     || kid->op_type == OP_HELEM)
                            {
+                                OP *firstop;
                                 OP *op = ((BINOP*)kid)->op_first;
                                 name = NULL;
                                 if (op) {
-                                     SV *tmpstr = Nullsv;
+                                     SV *tmpstr = NULL;
                                      const char * const a =
                                           kid->op_type == OP_AELEM ?
                                           "[]" : "{}";
                                      if (((op->op_type == OP_RV2AV) ||
                                           (op->op_type == OP_RV2HV)) &&
-                                         (op = ((UNOP*)op)->op_first) &&
-                                         (op->op_type == OP_GV)) {
+                                         (firstop = ((UNOP*)op)->op_first) &&
+                                         (firstop->op_type == OP_GV)) {
                                           /* packagevar $a[] or $h{} */
-                                          GV * const gv = cGVOPx_gv(op);
+                                          GV * const gv = cGVOPx_gv(firstop);
                                           if (gv)
                                                tmpstr =
                                                     Perl_newSVpvf(aTHX_
@@ -5773,14 +6651,28 @@ Perl_ck_fun(pTHX_ OP *o)
            tokid = &kid->op_sibling;
            kid = kid->op_sibling;
        }
+#ifdef PERL_MAD
+       if (kid && kid->op_type != OP_STUB)
+           return too_many_arguments(o,OP_DESC(o));
+       o->op_private |= numargs;
+#else
+       /* FIXME - should the numargs move as for the PERL_MAD case?  */
        o->op_private |= numargs;
        if (kid)
            return too_many_arguments(o,OP_DESC(o));
+#endif
        listkids(o);
     }
     else if (PL_opargs[type] & OA_DEFGV) {
+#ifdef PERL_MAD
+       OP *newop = newUNOP(type, 0, newDEFSVOP());
+       op_getmad(o,newop,'O');
+       return newop;
+#else
+       /* Ordering of these two is important to keep f_map.t passing.  */
        op_free(o);
        return newUNOP(type, 0, newDEFSVOP());
+#endif
     }
 
     if (oa) {
@@ -5814,11 +6706,11 @@ Perl_ck_glob(pTHX_ OP *o)
        GV *glob_gv;
        ENTER;
        Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT,
-               newSVpvs("File::Glob"), Nullsv, Nullsv, Nullsv);
+               newSVpvs("File::Glob"), NULL, NULL, NULL);
        gv = gv_fetchpvs("CORE::GLOBAL::glob", 0, SVt_PVCV);
        glob_gv = gv_fetchpvs("File::Glob::csh_glob", 0, SVt_PVCV);
        GvCV(gv) = GvCV(glob_gv);
-       (void)SvREFCNT_inc((SV*)GvCV(gv));
+       SvREFCNT_inc_void((SV*)GvCV(gv));
        GvIMPORTED_CV_on(gv);
        LEAVE;
     }
@@ -5851,13 +6743,13 @@ OP *
 Perl_ck_grep(pTHX_ OP *o)
 {
     dVAR;
-    LOGOP *gwop;
+    LOGOP *gwop = NULL;
     OP *kid;
     const OPCODE type = o->op_type == OP_GREPSTART ? OP_GREPWHILE : OP_MAPWHILE;
-    I32 offset;
+    PADOFFSET offset;
 
     o->op_ppaddr = PL_ppaddr[OP_GREPSTART];
-    NewOp(1101, gwop, 1, LOGOP);
+    /* don't allocate gwop here, as we may leak it if PL_parser->error_count > 0 */
 
     if (o->op_flags & OPf_STACKED) {
        OP* k;
@@ -5868,6 +6760,7 @@ Perl_ck_grep(pTHX_ OP *o)
        for (k = cUNOPx(kid)->op_first; k; k = k->op_next) {
            kid = k;
        }
+       NewOp(1101, gwop, 1, LOGOP);
        kid->op_next = (OP*)gwop;
        o->op_flags &= ~OPf_STACKED;
     }
@@ -5877,13 +6770,15 @@ Perl_ck_grep(pTHX_ OP *o)
     else
        scalar(kid);
     o = ck_fun(o);
-    if (PL_error_count)
+    if (PL_parser && PL_parser->error_count)
        return o;
     kid = cLISTOPo->op_first->op_sibling;
     if (kid->op_type != OP_NULL)
        Perl_croak(aTHX_ "panic: ck_grep");
     kid = kUNOP->op_first;
 
+    if (!gwop)
+       NewOp(1101, gwop, 1, LOGOP);
     gwop->op_type = type;
     gwop->op_ppaddr = PL_ppaddr[type];
     gwop->op_first = listkids(o);
@@ -5891,7 +6786,7 @@ Perl_ck_grep(pTHX_ OP *o)
     gwop->op_other = LINKLIST(kid);
     kid->op_next = (OP*)gwop;
     offset = pad_findmy("$_");
-    if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS(offset) & SVpad_OUR) {
+    if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS_isOUR(offset)) {
        o->op_private = gwop->op_private = 0;
        gwop->op_targ = pad_alloc(type, SVs_PADTMP);
     }
@@ -5975,6 +6870,22 @@ Perl_ck_defined(pTHX_ OP *o)             /* 19990527 MJD */
 }
 
 OP *
+Perl_ck_readline(pTHX_ OP *o)
+{
+    if (!(o->op_flags & OPf_KIDS)) {
+       OP * const newop
+           = newUNOP(OP_READLINE, 0, newGVOP(OP_GV, 0, PL_argvgv));
+#ifdef PERL_MAD
+       op_getmad(o,newop,'O');
+#else
+       op_free(o);
+#endif
+       return newop;
+    }
+    return o;
+}
+
+OP *
 Perl_ck_rfun(pTHX_ OP *o)
 {
     const OPCODE type = o->op_type;
@@ -6012,16 +6923,6 @@ Perl_ck_listiob(pTHX_ OP *o)
 }
 
 OP *
-Perl_ck_say(pTHX_ OP *o)
-{
-    o = ck_listiob(o);
-    o->op_type = OP_PRINT;
-    cLISTOPo->op_last = cLISTOPo->op_last->op_sibling
-       = newSVOP(OP_CONST, 0, newSVpvs("\n"));
-    return o;
-}
-
-OP *
 Perl_ck_smartmatch(pTHX_ OP *o)
 {
     dVAR;
@@ -6030,7 +6931,7 @@ Perl_ck_smartmatch(pTHX_ OP *o)
        OP *second = first->op_sibling;
        
        /* Implicitly take a reference to an array or hash */
-       first->op_sibling = Nullop;
+       first->op_sibling = NULL;
        first = cBINOPo->op_first = ref_array_or_hash(first);
        second = first->op_sibling = ref_array_or_hash(second);
        
@@ -6052,12 +6953,15 @@ Perl_ck_smartmatch(pTHX_ OP *o)
 OP *
 Perl_ck_sassign(pTHX_ OP *o)
 {
-    OP *kid = cLISTOPo->op_first;
+    OP * const kid = cLISTOPo->op_first;
     /* has a disposable target? */
     if ((PL_opargs[kid->op_type] & OA_TARGLEX)
        && !(kid->op_flags & OPf_STACKED)
        /* Cannot steal the second time! */
-       && !(kid->op_private & OPpTARGET_MY))
+       && !(kid->op_private & OPpTARGET_MY)
+       /* Keep the full thing for madskills */
+       && !PL_madskills
+       )
     {
        OP * const kkid = kid->op_sibling;
 
@@ -6084,8 +6988,8 @@ Perl_ck_match(pTHX_ OP *o)
 {
     dVAR;
     if (o->op_type != OP_QR && PL_compcv) {
-       const I32 offset = pad_findmy("$_");
-       if (offset != NOT_IN_PAD && !(PAD_COMPNAME_FLAGS(offset) & SVpad_OUR)) {
+       const PADOFFSET offset = pad_findmy("$_");
+       if (offset != NOT_IN_PAD && !(PAD_COMPNAME_FLAGS_isOUR(offset))) {
            o->op_targ = offset;
            o->op_private |= OPpTARGET_MY;
        }
@@ -6108,10 +7012,14 @@ Perl_ck_method(pTHX_ OP *o)
                sv = newSVpvn_share(method, SvCUR(sv), 0);
            }
            else {
-               kSVOP->op_sv = Nullsv;
+               kSVOP->op_sv = NULL;
            }
            cmop = newSVOP(OP_METHOD_NAMED, 0, sv);
+#ifdef PERL_MAD
+           op_getmad(o,cmop,'O');
+#else
            op_free(o);
+#endif
            return cmop;
        }
     }
@@ -6121,6 +7029,7 @@ Perl_ck_method(pTHX_ OP *o)
 OP *
 Perl_ck_null(pTHX_ OP *o)
 {
+    PERL_UNUSED_CONTEXT;
     return o;
 }
 
@@ -6148,8 +7057,18 @@ Perl_ck_open(pTHX_ OP *o)
                o->op_private |= OPpOPEN_OUT_CRLF;
        }
     }
-    if (o->op_type == OP_BACKTICK)
+    if (o->op_type == OP_BACKTICK) {
+       if (!(o->op_flags & OPf_KIDS)) {
+           OP * const newop = newUNOP(OP_BACKTICK, 0, newDEFSVOP());
+#ifdef PERL_MAD
+           op_getmad(o,newop,'O');
+#else
+           op_free(o);
+#endif
+           return newop;
+       }
        return o;
+    }
     {
         /* In case of three-arg dup open remove strictness
          * from the last arg if it is a bareword. */
@@ -6189,7 +7108,7 @@ OP *
 Perl_ck_require(pTHX_ OP *o)
 {
     dVAR;
-    GV* gv = Nullgv;
+    GV* gv = NULL;
 
     if (o->op_flags & OPf_KIDS) {      /* Shall we supply missing .pm? */
        SVOP * const kid = (SVOP*)cUNOPo->op_first;
@@ -6227,19 +7146,25 @@ Perl_ck_require(pTHX_ OP *o)
        gv = gv_fetchpvs("require", GV_NOTQUAL, SVt_PVCV);
        if (!(gv && GvCVu(gv) && GvIMPORTED_CV(gv))) {
            GV * const * const gvp = (GV**)hv_fetchs(PL_globalstash, "require", FALSE);
-           gv = gvp ? *gvp : Nullgv;
+           gv = gvp ? *gvp : NULL;
        }
     }
 
     if (gv && GvCVu(gv) && GvIMPORTED_CV(gv)) {
        OP * const kid = cUNOPo->op_first;
+       OP * newop;
+
        cUNOPo->op_first = 0;
+#ifndef PERL_MAD
        op_free(o);
-       return ck_subr(newUNOP(OP_ENTERSUB, OPf_STACKED,
-                              append_elem(OP_LIST, kid,
-                                          scalar(newUNOP(OP_RV2CV, 0,
-                                                         newGVOP(OP_GV, 0,
-                                                                 gv))))));
+#endif
+       newop = ck_subr(newUNOP(OP_ENTERSUB, OPf_STACKED,
+                               append_elem(OP_LIST, kid,
+                                           scalar(newUNOP(OP_RV2CV, 0,
+                                                          newGVOP(OP_GV, 0,
+                                                                  gv))))));
+       op_getmad(o,newop,'O');
+       return newop;
     }
 
     return ck_fun(o);
@@ -6286,11 +7211,21 @@ Perl_ck_shift(pTHX_ OP *o)
 
     if (!(o->op_flags & OPf_KIDS)) {
        OP *argop;
-
+       /* FIXME - this can be refactored to reduce code in #ifdefs  */
+#ifdef PERL_MAD
+       OP * const oldo = o;
+#else
        op_free(o);
+#endif
        argop = newUNOP(OP_RV2AV, 0,
            scalar(newGVOP(OP_GV, 0, CvUNIQUE(PL_compcv) ? PL_argvgv : PL_defgv)));
+#ifdef PERL_MAD
+       o = newUNOP(type, 0, scalar(argop));
+       op_getmad(oldo,o,'O');
+       return o;
+#else
        return newUNOP(type, 0, scalar(argop));
+#endif
     }
     return scalar(modkids(ck_fun(o), type));
 }
@@ -6301,8 +7236,7 @@ Perl_ck_sort(pTHX_ OP *o)
     dVAR;
     OP *firstkid;
 
-    if (o->op_type == OP_SORT && (PL_hints & HINT_LOCALIZE_HH) != 0)
-    {
+    if (o->op_type == OP_SORT && (PL_hints & HINT_LOCALIZE_HH) != 0) {
        HV * const hinthv = GvHV(PL_hintgv);
        if (hinthv) {
            SV ** const svp = hv_fetchs(hinthv, "sort", FALSE);
@@ -6441,7 +7375,11 @@ S_simplify_sort(pTHX_ OP *o)
        o->op_private |= OPpSORT_NUMERIC | OPpSORT_INTEGER;
     kid = cLISTOPo->op_first->op_sibling;
     cLISTOPo->op_first->op_sibling = kid->op_sibling; /* bypass old block */
+#ifdef PERL_MAD
+    op_getmad(kid,o,'S');                            /* then delete it */
+#else
     op_free(kid);                                    /* then delete it */
+#endif
 }
 
 OP *
@@ -6490,6 +7428,7 @@ Perl_ck_split(pTHX_ OP *o)
 
     if (!kid->op_sibling)
        append_elem(OP_SPLIT, o, newSVOP(OP_CONST, 0, newSViv(0)));
+    assert(kid->op_sibling);
 
     kid = kid->op_sibling;
     scalar(kid);
@@ -6508,9 +7447,10 @@ Perl_ck_join(pTHX_ OP *o)
        if (ckWARN(WARN_SYNTAX)) {
             const REGEXP *re = PM_GETRE(kPMOP);
            const char *pmstr = re ? re->precomp : "STRING";
+           const STRLEN len = re ? re->prelen : 6;
            Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
-                       "/%s/ should probably be written as \"%s\"",
-                       pmstr, pmstr);
+                       "/%.*s/ should probably be written as \"%.*s\"",
+                       (int)len, pmstr, (int)len, pmstr);
        }
     }
     return ck_fun(o);
@@ -6524,13 +7464,14 @@ Perl_ck_subr(pTHX_ OP *o)
             ? cUNOPo : ((UNOP*)cUNOPo->op_first))->op_first;
     OP *o2 = prev->op_sibling;
     OP *cvop;
-    char *proto = NULL;
+    const char *proto = NULL;
+    const char *proto_end = NULL;
     CV *cv = NULL;
     GV *namegv = NULL;
     int optional = 0;
     I32 arg = 0;
     I32 contextclass = 0;
-    char *e = NULL;
+    const char *e = NULL;
     bool delete_op = 0;
 
     o->op_private |= OPpENTERSUB_HASTARG;
@@ -6547,21 +7488,10 @@ Perl_ck_subr(pTHX_ OP *o)
                tmpop->op_private |= OPpEARLY_CV;
            else {
                if (SvPOK(cv)) {
+                   STRLEN len;
                    namegv = CvANON(cv) ? gv : CvGV(cv);
-                   proto = SvPV_nolen((SV*)cv);
-               }
-               if (CvASSERTION(cv)) {
-                   if (PL_hints & HINT_ASSERTING) {
-                       if (PERLDB_ASSERTION && PL_curstash != PL_debstash)
-                           o->op_private |= OPpENTERSUB_DB;
-                   }
-                   else {
-                       delete_op = 1;
-                       if (!(PL_hints & HINT_ASSERTIONSSEEN) && ckWARN(WARN_ASSERTIONS)) {
-                           Perl_warner(aTHX_ packWARN(WARN_ASSERTIONS),
-                                       "Impossible to activate assertion call");
-                       }
-                   }
+                   proto = SvPV((SV*)cv, len);
+                   proto_end = proto + len;
                }
            }
        }
@@ -6570,23 +7500,37 @@ Perl_ck_subr(pTHX_ OP *o)
        if (o2->op_type == OP_CONST)
            o2->op_private &= ~OPpCONST_STRICT;
        else if (o2->op_type == OP_LIST) {
-           OP * const o = ((UNOP*)o2)->op_first->op_sibling;
-           if (o && o->op_type == OP_CONST)
-               o->op_private &= ~OPpCONST_STRICT;
+           OP * const sib = ((UNOP*)o2)->op_first->op_sibling;
+           if (sib && sib->op_type == OP_CONST)
+               sib->op_private &= ~OPpCONST_STRICT;
        }
     }
     o->op_private |= (PL_hints & HINT_STRICT_REFS);
     if (PERLDB_SUB && PL_curstash != PL_debstash)
        o->op_private |= OPpENTERSUB_DB;
     while (o2 != cvop) {
+       OP* o3;
+       if (PL_madskills && o2->op_type == OP_STUB) {
+           o2 = o2->op_sibling;
+           continue;
+       }
+       if (PL_madskills && o2->op_type == OP_NULL)
+           o3 = ((UNOP*)o2)->op_first;
+       else
+           o3 = o2;
        if (proto) {
-           switch (*proto) {
-           case '\0':
+           if (proto >= proto_end)
                return too_many_arguments(o, gv_ename(namegv));
+
+           switch (*proto) {
            case ';':
                optional = 1;
                proto++;
                continue;
+           case '_':
+               /* _ must be at the end */
+               if (proto[1] && proto[1] != ';')
+                   goto oops;
            case '$':
                proto++;
                arg++;
@@ -6600,22 +7544,22 @@ Perl_ck_subr(pTHX_ OP *o)
            case '&':
                proto++;
                arg++;
-               if (o2->op_type != OP_REFGEN && o2->op_type != OP_UNDEF)
+               if (o3->op_type != OP_REFGEN && o3->op_type != OP_UNDEF)
                    bad_type(arg,
                        arg == 1 ? "block or sub {}" : "sub {}",
-                       gv_ename(namegv), o2);
+                       gv_ename(namegv), o3);
                break;
            case '*':
                /* '*' allows any scalar type, including bareword */
                proto++;
                arg++;
-               if (o2->op_type == OP_RV2GV)
+               if (o3->op_type == OP_RV2GV)
                    goto wrapref;       /* autoconvert GLOB -> GLOBref */
-               else if (o2->op_type == OP_CONST)
-                   o2->op_private &= ~OPpCONST_STRICT;
-               else if (o2->op_type == OP_ENTERSUB) {
+               else if (o3->op_type == OP_CONST)
+                   o3->op_private &= ~OPpCONST_STRICT;
+               else if (o3->op_type == OP_ENTERSUB) {
                    /* accidental subroutine, revert to bareword */
-                   OP *gvop = ((UNOP*)o2)->op_first;
+                   OP *gvop = ((UNOP*)o3)->op_first;
                    if (gvop && gvop->op_type == OP_NULL) {
                        gvop = ((UNOP*)gvop)->op_first;
                        if (gvop) {
@@ -6629,9 +7573,14 @@ Perl_ck_subr(pTHX_ OP *o)
                                GV * const gv = cGVOPx_gv(gvop);
                                OP * const sibling = o2->op_sibling;
                                SV * const n = newSVpvs("");
+#ifdef PERL_MAD
+                               OP * const oldo2 = o2;
+#else
                                op_free(o2);
+#endif
                                gv_fullname4(n, gv, "", FALSE);
                                o2 = newSVOP(OP_CONST, 0, n);
+                               op_getmad(oldo2,o2,'O');
                                prev->op_sibling = o2;
                                o2->op_sibling = sibling;
                            }
@@ -6660,53 +7609,51 @@ Perl_ck_subr(pTHX_ OP *o)
                     break;
                case ']':
                     if (contextclass) {
-                        /* XXX We shouldn't be modifying proto, so we can const proto */
-                        char *p = proto;
-                        const char s = *p;
+                        const char *p = proto;
+                        const char *const end = proto;
                         contextclass = 0;
-                        *p = '\0';
                         while (*--p != '[');
-                        bad_type(arg, Perl_form(aTHX_ "one of %s", p),
-                                gv_ename(namegv), o2);
-                        *proto = s;
+                        bad_type(arg, Perl_form(aTHX_ "one of %.*s",
+                                                (int)(end - p), p),
+                                 gv_ename(namegv), o3);
                     } else
                          goto oops;
                     break;
                case '*':
-                    if (o2->op_type == OP_RV2GV)
+                    if (o3->op_type == OP_RV2GV)
                          goto wrapref;
                     if (!contextclass)
-                         bad_type(arg, "symbol", gv_ename(namegv), o2);
+                         bad_type(arg, "symbol", gv_ename(namegv), o3);
                     break;
                case '&':
-                    if (o2->op_type == OP_ENTERSUB)
+                    if (o3->op_type == OP_ENTERSUB)
                          goto wrapref;
                     if (!contextclass)
-                         bad_type(arg, "subroutine entry", gv_ename(namegv), o2);
+                         bad_type(arg, "subroutine entry", gv_ename(namegv),
+                                  o3);
                     break;
                case '$':
-                   if (o2->op_type == OP_RV2SV ||
-                       o2->op_type == OP_PADSV ||
-                       o2->op_type == OP_HELEM ||
-                       o2->op_type == OP_AELEM ||
-                       o2->op_type == OP_THREADSV)
+                   if (o3->op_type == OP_RV2SV ||
+                       o3->op_type == OP_PADSV ||
+                       o3->op_type == OP_HELEM ||
+                       o3->op_type == OP_AELEM)
                         goto wrapref;
                    if (!contextclass)
-                       bad_type(arg, "scalar", gv_ename(namegv), o2);
+                       bad_type(arg, "scalar", gv_ename(namegv), o3);
                     break;
                case '@':
-                   if (o2->op_type == OP_RV2AV ||
-                       o2->op_type == OP_PADAV)
+                   if (o3->op_type == OP_RV2AV ||
+                       o3->op_type == OP_PADAV)
                         goto wrapref;
                    if (!contextclass)
-                       bad_type(arg, "array", gv_ename(namegv), o2);
+                       bad_type(arg, "array", gv_ename(namegv), o3);
                    break;
                case '%':
-                   if (o2->op_type == OP_RV2HV ||
-                       o2->op_type == OP_PADHV)
+                   if (o3->op_type == OP_RV2HV ||
+                       o3->op_type == OP_PADHV)
                         goto wrapref;
                    if (!contextclass)
-                        bad_type(arg, "hash", gv_ename(namegv), o2);
+                        bad_type(arg, "hash", gv_ename(namegv), o3);
                    break;
                wrapref:
                    {
@@ -6733,7 +7680,7 @@ Perl_ck_subr(pTHX_ OP *o)
            default:
              oops:
                Perl_croak(aTHX_ "Malformed prototype for %s: %"SVf,
-                          gv_ename(namegv), cv);
+                          gv_ename(namegv), SVfARG(cv));
            }
        }
        else
@@ -6742,12 +7689,23 @@ Perl_ck_subr(pTHX_ OP *o)
        prev = o2;
        o2 = o2->op_sibling;
     } /* while */
-    if (proto && !optional &&
-         (*proto && *proto != '@' && *proto != '%' && *proto != ';'))
+    if (o2 == cvop && proto && *proto == '_') {
+       /* generate an access to $_ */
+       o2 = newDEFSVOP();
+       o2->op_sibling = prev->op_sibling;
+       prev->op_sibling = o2; /* instead of cvop */
+    }
+    if (proto && !optional && proto_end > proto &&
+       (*proto != '@' && *proto != '%' && *proto != ';' && *proto != '_'))
        return too_few_arguments(o, gv_ename(namegv));
     if(delete_op) {
+#ifdef PERL_MAD
+       OP * const oldo = o;
+#else
        op_free(o);
+#endif
        o=newSVOP(OP_CONST, 0, newSViv(0));
+       op_getmad(oldo,o,'O');
     }
     return o;
 }
@@ -6755,11 +7713,28 @@ Perl_ck_subr(pTHX_ OP *o)
 OP *
 Perl_ck_svconst(pTHX_ OP *o)
 {
+    PERL_UNUSED_CONTEXT;
     SvREADONLY_on(cSVOPo->op_sv);
     return o;
 }
 
 OP *
+Perl_ck_chdir(pTHX_ OP *o)
+{
+    if (o->op_flags & OPf_KIDS) {
+       SVOP * const kid = (SVOP*)cUNOPo->op_first;
+
+       if (kid && kid->op_type == OP_CONST &&
+           (kid->op_private & OPpCONST_BARE))
+       {
+           o->op_flags |= OPf_SPECIAL;
+           kid->op_private &= ~OPpCONST_STRICT;
+       }
+    }
+    return ck_fun(o);
+}
+
+OP *
 Perl_ck_trunc(pTHX_ OP *o)
 {
     if (o->op_flags & OPf_KIDS) {
@@ -6793,7 +7768,7 @@ OP *
 Perl_ck_substr(pTHX_ OP *o)
 {
     o = ck_fun(o);
-    if ((o->op_flags & OPf_KIDS) && o->op_private == 4) {
+    if ((o->op_flags & OPf_KIDS) && (o->op_private == 4)) {
        OP *kid = cLISTOPo->op_first;
 
        if (kid->op_type == OP_NULL)
@@ -6823,13 +7798,15 @@ Perl_peep(pTHX_ register OP *o)
     for (; o; o = o->op_next) {
        if (o->op_opt)
            break;
+       /* By default, this op has now been optimised. A couple of cases below
+          clear this again.  */
+       o->op_opt = 1;
        PL_op = o;
        switch (o->op_type) {
        case OP_SETSTATE:
        case OP_NEXTSTATE:
        case OP_DBSTATE:
            PL_curcop = ((COP*)o);              /* for warnings */
-           o->op_opt = 1;
            break;
 
        case OP_CONST:
@@ -6868,18 +7845,17 @@ Perl_peep(pTHX_ register OP *o)
                    /* XXX I don't know how this isn't readonly already. */
                    SvREADONLY_on(PAD_SVl(ix));
                }
-               cSVOPo->op_sv = Nullsv;
+               cSVOPo->op_sv = NULL;
                o->op_targ = ix;
            }
 #endif
-           o->op_opt = 1;
            break;
 
        case OP_CONCAT:
            if (o->op_next && o->op_next->op_type == OP_STRINGIFY) {
                if (o->op_next->op_private & OPpTARGET_MY) {
                    if (o->op_flags & OPf_STACKED) /* chained concats */
-                       goto ignore_optimization;
+                       break; /* ignore_optimization */
                    else {
                        /* assert(PL_opargs[o->op_type] & OA_TARGLEX); */
                        o->op_targ = o->op_next->op_targ;
@@ -6889,12 +7865,9 @@ Perl_peep(pTHX_ register OP *o)
                }
                op_null(o->op_next);
            }
-         ignore_optimization:
-           o->op_opt = 1;
            break;
        case OP_STUB:
            if ((o->op_flags & OPf_WANT) != OPf_WANT_LIST) {
-               o->op_opt = 1;
                break; /* Scalar stub must produce undef.  List stub is noop */
            }
            goto nothin;
@@ -6910,20 +7883,17 @@ Perl_peep(pTHX_ register OP *o)
               has already occurred. This doesn't fix the real problem,
               though (See 20010220.007). AMS 20010719 */
            /* op_seq functionality is now replaced by op_opt */
-           if (oldop && o->op_next) {
-               oldop->op_next = o->op_next;
-               continue;
-           }
-           break;
+           o->op_opt = 0;
+           /* FALL THROUGH */
        case OP_SCALAR:
        case OP_LINESEQ:
        case OP_SCOPE:
-         nothin:
+       nothin:
            if (oldop && o->op_next) {
                oldop->op_next = o->op_next;
+               o->op_opt = 0;
                continue;
            }
-           o->op_opt = 1;
            break;
 
        case OP_PADAV:
@@ -6937,7 +7907,7 @@ Perl_peep(pTHX_ register OP *o)
                    pop->op_next->op_type == OP_AELEM &&
                    !(pop->op_next->op_private &
                      (OPpLVAL_INTRO|OPpLVAL_DEFER|OPpDEREF|OPpMAYBE_LVSUB)) &&
-                   (i = SvIV(((SVOP*)pop)->op_sv) - PL_curcop->cop_arybase)
+                   (i = SvIV(((SVOP*)pop)->op_sv) - CopARYBASE_get(PL_curcop))
                                <= 255 &&
                    i >= 0)
                {
@@ -6960,7 +7930,6 @@ Perl_peep(pTHX_ register OP *o)
                        o->op_flags |= OPf_SPECIAL;
                    o->op_type = OP_AELEMFAST;
                }
-               o->op_opt = 1;
                break;
            }
 
@@ -6982,7 +7951,7 @@ Perl_peep(pTHX_ register OP *o)
                    gv_efullname3(sv, gv, NULL);
                    Perl_warner(aTHX_ packWARN(WARN_PROTOTYPE),
                                "%"SVf"() called too early to check prototype",
-                               sv);
+                               SVfARG(sv));
                }
            }
            else if (o->op_next->op_type == OP_READLINE
@@ -6997,7 +7966,6 @@ Perl_peep(pTHX_ register OP *o)
                op_null(o->op_next);
            }
 
-           o->op_opt = 1;
            break;
 
        case OP_MAPWHILE:
@@ -7010,7 +7978,6 @@ Perl_peep(pTHX_ register OP *o)
        case OP_DORASSIGN:
        case OP_COND_EXPR:
        case OP_RANGE:
-           o->op_opt = 1;
            while (cLOGOP->op_other->op_type == OP_NULL)
                cLOGOP->op_other = cLOGOP->op_other->op_next;
            peep(cLOGOP->op_other); /* Recursive calls are not replaced by fptr calls */
@@ -7018,7 +7985,6 @@ Perl_peep(pTHX_ register OP *o)
 
        case OP_ENTERLOOP:
        case OP_ENTERITER:
-           o->op_opt = 1;
            while (cLOOP->op_redoop->op_type == OP_NULL)
                cLOOP->op_redoop = cLOOP->op_redoop->op_next;
            peep(cLOOP->op_redoop);
@@ -7030,33 +7996,30 @@ Perl_peep(pTHX_ register OP *o)
            peep(cLOOP->op_lastop);
            break;
 
-       case OP_QR:
-       case OP_MATCH:
        case OP_SUBST:
-           o->op_opt = 1;
-           while (cPMOP->op_pmreplstart &&
-                  cPMOP->op_pmreplstart->op_type == OP_NULL)
-               cPMOP->op_pmreplstart = cPMOP->op_pmreplstart->op_next;
-           peep(cPMOP->op_pmreplstart);
+           assert(!(cPMOP->op_pmflags & PMf_ONCE));
+           while (cPMOP->op_pmstashstartu.op_pmreplstart &&
+                  cPMOP->op_pmstashstartu.op_pmreplstart->op_type == OP_NULL)
+               cPMOP->op_pmstashstartu.op_pmreplstart
+                   = cPMOP->op_pmstashstartu.op_pmreplstart->op_next;
+           peep(cPMOP->op_pmstashstartu.op_pmreplstart);
            break;
 
        case OP_EXEC:
-           o->op_opt = 1;
            if (o->op_next && o->op_next->op_type == OP_NEXTSTATE
                && ckWARN(WARN_SYNTAX))
            {
-               if (o->op_next->op_sibling &&
-                       o->op_next->op_sibling->op_type != OP_EXIT &&
-                       o->op_next->op_sibling->op_type != OP_WARN &&
-                       o->op_next->op_sibling->op_type != OP_DIE) {
-                   const line_t oldline = CopLINE(PL_curcop);
-
-                   CopLINE_set(PL_curcop, CopLINE((COP*)o->op_next));
-                   Perl_warner(aTHX_ packWARN(WARN_EXEC),
-                               "Statement unlikely to be reached");
-                   Perl_warner(aTHX_ packWARN(WARN_EXEC),
-                               "\t(Maybe you meant system() when you said exec()?)\n");
-                   CopLINE_set(PL_curcop, oldline);
+               if (o->op_next->op_sibling) {
+                   const OPCODE type = o->op_next->op_sibling->op_type;
+                   if (type != OP_EXIT && type != OP_WARN && type != OP_DIE) {
+                       const line_t oldline = CopLINE(PL_curcop);
+                       CopLINE_set(PL_curcop, CopLINE((COP*)o->op_next));
+                       Perl_warner(aTHX_ packWARN(WARN_EXEC),
+                                   "Statement unlikely to be reached");
+                       Perl_warner(aTHX_ packWARN(WARN_EXEC),
+                                   "\t(Maybe you meant system() when you said exec()?)\n");
+                       CopLINE_set(PL_curcop, oldline);
+                   }
                }
            }
            break;
@@ -7069,8 +8032,6 @@ Perl_peep(pTHX_ register OP *o)
            const char *key = NULL;
            STRLEN keylen;
 
-           o->op_opt = 1;
-
            if (((BINOP*)o)->op_last->op_type != OP_CONST)
                break;
 
@@ -7079,7 +8040,7 @@ Perl_peep(pTHX_ register OP *o)
            if ((!SvFAKE(sv = *svp) || !SvREADONLY(sv)) && !IS_PADCONST(sv)) {
                key = SvPV_const(sv, keylen);
                lexname = newSVpvn_share(key,
-                                        SvUTF8(sv) ? -(I32)keylen : keylen,
+                                        SvUTF8(sv) ? -(I32)keylen : (I32)keylen,
                                         0);
                SvREFCNT_dec(sv);
                *svp = lexname;
@@ -7092,14 +8053,14 @@ Perl_peep(pTHX_ register OP *o)
            if (rop->op_type != OP_RV2HV || rop->op_first->op_type != OP_PADSV)
                break;
            lexname = *av_fetch(PL_comppad_name, rop->op_first->op_targ, TRUE);
-           if (!(SvFLAGS(lexname) & SVpad_TYPED))
+           if (!SvPAD_TYPED(lexname))
                break;
            fields = (GV**)hv_fetchs(SvSTASH(lexname), "FIELDS", FALSE);
            if (!fields || !GvHV(*fields))
                break;
            key = SvPV_const(*svp, keylen);
            if (!hv_fetch(GvHV(*fields), key,
-                       SvUTF8(*svp) ? -(I32)keylen : keylen, FALSE))
+                       SvUTF8(*svp) ? -(I32)keylen : (I32)keylen, FALSE))
            {
                Perl_croak(aTHX_ "No such class field \"%s\" " 
                           "in variable %s of type %s", 
@@ -7141,7 +8102,7 @@ Perl_peep(pTHX_ register OP *o)
            }
                    
            lexname = *av_fetch(PL_comppad_name, rop->op_targ, TRUE);
-           if (!(SvFLAGS(lexname) & SVpad_TYPED))
+           if (!SvPAD_TYPED(lexname))
                break;
            fields = (GV**)hv_fetchs(SvSTASH(lexname), "FIELDS", FALSE);
            if (!fields || !GvHV(*fields))
@@ -7156,7 +8117,7 @@ Perl_peep(pTHX_ register OP *o)
                svp = cSVOPx_svp(key_op);
                key = SvPV_const(*svp, keylen);
                if (!hv_fetch(GvHV(*fields), key, 
-                           SvUTF8(*svp) ? -(I32)keylen : keylen, FALSE))
+                           SvUTF8(*svp) ? -(I32)keylen : (I32)keylen, FALSE))
                {
                    Perl_croak(aTHX_ "No such class field \"%s\" "
                               "in variable %s of type %s",
@@ -7197,8 +8158,6 @@ Perl_peep(pTHX_ register OP *o)
 
            /* make @a = sort @a act in-place */
 
-           o->op_opt = 1;
-
            oright = cUNOPx(oright)->op_sibling;
            if (!oright)
                break;
@@ -7289,7 +8248,6 @@ Perl_peep(pTHX_ register OP *o)
            OP *ourmark, *theirmark, *ourlast, *iter, *expushmark, *rv2av;
            OP *gvop = NULL;
            LISTOP *enter, *exlist;
-           o->op_opt = 1;
 
            enter = (LISTOP *) o->op_next;
            if (!enter)
@@ -7380,13 +8338,6 @@ Perl_peep(pTHX_ register OP *o)
            UNOP *refgen, *rv2cv;
            LISTOP *exlist;
 
-           /* I do not understand this, but if o->op_opt isn't set to 1,
-              various tests in ext/B/t/bytecode.t fail with no readily
-              apparent cause.  */
-
-           o->op_opt = 1;
-
-
            if ((o->op_flags && OPf_WANT) != OPf_WANT_VOID)
                break;
 
@@ -7427,8 +8378,11 @@ Perl_peep(pTHX_ register OP *o)
        }
 
        
-       default:
-           o->op_opt = 1;
+       case OP_QR:
+       case OP_MATCH:
+           if (!(cPMOP->op_pmflags & PMf_ONCE)) {
+               assert (!cPMOP->op_pmstashstartu.op_pmreplstart);
+           }
            break;
        }
        oldop = o;
@@ -7436,7 +8390,7 @@ Perl_peep(pTHX_ register OP *o)
     LEAVE;
 }
 
-char*
+const char*
 Perl_custom_op_name(pTHX_ const OP* o)
 {
     dVAR;
@@ -7456,7 +8410,7 @@ Perl_custom_op_name(pTHX_ const OP* o)
     return SvPV_nolen(HeVAL(he));
 }
 
-char*
+const char*
 Perl_custom_op_desc(pTHX_ const OP* o)
 {
     dVAR;
@@ -7485,6 +8439,7 @@ const_sv_xsub(pTHX_ CV* cv)
     dVAR;
     dXSARGS;
     if (items != 0) {
+       NOOP;
 #if 0
         Perl_croak(aTHX_ "usage: %s::%s()",
                    HvNAME_get(GvSTASH(CvGV(cv))), GvNAME(CvGV(cv)));