This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Making t/14gzopen.t a bit more robust.
[perl5.git] / op.c
diff --git a/op.c b/op.c
index 610c0e5..6500d49 100644 (file)
--- a/op.c
+++ b/op.c
@@ -1,6 +1,7 @@
 /*    op.c
  *
- *    Copyright (c) 1991-2002, Larry Wall
+ *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ *    2000, 2001, 2002, 2003, 2004, 2005, 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.
  * either way, as the saying is, if you follow me."  --the Gaffer
  */
 
+/* This file contains the functions that create, manipulate and optimize
+ * the OP structures that hold a compiled perl program.
+ *
+ * A Perl program is compiled into a tree of OPs. Each op contains
+ * structural pointers (eg to its siblings and the next op in the
+ * execution sequence), a pointer to the function that would execute the
+ * op, plus any data specific to that op. For example, an OP_CONST op
+ * points to the pp_const() function and to an SV containing the constant
+ * value. When pp_const() is executed, its job is to push that SV onto the
+ * stack.
+ *
+ * OPs are mainly created by the newFOO() functions, which are mainly
+ * called from the parser (in perly.y) as the code is parsed. For example
+ * the Perl code $a + $b * $c would cause the equivalent of the following
+ * to be called (oversimplifying a bit):
+ *
+ *  newBINOP(OP_ADD, flags,
+ *     newSVREF($a),
+ *     newBINOP(OP_MULTIPLY, flags, newSVREF($b), newSVREF($c))
+ *  )
+ *
+ * Note that during the build of miniperl, a temporary copy of this file
+ * is made, called opmini.c.
+ */
+
+/*
+Perl's compiler is essentially a 3-pass compiler with interleaved phases:
+
+    A bottom-up pass
+    A top-down pass
+    An execution-order pass
+
+The bottom-up pass is represented by all the "newOP" routines and
+the ck_ routines.  The bottom-upness is actually driven by yacc.
+So at the point that a ck_ routine fires, we have no idea what the
+context is, either upward in the syntax tree, or either forward or
+backward in the execution order.  (The bottom-up parser builds that
+part of the execution order it knows about, but if you follow the "next"
+links around, you'll find it's actually a closed loop through the
+top level node.
+
+Whenever the bottom-up parser gets to a node that supplies context to
+its components, it invokes that portion of the top-down pass that applies
+to that part of the subtree (and marks the top node as processed, so
+if a node further up supplies context, it doesn't have to take the
+plunge again).  As a particular subcase of this, as the new node is
+built, it takes all the closed execution loops of its subcomponents
+and links them into a new closed loop for the higher level node.  But
+it's still not the real execution order.
+
+The actual execution order is not known till we get a grammar reduction
+to a top-level unit like a subroutine or file that will be called by
+"name" rather than via a "next" pointer.  At that point, we can call
+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.
+*/
 
 #include "EXTERN.h"
 #define PERL_IN_OP_C
 #define PERL_SLAB_SIZE 2048
 #endif
 
-#define NewOp(m,var,c,type) \
-       STMT_START { var = (type *) Slab_Alloc(m,c*sizeof(type)); } STMT_END
-
-#define FreeOp(p) Slab_Free(p)
-
-STATIC void *
-S_Slab_Alloc(pTHX_ int m, size_t sz)
+void *
+Perl_Slab_Alloc(pTHX_ int m, size_t sz)
 {
     /*
      * To make incrementing use count easy PL_OpSlab is an I32 *
@@ -73,18 +125,18 @@ S_Slab_Alloc(pTHX_ int m, size_t sz)
     return (void *)(PL_OpPtr + 1);
 }
 
-STATIC void
-S_Slab_Free(pTHX_ void *op)
+void
+Perl_Slab_Free(pTHX_ void *op)
 {
-    I32 **ptr = (I32 **) op;
-    I32 *slab = ptr[-1];
+    I32 ** 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 (--(*slab) == 0) {
-     #ifdef NETWARE
-      #define PerlMemShared PerlMem
-     #endif
+#  ifdef NETWARE
+#    define PerlMemShared PerlMem
+#  endif
        
     PerlMemShared_free(slab);
        if (slab == PL_OpSlab) {
@@ -92,10 +144,6 @@ S_Slab_Free(pTHX_ void *op)
        }
     }
 }
-
-#else
-#define NewOp(m, var, c, type) Newz(m, var, c, type)
-#define FreeOp(p) Safefree(p)
 #endif
 /*
  * In the following definition, the ", Nullop" is just to make the compiler
@@ -110,13 +158,12 @@ S_Slab_Free(pTHX_ void *op)
 
 #define RETURN_UNLIMITED_NUMBER (PERL_INT_MAX / 2)
 
-STATIC char*
+STATIC const char*
 S_gv_ename(pTHX_ GV *gv)
 {
-    STRLEN n_a;
-    SV* tmpsv = sv_newmortal();
+    SV* const tmpsv = sv_newmortal();
     gv_efullname3(tmpsv, gv, Nullch);
-    return SvPV(tmpsv,n_a);
+    return SvPV_nolen_const(tmpsv);
 }
 
 STATIC OP *
@@ -128,28 +175,28 @@ S_no_fh_allowed(pTHX_ OP *o)
 }
 
 STATIC OP *
-S_too_few_arguments(pTHX_ OP *o, char *name)
+S_too_few_arguments(pTHX_ OP *o, const char *name)
 {
     yyerror(Perl_form(aTHX_ "Not enough arguments for %s", name));
     return o;
 }
 
 STATIC OP *
-S_too_many_arguments(pTHX_ OP *o, char *name)
+S_too_many_arguments(pTHX_ OP *o, const char *name)
 {
     yyerror(Perl_form(aTHX_ "Too many arguments for %s", name));
     return o;
 }
 
 STATIC void
-S_bad_type(pTHX_ I32 n, char *t, char *name, OP *kid)
+S_bad_type(pTHX_ I32 n, const char *t, const char *name, const OP *kid)
 {
     yyerror(Perl_form(aTHX_ "Type of arg %d to %s must be %s (not %s)",
                 (int)n, name, t, OP_DESC(kid)));
 }
 
 STATIC void
-S_no_bareword_allowed(pTHX_ OP *o)
+S_no_bareword_allowed(pTHX_ const OP *o)
 {
     qerror(Perl_mess(aTHX_
                     "Bareword \"%"SVf"\" not allowed while \"strict subs\" in use",
@@ -163,11 +210,11 @@ Perl_allocmy(pTHX_ char *name)
 {
     PADOFFSET off;
 
-    /* complain about "my $_" etc etc */
+    /* complain about "my $<special_var>" etc etc */
     if (!(PL_in_my == KEY_our ||
          isALPHA(name[1]) ||
          (USE_UTF8_IN_NAMES && UTF8_IS_START(name[1])) ||
-         (name[1] == '_' && (int)strlen(name) > 2)))
+         (name[1] == '_' && (*name == '$' || (int)strlen(name) > 2))))
     {
        if (!isPRINT(name[1]) || strchr("\t\n\r\f", name[1])) {
            /* 1999-02-27 mjd@plover.com */
@@ -193,7 +240,7 @@ Perl_allocmy(pTHX_ char *name)
 
     /* check for duplicate declaration */
     pad_check_dup(name,
-               PL_in_my == KEY_our,
+               (bool)(PL_in_my == KEY_our),
                (PL_curstash ? PL_curstash : PL_defstash)
     );
 
@@ -208,7 +255,8 @@ Perl_allocmy(pTHX_ char *name)
     off = pad_add_name(name,
                    PL_in_my_stash,
                    (PL_in_my == KEY_our 
-                       ? (PL_curstash ? PL_curstash : PL_defstash)
+                       /* $_ is always in main::, even with our */
+                       ? (PL_curstash && !strEQ(name,"$_") ? PL_curstash : PL_defstash)
                        : Nullhv
                    ),
                    0 /*  not fake */
@@ -221,10 +269,11 @@ Perl_allocmy(pTHX_ char *name)
 void
 Perl_op_free(pTHX_ OP *o)
 {
-    register OP *kid, *nextkid;
+    dVAR;
     OPCODE type;
+    PADOFFSET refcnt;
 
-    if (!o || o->op_seq == (U16)-1)
+    if (!o || o->op_static)
        return;
 
     if (o->op_private & OPpREFCOUNTED) {
@@ -236,11 +285,10 @@ Perl_op_free(pTHX_ OP *o)
        case OP_SCOPE:
        case OP_LEAVEWRITE:
            OP_REFCNT_LOCK;
-           if (OpREFCNT_dec(o)) {
-               OP_REFCNT_UNLOCK;
-               return;
-           }
+           refcnt = OpREFCNT_dec(o);
            OP_REFCNT_UNLOCK;
+           if (refcnt)
+               return;
            break;
        default:
            break;
@@ -248,6 +296,7 @@ Perl_op_free(pTHX_ OP *o)
     }
 
     if (o->op_flags & OPf_KIDS) {
+        register OP *kid, *nextkid;
        for (kid = cUNOPo->op_first; kid; kid = nextkid) {
            nextkid = kid->op_sibling; /* Get before next freeing kid */
            op_free(kid);
@@ -264,12 +313,17 @@ Perl_op_free(pTHX_ OP *o)
 
     op_clear(o);
     FreeOp(o);
+#ifdef DEBUG_LEAKING_SCALARS
+    if (PL_op == o)
+       PL_op = Nullop;
+#endif
 }
 
 void
 Perl_op_clear(pTHX_ OP *o)
 {
 
+    dVAR;
     switch (o->op_type) {
     case OP_NULL:      /* Was holding old type, if any. */
     case OP_ENTEREVAL: /* Was holding hints. */
@@ -283,22 +337,37 @@ Perl_op_clear(pTHX_ OP *o)
     case OP_GVSV:
     case OP_GV:
     case OP_AELEMFAST:
+       if (! (o->op_type == OP_AELEMFAST && o->op_flags & OPf_SPECIAL)) {
+           /* not an OP_PADAV replacement */
 #ifdef USE_ITHREADS
-       if (cPADOPo->op_padix > 0) {
-           /* No GvIN_PAD_off(cGVOPo_gv) here, because other references
-            * may still exist on the pad */
-           pad_swipe(cPADOPo->op_padix, TRUE);
-           cPADOPo->op_padix = 0;
-       }
+           if (cPADOPo->op_padix > 0) {
+               /* No GvIN_PAD_off(cGVOPo_gv) here, because other references
+                * may still exist on the pad */
+               pad_swipe(cPADOPo->op_padix, TRUE);
+               cPADOPo->op_padix = 0;
+           }
 #else
-       SvREFCNT_dec(cSVOPo->op_sv);
-       cSVOPo->op_sv = Nullsv;
+           SvREFCNT_dec(cSVOPo->op_sv);
+           cSVOPo->op_sv = Nullsv;
 #endif
+       }
        break;
     case OP_METHOD_NAMED:
     case OP_CONST:
        SvREFCNT_dec(cSVOPo->op_sv);
        cSVOPo->op_sv = Nullsv;
+#ifdef USE_ITHREADS
+       /** Bug #15654
+         Even if op_clear does a pad_free for the target of the op,
+         pad_free doesn't actually remove the sv that exists in the pad;
+         instead it lives on. This results in that it could be reused as 
+         a target later on when the pad was reallocated.
+       **/
+        if(o->op_targ) {
+          pad_swipe(o->op_targ,1);
+          o->op_targ = 0;
+        }
+#endif
        break;
     case OP_GOTO:
     case OP_NEXT:
@@ -337,18 +406,21 @@ clear_pmop:
        {
            HV *pmstash = PmopSTASH(cPMOPo);
            if (pmstash && SvREFCNT(pmstash)) {
-               PMOP *pmop = HvPMROOT(pmstash);
-               PMOP *lastpmop = NULL;
-               while (pmop) {
-                   if (cPMOPo == pmop) {
-                       if (lastpmop)
-                           lastpmop->op_pmnext = pmop->op_pmnext;
-                       else
-                           HvPMROOT(pmstash) = pmop->op_pmnext;
-                       break;
+               MAGIC *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;
                    }
-                   lastpmop = pmop;
-                   pmop = pmop->op_pmnext;
                }
            }
            PmopSTASH_free(cPMOPo);
@@ -403,6 +475,7 @@ S_cop_free(pTHX_ COP* cop)
 void
 Perl_op_null(pTHX_ OP *o)
 {
+    dVAR;
     if (o->op_type == OP_NULL)
        return;
     op_clear(o);
@@ -411,6 +484,20 @@ Perl_op_null(pTHX_ OP *o)
     o->op_ppaddr = PL_ppaddr[OP_NULL];
 }
 
+void
+Perl_op_refcnt_lock(pTHX)
+{
+    dVAR;
+    OP_REFCNT_LOCK;
+}
+
+void
+Perl_op_refcnt_unlock(pTHX)
+{
+    dVAR;
+    OP_REFCNT_UNLOCK;
+}
+
 /* Contextualizers */
 
 #define LINKLIST(o) ((o)->op_next ? (o)->op_next : linklist((OP*)o))
@@ -418,13 +505,13 @@ Perl_op_null(pTHX_ OP *o)
 OP *
 Perl_linklist(pTHX_ OP *o)
 {
-    register OP *kid;
 
     if (o->op_next)
        return o->op_next;
 
     /* establish postfix order */
     if (cUNOPo->op_first) {
+        register OP *kid;
        o->op_next = LINKLIST(cUNOPo->op_first);
        for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) {
            if (kid->op_sibling)
@@ -442,8 +529,8 @@ Perl_linklist(pTHX_ OP *o)
 OP *
 Perl_scalarkids(pTHX_ OP *o)
 {
-    OP *kid;
     if (o && o->op_flags & OPf_KIDS) {
+        OP *kid;
        for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
            scalar(kid);
     }
@@ -455,7 +542,7 @@ S_scalarboolean(pTHX_ OP *o)
 {
     if (o->op_type == OP_SASSIGN && cBINOPo->op_first->op_type == OP_CONST) {
        if (ckWARN(WARN_SYNTAX)) {
-           line_t oldline = CopLINE(PL_curcop);
+           const line_t oldline = CopLINE(PL_curcop);
 
            if (PL_copline != NOLINE)
                CopLINE_set(PL_curcop, PL_copline);
@@ -469,6 +556,7 @@ S_scalarboolean(pTHX_ OP *o)
 OP *
 Perl_scalar(pTHX_ OP *o)
 {
+    dVAR;
     OP *kid;
 
     /* assumes no premature commitment */
@@ -539,8 +627,9 @@ Perl_scalar(pTHX_ OP *o)
 OP *
 Perl_scalarvoid(pTHX_ OP *o)
 {
+    dVAR;
     OP *kid;
-    char* useless = 0;
+    const char* useless = 0;
     SV* sv;
     U8 want;
 
@@ -654,6 +743,15 @@ Perl_scalarvoid(pTHX_ OP *o)
            useless = OP_DESC(o);
        break;
 
+    case OP_NOT:
+       kid = cUNOPo->op_first;
+       if (kid->op_type != OP_MATCH && kid->op_type != OP_SUBST &&
+           kid->op_type != OP_TRANS) {
+               goto func_ops;
+       }
+       useless = "negative pattern binding (!~)";
+       break;
+
     case OP_RV2GV:
     case OP_RV2SV:
     case OP_RV2AV:
@@ -670,10 +768,14 @@ Perl_scalarvoid(pTHX_ OP *o)
        else {
            if (ckWARN(WARN_VOID)) {
                useless = "a constant";
+               /* don't warn on optimised away booleans, eg 
+                * use constant Foo, 5; Foo || print; */
+               if (cSVOPo->op_private & OPpCONST_SHORTCIRCUIT)
+                   useless = 0;
                /* the constants 0 and 1 are permitted as they are
                   conventionally used as dummies in constructs like
                        1 while some_condition_with_side_effects;  */
-               if (SvNIOK(sv) && (SvNV(sv) == 0.0 || SvNV(sv) == 1.0))
+               else if (SvNIOK(sv) && (SvNV(sv) == 0.0 || SvNV(sv) == 1.0))
                    useless = 0;
                else if (SvPOK(sv)) {
                   /* perl4's way of mixing documentation and code
@@ -682,9 +784,9 @@ Perl_scalarvoid(pTHX_ OP *o)
                      built upon these three nroff macros being used in
                      void context. The pink camel has the details in
                      the script wrapman near page 319. */
-                   if (strnEQ(SvPVX(sv), "di", 2) ||
-                       strnEQ(SvPVX(sv), "ds", 2) ||
-                       strnEQ(SvPVX(sv), "ig", 2))
+                   if (strnEQ(SvPVX_const(sv), "di", 2) ||
+                       strnEQ(SvPVX_const(sv), "ds", 2) ||
+                       strnEQ(SvPVX_const(sv), "ig", 2))
                            useless = 0;
                }
            }
@@ -754,8 +856,8 @@ Perl_scalarvoid(pTHX_ OP *o)
 OP *
 Perl_listkids(pTHX_ OP *o)
 {
-    OP *kid;
     if (o && o->op_flags & OPf_KIDS) {
+        OP *kid;
        for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
            list(kid);
     }
@@ -765,6 +867,7 @@ Perl_listkids(pTHX_ OP *o)
 OP *
 Perl_list(pTHX_ OP *o)
 {
+    dVAR;
     OP *kid;
 
     /* assumes no premature commitment */
@@ -840,14 +943,13 @@ Perl_list(pTHX_ OP *o)
 OP *
 Perl_scalarseq(pTHX_ OP *o)
 {
-    OP *kid;
-
     if (o) {
        if (o->op_type == OP_LINESEQ ||
             o->op_type == OP_SCOPE ||
             o->op_type == OP_LEAVE ||
             o->op_type == OP_LEAVETRY)
        {
+            OP *kid;
            for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) {
                if (kid->op_sibling) {
                    scalarvoid(kid);
@@ -867,18 +969,32 @@ Perl_scalarseq(pTHX_ OP *o)
 STATIC OP *
 S_modkids(pTHX_ OP *o, I32 type)
 {
-    OP *kid;
     if (o && o->op_flags & OPf_KIDS) {
+        OP *kid;
        for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
            mod(kid, type);
     }
     return o;
 }
 
+/* Propagate lvalue ("modifiable") context to an op and it's children.
+ * 'type' represents the context type, roughly based on the type of op that
+ * would do the modifying, although local() is represented by OP_NULL.
+ * It's responsible for detecting things that can't be modified,  flag
+ * things that need to behave specially in an lvalue context (e.g., "$$x = 5"
+ * might have to vivify a reference in $x), and so on.
+ *
+ * For example, "$a+1 = 2" would cause mod() to be called with o being
+ * OP_ADD and type being OP_SASSIGN, and would output an error.
+ */
+
 OP *
 Perl_mod(pTHX_ OP *o, I32 type)
 {
+    dVAR;
     OP *kid;
+    /* -1 = error on localize, 0 = ignore localize, 1 = ok to localize */
+    int localize = -1;
 
     if (!o || PL_error_count)
        return o;
@@ -891,6 +1007,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
 
     switch (o->op_type) {
     case OP_UNDEF:
+       localize = 0;
        PL_modcount++;
        return o;
     case OP_CONST:
@@ -1047,14 +1164,13 @@ Perl_mod(pTHX_ OP *o, I32 type)
        break;
 
     case OP_COND_EXPR:
+       localize = 1;
        for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
            mod(kid, type);
        break;
 
     case OP_RV2AV:
     case OP_RV2HV:
-       if (!type && cUNOPo->op_first->op_type != OP_GV)
-           Perl_croak(aTHX_ "Can't localize through a reference");
        if (type == OP_REFGEN && o->op_flags & OPf_PARENS) {
            PL_modcount = RETURN_UNLIMITED_NUMBER;
            return o;           /* Treat \(@foo) like ordinary list. */
@@ -1069,6 +1185,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
     case OP_HSLICE:
        if (type == OP_LEAVESUBLV)
            o->op_private |= OPpMAYBE_LVSUB;
+       localize = 1;
        /* FALL THROUGH */
     case OP_AASSIGN:
     case OP_NEXTSTATE:
@@ -1076,9 +1193,8 @@ Perl_mod(pTHX_ OP *o, I32 type)
        PL_modcount = RETURN_UNLIMITED_NUMBER;
        break;
     case OP_RV2SV:
-       if (!type && cUNOPo->op_first->op_type != OP_GV)
-           Perl_croak(aTHX_ "Can't localize through a reference");
        ref(cUNOPo->op_first, o->op_type);
+       localize = 1;
        /* FALL THROUGH */
     case OP_GV:
     case OP_AV2ARYLEN:
@@ -1087,7 +1203,11 @@ Perl_mod(pTHX_ OP *o, I32 type)
     case OP_ANDASSIGN:
     case OP_ORASSIGN:
     case OP_DORASSIGN:
+       PL_modcount++;
+       break;
+
     case OP_AELEMFAST:
+       localize = -1;
        PL_modcount++;
        break;
 
@@ -1103,17 +1223,13 @@ Perl_mod(pTHX_ OP *o, I32 type)
        /* FALL THROUGH */
     case OP_PADSV:
        PL_modcount++;
-       if (!type)
-       {   /* XXX DAPM 2002.08.25 tmp assert test */
-           /* XXX */ assert(av_fetch(PL_comppad_name, (o->op_targ), FALSE));
-           /* XXX */ assert(*av_fetch(PL_comppad_name, (o->op_targ), FALSE));
-
+       if (!type) /* local() */
            Perl_croak(aTHX_ "Can't localize lexical variable %s",
                 PAD_COMPNAME_PV(o->op_targ));
-       }
        break;
 
     case OP_PUSHMARK:
+       localize = 0;
        break;
 
     case OP_KEYS:
@@ -1144,6 +1260,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
            o->op_private |= OPpLVAL_DEFER;
        if (type == OP_LEAVESUBLV)
            o->op_private |= OPpMAYBE_LVSUB;
+       localize = 1;
        PL_modcount++;
        break;
 
@@ -1151,11 +1268,13 @@ Perl_mod(pTHX_ OP *o, I32 type)
     case OP_LEAVE:
     case OP_ENTER:
     case OP_LINESEQ:
+       localize = 0;
        if (o->op_flags & OPf_KIDS)
            mod(cLISTOPo->op_last, type);
        break;
 
     case OP_NULL:
+       localize = 0;
        if (o->op_flags & OPf_SPECIAL)          /* do BLOCK */
            goto nomod;
        else if (!(o->op_flags & OPf_KIDS))
@@ -1166,6 +1285,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
        }
        /* FALL THROUGH */
     case OP_LIST:
+       localize = 0;
        for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
            mod(kid, type);
        break;
@@ -1188,10 +1308,21 @@ Perl_mod(pTHX_ OP *o, I32 type)
 
     if (type == OP_AASSIGN || type == OP_SASSIGN)
        o->op_flags |= OPf_SPECIAL|OPf_REF;
-    else if (!type) {
-       o->op_private |= OPpLVAL_INTRO;
-       o->op_flags &= ~OPf_SPECIAL;
-       PL_hints |= HINT_BLOCK_SCOPE;
+    else if (!type) { /* local() */
+       switch (localize) {
+       case 1:
+           o->op_private |= OPpLVAL_INTRO;
+           o->op_flags &= ~OPf_SPECIAL;
+           PL_hints |= HINT_BLOCK_SCOPE;
+           break;
+       case 0:
+           break;
+       case -1:
+           if (ckWARN(WARN_SYNTAX)) {
+               Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
+                   "Useless localization of %s", OP_DESC(o));
+           }
+       }
     }
     else if (type != OP_GREPSTART && type != OP_ENTERSUB
              && type != OP_LEAVESUBLV)
@@ -1200,7 +1331,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
 }
 
 STATIC bool
-S_scalar_mod_type(pTHX_ OP *o, I32 type)
+S_scalar_mod_type(pTHX_ const OP *o, I32 type)
 {
     switch (type) {
     case OP_SASSIGN:
@@ -1247,12 +1378,12 @@ S_scalar_mod_type(pTHX_ OP *o, I32 type)
 }
 
 STATIC bool
-S_is_handle_constructor(pTHX_ OP *o, I32 argnum)
+S_is_handle_constructor(pTHX_ const OP *o, I32 numargs)
 {
     switch (o->op_type) {
     case OP_PIPE_OP:
     case OP_SOCKPAIR:
-       if (argnum == 2)
+       if (numargs == 2)
            return TRUE;
        /* FALL THROUGH */
     case OP_SYSOPEN:
@@ -1261,7 +1392,7 @@ S_is_handle_constructor(pTHX_ OP *o, I32 argnum)
     case OP_SOCKET:
     case OP_OPEN_DIR:
     case OP_ACCEPT:
-       if (argnum == 1)
+       if (numargs == 1)
            return TRUE;
        /* FALL THROUGH */
     default:
@@ -1272,8 +1403,8 @@ S_is_handle_constructor(pTHX_ OP *o, I32 argnum)
 OP *
 Perl_refkids(pTHX_ OP *o, I32 type)
 {
-    OP *kid;
     if (o && o->op_flags & OPf_KIDS) {
+        OP *kid;
        for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
            ref(kid, type);
     }
@@ -1283,6 +1414,7 @@ Perl_refkids(pTHX_ OP *o, I32 type)
 OP *
 Perl_ref(pTHX_ OP *o, I32 type)
 {
+    dVAR;
     OP *kid;
 
     if (!o || PL_error_count)
@@ -1395,23 +1527,20 @@ S_dup_attrlist(pTHX_ OP *o)
 STATIC void
 S_apply_attrs(pTHX_ HV *stash, SV *target, OP *attrs, bool for_my)
 {
+    dVAR;
     SV *stashsv;
 
     /* fake up C<use attributes $pkg,$rv,@attrs> */
     ENTER;             /* need to protect against side-effects of 'use' */
     SAVEINT(PL_expect);
-    if (stash)
-       stashsv = newSVpv(HvNAME(stash), 0);
-    else
-       stashsv = &PL_sv_no;
+    stashsv = stash ? newSVhek(HvNAME_HEK(stash)) : &PL_sv_no;
 
 #define ATTRSMODULE "attributes"
 #define ATTRSMODULE_PM "attributes.pm"
 
     if (for_my) {
-       SV **svp;
        /* Don't force the C<use> if we don't need it. */
-       svp = hv_fetch(GvHVn(PL_incgv), ATTRSMODULE_PM,
+       SV **svp = hv_fetch(GvHVn(PL_incgv), ATTRSMODULE_PM,
                       sizeof(ATTRSMODULE_PM)-1, 0);
        if (svp && *svp != &PL_sv_undef)
            ;           /* already in %INC */
@@ -1454,10 +1583,8 @@ S_apply_attrs_my(pTHX_ HV *stash, OP *target, OP *attrs, OP **imopsp)
     pack = newSVOP(OP_CONST, 0, newSVpvn(ATTRSMODULE, sizeof(ATTRSMODULE)-1));
 
     /* Build up the real arg-list. */
-    if (stash)
-       stashsv = newSVpv(HvNAME(stash), 0);
-    else
-       stashsv = &PL_sv_no;
+    stashsv = stash ? newSVhek(HvNAME_HEK(stash)) : &PL_sv_no;
+
     arg = newOP(OP_PADSV, 0);
     arg->op_targ = target->op_targ;
     arg = prepend_elem(OP_LIST,
@@ -1468,10 +1595,7 @@ S_apply_attrs_my(pTHX_ HV *stash, OP *target, OP *attrs, OP **imopsp)
                                    dup_attrlist(attrs)));
 
     /* Fake up a method call to import */
-    meth = newSVpvn("import", 6);
-    (void)SvUPGRADE(meth, SVt_PVIV);
-    (void)SvIOK_on(meth);
-    PERL_HASH(SvUVX(meth), SvPVX(meth), SvCUR(meth));
+    meth = newSVpvn_share("import", 6, 0);
     imop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL|OPf_WANT_VOID,
                   append_elem(OP_LIST,
                               prepend_elem(OP_LIST, pack, list(arg)),
@@ -1500,8 +1624,8 @@ to respect attribute syntax properly would be welcome.
 */
 
 void
-Perl_apply_attrs_string(pTHX_ char *stashpv, CV *cv,
-                        char *attrstr, STRLEN len)
+Perl_apply_attrs_string(pTHX_ const char *stashpv, CV *cv,
+                        const char *attrstr, STRLEN len)
 {
     OP *attrs = Nullop;
 
@@ -1512,7 +1636,7 @@ Perl_apply_attrs_string(pTHX_ char *stashpv, CV *cv,
     while (len) {
         for (; isSPACE(*attrstr) && len; --len, ++attrstr) ;
         if (len) {
-            char *sstr = attrstr;
+            const char * const sstr = attrstr;
             for (; !isSPACE(*attrstr) && len; --len, ++attrstr) ;
             attrs = append_elem(OP_LIST, attrs,
                                 newSVOP(OP_CONST, 0,
@@ -1533,7 +1657,6 @@ Perl_apply_attrs_string(pTHX_ char *stashpv, CV *cv,
 STATIC OP *
 S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp)
 {
-    OP *kid;
     I32 type;
 
     if (!o || PL_error_count)
@@ -1541,6 +1664,7 @@ S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp)
 
     type = o->op_type;
     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) {
@@ -1641,13 +1765,15 @@ OP *
 Perl_bind_match(pTHX_ I32 type, OP *left, OP *right)
 {
     OP *o;
+    bool ismatchop = 0;
 
-    if (ckWARN(WARN_MISC) &&
-      (left->op_type == OP_RV2AV ||
+    if ( (left->op_type == OP_RV2AV ||
        left->op_type == OP_RV2HV ||
        left->op_type == OP_PADAV ||
-       left->op_type == OP_PADHV)) {
-      char *desc = PL_op_desc[(right->op_type == OP_SUBST ||
+       left->op_type == OP_PADHV)
+       && ckWARN(WARN_MISC))
+    {
+      const char *desc = PL_op_desc[(right->op_type == OP_SUBST ||
                             right->op_type == OP_TRANS)
                            ? right->op_type : OP_MATCH];
       const char *sample = ((left->op_type == OP_RV2AV ||
@@ -1665,10 +1791,14 @@ Perl_bind_match(pTHX_ I32 type, OP *left, OP *right)
        no_bareword_allowed(right);
     }
 
-    if (!(right->op_flags & OPf_STACKED) &&
-       (right->op_type == OP_MATCH ||
-       right->op_type == OP_SUBST ||
-       right->op_type == OP_TRANS)) {
+    ismatchop = right->op_type == OP_MATCH ||
+               right->op_type == OP_SUBST ||
+               right->op_type == 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) {
        right->op_flags |= OPf_STACKED;
        if (right->op_type != OP_MATCH &&
             ! (right->op_type == OP_TRANS &&
@@ -1684,7 +1814,7 @@ Perl_bind_match(pTHX_ I32 type, OP *left, OP *right)
     }
     else
        return bind_match(type, left,
-               pmruntime(newPMOP(OP_MATCH, 0), right, Nullop));
+               pmruntime(newPMOP(OP_MATCH, 0), right, 0));
 }
 
 OP *
@@ -1699,44 +1829,38 @@ Perl_invert(pTHX_ OP *o)
 OP *
 Perl_scope(pTHX_ OP *o)
 {
+    dVAR;
     if (o) {
        if (o->op_flags & OPf_PARENS || PERLDB_NOOPT || PL_tainting) {
            o = prepend_elem(OP_LINESEQ, newOP(OP_ENTER, 0), o);
            o->op_type = OP_LEAVE;
            o->op_ppaddr = PL_ppaddr[OP_LEAVE];
        }
-       else {
-           if (o->op_type == OP_LINESEQ) {
-               OP *kid;
-               o->op_type = OP_SCOPE;
-               o->op_ppaddr = PL_ppaddr[OP_SCOPE];
-               kid = ((LISTOP*)o)->op_first;
-               if (kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE)
-                   op_null(kid);
-           }
-           else
-               o = newLISTOP(OP_SCOPE, 0, o, Nullop);
+       else if (o->op_type == OP_LINESEQ) {
+           OP *kid;
+           o->op_type = OP_SCOPE;
+           o->op_ppaddr = PL_ppaddr[OP_SCOPE];
+           kid = ((LISTOP*)o)->op_first;
+           if (kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE)
+               op_null(kid);
        }
+       else
+           o = newLISTOP(OP_SCOPE, 0, o, Nullop);
     }
     return o;
 }
 
+/* XXX kept for BINCOMPAT only */
 void
 Perl_save_hints(pTHX)
 {
-    SAVEI32(PL_hints);
-    SAVESPTR(GvHV(PL_hintgv));
-    GvHV(PL_hintgv) = newHVhv(GvHV(PL_hintgv));
-    SAVEFREESV(GvHV(PL_hintgv));
+    Perl_croak(aTHX_ "internal error: obsolete function save_hints() called");
 }
 
 int
 Perl_block_start(pTHX_ int full)
 {
-    int retval = PL_savestack_ix;
-    /* If there were syntax errors, don't try to start a block */
-    if (PL_yynerrs) return retval;
-
+    const int retval = PL_savestack_ix;
     pad_block_start(full);
     SAVEHINTS();
     PL_hints &= ~HINT_BLOCK_SCOPE;
@@ -1756,18 +1880,8 @@ Perl_block_start(pTHX_ int full)
 OP*
 Perl_block_end(pTHX_ I32 floor, OP *seq)
 {
-    int needblockscope = PL_hints & HINT_BLOCK_SCOPE;
-    line_t copline = PL_copline;
+    const int needblockscope = PL_hints & HINT_BLOCK_SCOPE;
     OP* retval = scalarseq(seq);
-    /* If there were syntax errors, don't try to close a block */
-    if (PL_yynerrs) return retval;
-    if (!seq) {
-       /* scalarseq() gave us an OP_STUB */
-       retval->op_flags |= OPf_PARENS;
-       /* there should be a nextstate in every block */
-       retval = newSTATEOP(0, Nullch, retval);
-       PL_copline = copline;  /* XXX newSTATEOP may reset PL_copline */
-    }
     LEAVE_SCOPE(floor);
     PL_compiling.op_private = (U8)(PL_hints & HINT_PRIVATE_MASK);
     if (needblockscope)
@@ -1779,7 +1893,15 @@ Perl_block_end(pTHX_ I32 floor, OP *seq)
 STATIC OP *
 S_newDEFSVOP(pTHX)
 {
-    return newSVREF(newGVOP(OP_GV, 0, PL_defgv));
+    const I32 offset = pad_findmy("$_");
+    if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS(offset) & SVpad_OUR) {
+       return newSVREF(newGVOP(OP_GV, 0, PL_defgv));
+    }
+    else {
+       OP *o = newOP(OP_PADSV, 0);
+       o->op_targ = offset;
+       return o;
+    }
 }
 
 void
@@ -1798,8 +1920,12 @@ Perl_newPROG(pTHX_ OP *o)
        CALL_PEEP(PL_eval_start);
     }
     else {
-       if (!o)
+       if (o->op_type == OP_STUB) {
+           PL_comppad_name = 0;
+           PL_compcv = 0;
+           FreeOp(o);
            return;
+       }
        PL_main_root = scope(sawparens(scalarvoid(o)));
        PL_curcop = &PL_compiling;
        PL_main_start = LINKLIST(PL_main_root);
@@ -1835,18 +1961,35 @@ Perl_localize(pTHX_ OP *o, I32 lex)
        ;
 #endif
     else {
-       if (ckWARN(WARN_PARENTHESIS)
-           && PL_bufptr > PL_oldbufptr && PL_bufptr[-1] == ',')
+       if ( PL_bufptr > PL_oldbufptr && PL_bufptr[-1] == ','
+           && ckWARN(WARN_PARENTHESIS))
        {
            char *s = PL_bufptr;
+           bool sigil = FALSE;
 
-           while (*s && (isALNUM(*s) || UTF8_IS_CONTINUED(*s) || strchr("@$%, ", *s)))
+           /* some heuristics to detect a potential error */
+           while (*s && (strchr(", \t\n", *s)))
                s++;
 
-           if (*s == ';' || *s == '=')
+           while (1) {
+               if (*s && strchr("@$%*", *s) && *++s
+                      && (isALNUM(*s) || UTF8_IS_CONTINUED(*s))) {
+                   s++;
+                   sigil = TRUE;
+                   while (*s && (isALNUM(*s) || UTF8_IS_CONTINUED(*s)))
+                       s++;
+                   while (*s && (strchr(", \t\n", *s)))
+                       s++;
+               }
+               else
+                   break;
+           }
+           if (sigil && (*s == ';' || *s == '=')) {
                Perl_warner(aTHX_ packWARN(WARN_PARENTHESIS),
-                           "Parentheses missing around \"%s\" list",
-                           lex ? (PL_in_my == KEY_our ? "our" : "my") : "local");
+                               "Parentheses missing around \"%s\" list",
+                               lex ? (PL_in_my == KEY_our ? "our" : "my")
+                               : "local");
+           }
        }
     }
     if (lex)
@@ -1872,6 +2015,7 @@ Perl_jmaybe(pTHX_ OP *o)
 OP *
 Perl_fold_constants(pTHX_ register OP *o)
 {
+    dVAR;
     register OP *curop;
     I32 type = o->op_type;
     SV *sv;
@@ -1942,19 +2086,7 @@ Perl_fold_constants(pTHX_ register OP *o)
     op_free(o);
     if (type == OP_RV2GV)
        return newGVOP(OP_GV, 0, (GV*)sv);
-    else {
-       /* try to smush double to int, but don't smush -2.0 to -2 */
-       if ((SvFLAGS(sv) & (SVf_IOK|SVf_NOK|SVf_POK)) == SVf_NOK &&
-           type != OP_NEGATE)
-       {
-#ifdef PERL_PRESERVE_IVUV
-           /* Only bother to attempt to fold to IV if
-              most operators will benefit  */
-           SvIV_please(sv);
-#endif
-       }
-       return newSVOP(OP_CONST, 0, sv);
-    }
+    return newSVOP(OP_CONST, 0, sv);
 
   nope:
     return o;
@@ -1963,8 +2095,9 @@ Perl_fold_constants(pTHX_ register OP *o)
 OP *
 Perl_gen_constant_list(pTHX_ register OP *o)
 {
+    dVAR;
     register OP *curop;
-    I32 oldtmps_floor = PL_tmps_floor;
+    const I32 oldtmps_floor = PL_tmps_floor;
 
     list(o);
     if (PL_error_count)
@@ -1981,7 +2114,9 @@ Perl_gen_constant_list(pTHX_ register OP *o)
 
     o->op_type = OP_RV2AV;
     o->op_ppaddr = PL_ppaddr[OP_RV2AV];
-    o->op_seq = 0;             /* needs to be revisited in peep() */
+    o->op_flags &= ~OPf_REF;   /* treat \(1..2) like an ordinary list */
+    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--));
     op_free(curop);
@@ -1992,6 +2127,7 @@ Perl_gen_constant_list(pTHX_ register OP *o)
 OP *
 Perl_convert(pTHX_ I32 type, I32 flags, OP *o)
 {
+    dVAR;
     if (!o || o->op_type != OP_LIST)
        o = newLISTOP(OP_LIST, 0, o, Nullop);
     else
@@ -2005,7 +2141,7 @@ Perl_convert(pTHX_ I32 type, I32 flags, OP *o)
     o->op_flags |= flags;
 
     o = CHECKOP(type, o);
-    if (o->op_type != type)
+    if (o->op_type != (unsigned)type)
        return o;
 
     return fold_constants(o);
@@ -2022,7 +2158,7 @@ Perl_append_elem(pTHX_ I32 type, OP *first, OP *last)
     if (!last)
        return first;
 
-    if (first->op_type != type
+    if (first->op_type != (unsigned)type
        || (type == OP_LIST && (first->op_flags & OPf_PARENS)))
     {
        return newLISTOP(type, 0, first, last);
@@ -2047,10 +2183,10 @@ Perl_append_list(pTHX_ I32 type, LISTOP *first, LISTOP *last)
     if (!last)
        return (OP*)first;
 
-    if (first->op_type != type)
+    if (first->op_type != (unsigned)type)
        return prepend_elem(type, (OP*)first, (OP*)last);
 
-    if (last->op_type != type)
+    if (last->op_type != (unsigned)type)
        return append_elem(type, (OP*)first, (OP*)last);
 
     first->op_last->op_sibling = last->op_first;
@@ -2071,7 +2207,7 @@ Perl_prepend_elem(pTHX_ I32 type, OP *first, OP *last)
     if (!last)
        return first;
 
-    if (last->op_type == type) {
+    if (last->op_type == (unsigned)type) {
        if (type == OP_LIST) {  /* already a PUSHMARK there */
            first->op_sibling = ((LISTOP*)last)->op_first->op_sibling;
            ((LISTOP*)last)->op_first->op_sibling = first;
@@ -2113,6 +2249,7 @@ Perl_force_list(pTHX_ OP *o)
 OP *
 Perl_newLISTOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
 {
+    dVAR;
     LISTOP *listop;
 
     NewOp(1101, listop, 1, LISTOP);
@@ -2141,12 +2278,13 @@ Perl_newLISTOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
            listop->op_last = pushop;
     }
 
-    return (OP*)listop;
+    return CHECKOP(type, listop);
 }
 
 OP *
 Perl_newOP(pTHX_ I32 type, I32 flags)
 {
+    dVAR;
     OP *o;
     NewOp(1101, o, 1, OP);
     o->op_type = (OPCODE)type;
@@ -2165,6 +2303,7 @@ Perl_newOP(pTHX_ I32 type, I32 flags)
 OP *
 Perl_newUNOP(pTHX_ I32 type, I32 flags, OP *first)
 {
+    dVAR;
     UNOP *unop;
 
     if (!first)
@@ -2188,6 +2327,7 @@ Perl_newUNOP(pTHX_ I32 type, I32 flags, OP *first)
 OP *
 Perl_newBINOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
 {
+    dVAR;
     BINOP *binop;
     NewOp(1101, binop, 1, BINOP);
 
@@ -2216,16 +2356,16 @@ 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)
+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 (*((UV *)a) < (*(UV *)b))
+    if (*((const UV *)a) < (*(const UV *)b))
        return -1;
-    if (*((UV *)a) > (*(UV *)b))
+    if (*((const UV *)a) > (*(const UV *)b))
        return 1;
-    if (*((UV *)a+1) < (*(UV *)b+1))
+    if (*((const UV *)a+1) < (*(const UV *)b+1))
        return -1;
-    if (*((UV *)a+1) > (*(UV *)b+1))
+    if (*((const UV *)a+1) > (*(const UV *)b+1))
        return 1;
     return 0;
 }
@@ -2233,12 +2373,12 @@ uvcompare(const void *a, const void *b)
 OP *
 Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
 {
-    SV *tstr = ((SVOP*)expr)->op_sv;
-    SV *rstr = ((SVOP*)repl)->op_sv;
+    SV * const tstr = ((SVOP*)expr)->op_sv;
+    SV * const rstr = ((SVOP*)repl)->op_sv;
     STRLEN tlen;
     STRLEN rlen;
-    U8 *t = (U8*)SvPV(tstr, tlen);
-    U8 *r = (U8*)SvPV(rstr, rlen);
+    const U8 *t = (U8*)SvPV_const(tstr, tlen);
+    const U8 *r = (U8*)SvPV_const(rstr, rlen);
     register I32 i;
     register I32 j;
     I32 del;
@@ -2261,16 +2401,16 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
     if (o->op_private & (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF)) {
        SV* listsv = newSVpvn("# comment\n",10);
        SV* transv = 0;
-       U8* tend = t + tlen;
-       U8* rend = r + rlen;
+       const U8* tend = t + tlen;
+       const U8* rend = r + rlen;
        STRLEN ulen;
-       U32 tfirst = 1;
-       U32 tlast = 0;
-       I32 tdiff;
-       U32 rfirst = 1;
-       U32 rlast = 0;
-       I32 rdiff;
-       I32 diff;
+       UV tfirst = 1;
+       UV tlast = 0;
+       IV tdiff;
+       UV rfirst = 1;
+       UV rlast = 0;
+       IV rdiff;
+       IV diff;
        I32 none = 0;
        U32 max = 0;
        I32 bits;
@@ -2283,12 +2423,12 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
 
        if (!from_utf) {
            STRLEN len = tlen;
-           tsave = t = bytes_to_utf8(t, &len);
+           t = tsave = bytes_to_utf8(t, &len);
            tend = t + len;
        }
        if (!to_utf && rlen) {
            STRLEN len = rlen;
-           rsave = r = bytes_to_utf8(r, &len);
+           r = rsave = bytes_to_utf8(r, &len);
            rend = r + len;
        }
 
@@ -2299,10 +2439,10 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
 */
 
        if (complement) {
-           U8 tmpbuf[UTF8_MAXLEN+1];
+           U8 tmpbuf[UTF8_MAXBYTES+1];
            UV *cp;
            UV nextmin = 0;
-           New(1109, cp, 2*tlen, UV);
+           Newx(cp, 2*tlen, UV);
            i = 0;
            transv = newSVpvn("",0);
            while (t < tend) {
@@ -2345,7 +2485,7 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
            t = uvuni_to_utf8_flags(tmpbuf, 0x7fffffff,
                                    UNICODE_ALLOW_SUPER);
            sv_catpvn(transv, (char*)tmpbuf, t - tmpbuf);
-           t = (U8*)SvPVX(transv);
+           t = (const U8*)SvPVX_const(transv);
            tlen = SvCUR(transv);
            tend = t + tlen;
            Safefree(cp);
@@ -2540,6 +2680,7 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
 OP *
 Perl_newPMOP(pTHX_ I32 type, I32 flags)
 {
+    dVAR;
     PMOP *pmop;
 
     NewOp(1101, pmop, 1, PMOP);
@@ -2573,23 +2714,70 @@ Perl_newPMOP(pTHX_ I32 type, I32 flags)
 
         /* link into pm list */
     if (type != OP_TRANS && PL_curstash) {
-       pmop->op_pmnext = HvPMROOT(PL_curstash);
-       HvPMROOT(PL_curstash) = pmop;
+       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 (OP*)pmop;
+    return CHECKOP(type, pmop);
 }
 
+/* Given some sort of match op o, and an expression expr containing a
+ * pattern, either compile expr into a regex and attach it to o (if it's
+ * constant), or convert expr into a runtime regcomp op sequence (if it's
+ * not)
+ *
+ * isreg indicates that the pattern is part of a regex construct, eg
+ * $x =~ /pattern/ or split /pattern/, as opposed to $x =~ $pattern or
+ * split "pattern", which aren't. In the former case, expr will be a list
+ * if the pattern contains more than one term (eg /a$b/) or if it contains
+ * a replacement, ie s/// or tr///.
+ */
+
 OP *
-Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl)
+Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
 {
+    dVAR;
     PMOP *pm;
     LOGOP *rcop;
     I32 repl_has_vars = 0;
+    OP* repl  = Nullop;
+    bool reglist;
 
-    if (o->op_type == OP_TRANS)
+    if (o->op_type == OP_SUBST || o->op_type == OP_TRANS) {
+       /* last element in list is the replacement; pop it */
+       OP* kid;
+       repl = cLISTOPx(expr)->op_last;
+       kid = cLISTOPx(expr)->op_first;
+       while (kid->op_sibling != repl)
+           kid = kid->op_sibling;
+       kid->op_sibling = Nullop;
+       cLISTOPx(expr)->op_last = kid;
+    }
+
+    if (isreg && expr->op_type == OP_LIST &&
+       cLISTOPx(expr)->op_first->op_sibling == cLISTOPx(expr)->op_last)
+    {
+       /* convert single element list to element */
+       OP* oe = expr;
+       expr = cLISTOPx(oe)->op_first->op_sibling;
+       cLISTOPx(oe)->op_first->op_sibling = Nullop;
+       cLISTOPx(oe)->op_last = Nullop;
+       op_free(oe);
+    }
+
+    if (o->op_type == OP_TRANS) {
        return pmtrans(o, expr, repl);
+    }
+
+    reglist = isreg && expr->op_type == OP_LIST;
+    if (reglist)
+       op_null(expr);
 
     PL_hints |= HINT_BLOCK_SCOPE;
     pm = (PMOP*)o;
@@ -2597,15 +2785,31 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl)
     if (expr->op_type == OP_CONST) {
        STRLEN plen;
        SV *pat = ((SVOP*)expr)->op_sv;
-       char *p = SvPV(pat, plen);
-       if ((o->op_flags & OPf_SPECIAL) && strEQ(p, " ")) {
+       const char *p = SvPV_const(pat, plen);
+       if ((o->op_flags & OPf_SPECIAL) && (*p == ' ' && p[1] == '\0')) {
+           U32 was_readonly = SvREADONLY(pat);
+
+           if (was_readonly) {
+               if (SvFAKE(pat)) {
+                   sv_force_normal_flags(pat, 0);
+                   assert(!SvREADONLY(pat));
+                   was_readonly = 0;
+               } else {
+                   SvREADONLY_off(pat);
+               }
+           }   
+
            sv_setpvn(pat, "\\s+", 3);
-           p = SvPV(pat, plen);
+
+           SvFLAGS(pat) |= was_readonly;
+
+           p = SvPV_const(pat, plen);
            pm->op_pmflags |= PMf_SKIPWHITE;
        }
         if (DO_UTF8(pat))
            pm->op_pmdynflags |= PMdf_UTF8;
-       PM_SETRE(pm, CALLREGCOMP(aTHX_ p, p + plen, pm));
+       /* 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;
        op_free(expr);
@@ -2620,11 +2824,16 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl)
        rcop->op_type = OP_REGCOMP;
        rcop->op_ppaddr = PL_ppaddr[OP_REGCOMP];
        rcop->op_first = scalar(expr);
-       rcop->op_flags |= ((PL_hints & HINT_RE_EVAL)
-                          ? (OPf_SPECIAL | OPf_KIDS)
-                          : OPf_KIDS);
+       rcop->op_flags |= OPf_KIDS
+                           | ((PL_hints & HINT_RE_EVAL) ? OPf_SPECIAL : 0)
+                           | (reglist ? OPf_STACKED : 0);
        rcop->op_private = 1;
        rcop->op_other = o;
+       if (reglist)
+           rcop->op_targ = pad_alloc(rcop->op_type, SVs_PADTMP);
+
+       /* /$x/ may cause an eval, since $x might be qr/(?{..})/  */
+       PL_cv_has_eval = 1;
 
        /* establish postfix order */
        if (pm->op_pmflags & PMf_KEEP || !(PL_hints & HINT_RE_EVAL)) {
@@ -2644,7 +2853,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl)
        OP *curop;
        if (pm->op_pmflags & PMf_EVAL) {
            curop = 0;
-           if (CopLINE(PL_curcop) < PL_multi_end)
+           if (CopLINE(PL_curcop) < (line_t)PL_multi_end)
                CopLINE_set(PL_curcop, (line_t)PL_multi_end);
        }
        else if (repl->op_type == OP_CONST)
@@ -2656,7 +2865,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl)
                    if (curop->op_type == OP_GV) {
                        GV *gv = cGVOPx_gv(curop);
                        repl_has_vars = 1;
-                       if (strchr("&`'123456789+", *GvENAME(gv)))
+                       if (strchr("&`'123456789+-\016\022", *GvENAME(gv)))
                            break;
                    }
                    else if (curop->op_type == OP_RV2CV)
@@ -2719,6 +2928,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl)
 OP *
 Perl_newSVOP(pTHX_ I32 type, I32 flags, SV *sv)
 {
+    dVAR;
     SVOP *svop;
     NewOp(1101, svop, 1, SVOP);
     svop->op_type = (OPCODE)type;
@@ -2736,6 +2946,7 @@ Perl_newSVOP(pTHX_ I32 type, I32 flags, SV *sv)
 OP *
 Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
 {
+    dVAR;
     PADOP *padop;
     NewOp(1101, padop, 1, PADOP);
     padop->op_type = (OPCODE)type;
@@ -2757,6 +2968,7 @@ Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
 OP *
 Perl_newGVOP(pTHX_ I32 type, I32 flags, GV *gv)
 {
+    dVAR;
 #ifdef USE_ITHREADS
     if (gv)
        GvIN_PAD_on(gv);
@@ -2769,6 +2981,7 @@ Perl_newGVOP(pTHX_ I32 type, I32 flags, GV *gv)
 OP *
 Perl_newPVOP(pTHX_ I32 type, I32 flags, char *pv)
 {
+    dVAR;
     PVOP *pvop;
     NewOp(1101, pvop, 1, PVOP);
     pvop->op_type = (OPCODE)type;
@@ -2786,13 +2999,13 @@ Perl_newPVOP(pTHX_ I32 type, I32 flags, char *pv)
 void
 Perl_package(pTHX_ OP *o)
 {
-    char *name;
+    const char *name;
     STRLEN len;
 
     save_hptr(&PL_curstash);
     save_item(PL_curstname);
 
-    name = SvPV(cSVOPo->op_sv, len);
+    name = SvPV_const(cSVOPo->op_sv, len);
     PL_curstash = gv_stashpvn(name, len, TRUE);
     sv_setpvn(PL_curstname, name, len);
     op_free(o);
@@ -2803,21 +3016,21 @@ Perl_package(pTHX_ OP *o)
 }
 
 void
-Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *id, OP *arg)
+Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *idop, OP *arg)
 {
     OP *pack;
     OP *imop;
     OP *veop;
 
-    if (id->op_type != OP_CONST)
+    if (idop->op_type != OP_CONST)
        Perl_croak(aTHX_ "Module name must be constant");
 
     veop = Nullop;
 
-    if (version != Nullop) {
+    if (version) {
        SV *vesv = ((SVOP*)version)->op_sv;
 
-       if (arg == Nullop && !SvNIOKp(vesv)) {
+       if (!arg && !SvNIOKp(vesv)) {
            arg = version;
        }
        else {
@@ -2827,14 +3040,11 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *id, OP *arg)
            if (version->op_type != OP_CONST || !SvNIOKp(vesv))
                Perl_croak(aTHX_ "Version number must be constant number");
 
-           /* Make copy of id so we don't free it twice */
-           pack = newSVOP(OP_CONST, 0, newSVsv(((SVOP*)id)->op_sv));
+           /* Make copy of idop so we don't free it twice */
+           pack = newSVOP(OP_CONST, 0, newSVsv(((SVOP*)idop)->op_sv));
 
            /* Fake up a method call to VERSION */
-           meth = newSVpvn("VERSION",7);
-           sv_upgrade(meth, SVt_PVIV);
-           (void)SvIOK_on(meth);
-           PERL_HASH(SvUVX(meth), SvPVX(meth), SvCUR(meth));
+           meth = newSVpvn_share("VERSION", 7, 0);
            veop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL,
                            append_elem(OP_LIST,
                                        prepend_elem(OP_LIST, pack, list(version)),
@@ -2845,20 +3055,20 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *id, OP *arg)
     /* Fake up an import/unimport */
     if (arg && arg->op_type == OP_STUB)
        imop = arg;             /* no import on explicit () */
-    else if (SvNIOKp(((SVOP*)id)->op_sv)) {
+    else if (SvNIOKp(((SVOP*)idop)->op_sv)) {
        imop = Nullop;          /* use 5.0; */
+       if (!aver)
+           idop->op_private |= OPpCONST_NOVER;
     }
     else {
        SV *meth;
 
-       /* Make copy of id so we don't free it twice */
-       pack = newSVOP(OP_CONST, 0, newSVsv(((SVOP*)id)->op_sv));
+       /* Make copy of idop so we don't free it twice */
+       pack = newSVOP(OP_CONST, 0, newSVsv(((SVOP*)idop)->op_sv));
 
        /* Fake up a method call to import/unimport */
-       meth = aver ? newSVpvn("import",6) : newSVpvn("unimport", 8);
-       (void)SvUPGRADE(meth, SVt_PVIV);
-       (void)SvIOK_on(meth);
-       PERL_HASH(SvUVX(meth), SvPVX(meth), SvCUR(meth));
+       meth = aver
+           ? newSVpvn_share("import",6, 0) : newSVpvn_share("unimport", 8, 0);
        imop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL,
                       append_elem(OP_LIST,
                                   prepend_elem(OP_LIST, pack, list(arg)),
@@ -2867,12 +3077,12 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *id, OP *arg)
 
     /* Fake up the BEGIN {}, which does its thing immediately. */
     newATTRSUB(floor,
-       newSVOP(OP_CONST, 0, newSVpvn("BEGIN", 5)),
+       newSVOP(OP_CONST, 0, newSVpvn_share("BEGIN", 5, 0)),
        Nullop,
        Nullop,
        append_elem(OP_LINESEQ,
            append_elem(OP_LINESEQ,
-               newSTATEOP(0, Nullch, newUNOP(OP_REQUIRE, 0, id)),
+               newSTATEOP(0, Nullch, newUNOP(OP_REQUIRE, 0, idop)),
                newSTATEOP(0, Nullch, veop)),
            newSTATEOP(0, Nullch, imop) ));
 
@@ -2896,6 +3106,7 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *id, OP *arg)
     PL_hints |= HINT_BLOCK_SCOPE;
     PL_copline = NOLINE;
     PL_expect = XSTATE;
+    PL_cop_seqmax++; /* Purely for B::*'s benefit */
 }
 
 /*
@@ -2963,25 +3174,31 @@ Perl_vload_module(pTHX_ U32 flags, SV *name, SV *ver, va_list *args)
        }
     }
     {
-       line_t ocopline = PL_copline;
-       int oexpect = PL_expect;
+       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;
     }
 }
 
 OP *
-Perl_dofile(pTHX_ OP *term)
+Perl_dofile(pTHX_ OP *term, I32 force_builtin)
 {
     OP *doop;
-    GV *gv;
+    GV *gv = Nullgv;
 
-    gv = gv_fetchpv("do", FALSE, SVt_PVCV);
-    if (!(gv && GvCVu(gv) && GvIMPORTED_CV(gv)))
-       gv = gv_fetchpv("CORE::GLOBAL::do", FALSE, SVt_PVCV);
+    if (!force_builtin) {
+       gv = gv_fetchpv("do", FALSE, SVt_PVCV);
+       if (!(gv && GvCVu(gv) && GvIMPORTED_CV(gv))) {
+           GV **gvp = (GV**)hv_fetch(PL_globalstash, "do", 2, FALSE);
+           if (gvp) gv = *gvp; else gv = Nullgv;
+       }
+    }
 
     if (gv && GvCVu(gv) && GvIMPORTED_CV(gv)) {
        doop = ck_subr(newUNOP(OP_ENTERSUB, OPf_STACKED,
@@ -3005,7 +3222,7 @@ Perl_newSLICEOP(pTHX_ I32 flags, OP *subscript, OP *listval)
 }
 
 STATIC I32
-S_list_assignment(pTHX_ register OP *o)
+S_is_list_assignment(pTHX_ register const OP *o)
 {
     if (!o)
        return TRUE;
@@ -3014,8 +3231,8 @@ S_list_assignment(pTHX_ register OP *o)
        o = cUNOPo->op_first;
 
     if (o->op_type == OP_COND_EXPR) {
-       I32 t = list_assignment(cLOGOPo->op_first->op_sibling);
-       I32 f = list_assignment(cLOGOPo->op_first->op_sibling->op_sibling);
+        const I32 t = is_list_assignment(cLOGOPo->op_first->op_sibling);
+        const I32 f = is_list_assignment(cLOGOPo->op_first->op_sibling->op_sibling);
 
        if (t && f)
            return TRUE;
@@ -3060,18 +3277,28 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
        }
     }
 
-    if (list_assignment(left)) {
+    if (is_list_assignment(left)) {
        OP *curop;
 
        PL_modcount = 0;
-       PL_eval_start = right;  /* Grandfathering $[ assignment here.  Bletch.*/
+       /* Grandfathering $[ assignment here.  Bletch.*/
+       /* Only simple assignments like C<< ($[) = 1 >> are allowed */
+       PL_eval_start = (left->op_type == OP_CONST) ? right : 0;
        left = mod(left, OP_AASSIGN);
        if (PL_eval_start)
            PL_eval_start = 0;
-       else {
-           op_free(left);
+       else if (left->op_type == OP_CONST) {
+           /* Result of assignment is always 1 (or we'd be dead already) */
+           return newSVOP(OP_CONST, 0, newSViv(1));
+       }
+       /* optimise C<my @x = ()> to C<my @x>, and likewise for hashes */
+       if ((left->op_type == OP_PADAV || left->op_type == OP_PADHV)
+               && right->op_type == OP_STUB
+               && (left->op_private & OPpLVAL_INTRO))
+       {
            op_free(right);
-           return Nullop;
+           left->op_flags &= ~(OPf_REF|OPf_SPECIAL);
+           return left;
        }
        curop = list(force_list(left));
        o = newBINOP(OP_AASSIGN, flags, list(force_list(right)), curop);
@@ -3100,7 +3327,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                        GV *gv = cGVOPx_gv(curop);
                        if (gv == PL_defgv || (int)SvCUR(gv) == PL_generation)
                            break;
-                       SvCUR(gv) = PL_generation;
+                       SvCUR_set(gv, PL_generation);
                    }
                    else if (curop->op_type == OP_PADSV ||
                             curop->op_type == OP_PADAV ||
@@ -3110,8 +3337,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                        if (PAD_COMPNAME_GEN(curop->op_targ)
                                                    == (STRLEN)PL_generation)
                            break;
-                       PAD_COMPNAME_GEN(curop->op_targ)
-                                                       = PL_generation;
+                       PAD_COMPNAME_GEN_set(curop->op_targ, PL_generation);
 
                    }
                    else if (curop->op_type == OP_RV2CV)
@@ -3133,7 +3359,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
 #endif
                            if (gv == PL_defgv || (int)SvCUR(gv) == PL_generation)
                                break;
-                           SvCUR(gv) = PL_generation;
+                           SvCUR_set(gv, PL_generation);
                        }
                    }
                    else
@@ -3200,8 +3426,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
        if (PL_eval_start)
            PL_eval_start = 0;
        else {
-           op_free(o);
-           return Nullop;
+           o = newSVOP(OP_CONST, 0, newSViv(PL_compiling.cop_arybase));
        }
     }
     return o;
@@ -3210,7 +3435,8 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
 OP *
 Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o)
 {
-    U32 seq = intro_my();
+    dVAR;
+    const U32 seq = intro_my();
     register COP *cop;
 
     NewOp(1101, cop, 1, COP);
@@ -3260,10 +3486,10 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o)
     CopSTASH_set(cop, PL_curstash);
 
     if (PERLDB_LINE && PL_curstash != PL_debstash) {
-       SV **svp = av_fetch(CopFILEAV(PL_curcop), (I32)CopLINE(cop), FALSE);
-        if (svp && *svp != &PL_sv_undef ) {
-           (void)SvIOK_on(*svp);
-           SvIVX(*svp) = PTR2IV(cop);
+       SV ** const svp = av_fetch(CopFILEAV(PL_curcop), (I32)CopLINE(cop), FALSE);
+       if (svp && *svp != &PL_sv_undef ) {
+           (void)SvIOK_on(*svp);
+           SvIV_set(*svp, PTR2IV(cop));
        }
     }
 
@@ -3274,16 +3500,18 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o)
 OP *
 Perl_newLOGOP(pTHX_ I32 type, I32 flags, OP *first, OP *other)
 {
+    dVAR;
     return new_logop(type, flags, &first, &other);
 }
 
 STATIC OP *
 S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
 {
+    dVAR;
     LOGOP *logop;
     OP *o;
     OP *first = *firstp;
-    OP *other = *otherp;
+    OP * const other = *otherp;
 
     if (type == OP_XOR)                /* Not short circuit, but here by precedence. */
        return newBINOP(type, flags, scalar(first), scalar(other));
@@ -3305,26 +3533,49 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
        }
     }
     if (first->op_type == OP_CONST) {
-       if (ckWARN(WARN_BAREWORD) && (first->op_private & OPpCONST_BARE)) {
-           if (first->op_private & OPpCONST_STRICT)
-               no_bareword_allowed(first);
-           else
+       if (first->op_private & OPpCONST_STRICT)
+           no_bareword_allowed(first);
+       else if ((first->op_private & OPpCONST_BARE) && ckWARN(WARN_BAREWORD))
                Perl_warner(aTHX_ packWARN(WARN_BAREWORD), "Bareword found in conditional");
-       }
-       if ((type == OP_AND) == (SvTRUE(((SVOP*)first)->op_sv))) {
+       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;
+           if (other->op_type == OP_CONST)
+               other->op_private |= OPpCONST_SHORTCIRCUIT;
            return other;
        }
        else {
+           /* check for C<my $x if 0>, or C<my($x,$y) if 0> */
+           const OP *o2 = other;
+           if ( ! (o2->op_type == OP_LIST
+                   && (( o2 = cUNOPx(o2)->op_first))
+                   && o2->op_type == OP_PUSHMARK
+                   && (( o2 = o2->op_sibling)) )
+           )
+               o2 = other;
+           if ((o2->op_type == OP_PADSV || o2->op_type == OP_PADAV
+                       || o2->op_type == OP_PADHV)
+               && o2->op_private & OPpLVAL_INTRO
+               && ckWARN(WARN_DEPRECATED))
+           {
+               Perl_warner(aTHX_ packWARN(WARN_DEPRECATED),
+                           "Deprecated use of my() in false conditional");
+           }
+
            op_free(other);
            *otherp = Nullop;
+           if (first->op_type == OP_CONST)
+               first->op_private |= OPpCONST_SHORTCIRCUIT;
            return first;
        }
     }
-    else if (ckWARN(WARN_MISC) && (first->op_flags & OPf_KIDS)) {
-       OP *k1 = ((UNOP*)first)->op_first;
-       OP *k2 = k1->op_sibling;
+    else if ((first->op_flags & OPf_KIDS) && type != OP_DOR
+       && ckWARN(WARN_MISC)) /* [#24076] Don't warn for <FH> err FOO. */
+    {
+       const OP * const k1 = ((UNOP*)first)->op_first;
+       const OP * const k2 = k1->op_sibling;
        OPCODE warnop = 0;
        switch (first->op_type)
        {
@@ -3349,7 +3600,7 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
            break;
        }
        if (warnop) {
-           line_t oldline = CopLINE(PL_curcop);
+           const line_t oldline = CopLINE(PL_curcop);
            CopLINE_set(PL_curcop, PL_copline);
            Perl_warner(aTHX_ packWARN(WARN_MISC),
                 "Value of %s%s can be \"0\"; test with defined()",
@@ -3380,6 +3631,8 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
     first->op_next = (OP*)logop;
     first->op_sibling = other;
 
+    CHECKOP(type,logop);
+
     o = newUNOP(OP_NULL, 0, (OP*)logop);
     other->op_next = o;
 
@@ -3389,6 +3642,7 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
 OP *
 Perl_newCONDOP(pTHX_ I32 flags, OP *first, OP *trueop, OP *falseop)
 {
+    dVAR;
     LOGOP *logop;
     OP *start;
     OP *o;
@@ -3401,9 +3655,9 @@ Perl_newCONDOP(pTHX_ I32 flags, OP *first, OP *trueop, OP *falseop)
     scalarboolean(first);
     if (first->op_type == OP_CONST) {
         if (first->op_private & OPpCONST_BARE &&
-           first->op_private & OPpCONST_STRICT) {
-           no_bareword_allowed(first);
-       }
+           first->op_private & OPpCONST_STRICT) {
+           no_bareword_allowed(first);
+       }
        if (SvTRUE(((SVOP*)first)->op_sv)) {
            op_free(first);
            op_free(falseop);
@@ -3424,6 +3678,8 @@ Perl_newCONDOP(pTHX_ I32 flags, OP *first, OP *trueop, OP *falseop)
     logop->op_other = LINKLIST(trueop);
     logop->op_next = LINKLIST(falseop);
 
+    CHECKOP(OP_COND_EXPR, /* that's logop->op_type */
+           logop);
 
     /* establish postfix order */
     start = LINKLIST(first);
@@ -3442,6 +3698,7 @@ Perl_newCONDOP(pTHX_ I32 flags, OP *first, OP *trueop, OP *falseop)
 OP *
 Perl_newRANGE(pTHX_ I32 flags, OP *left, OP *right)
 {
+    dVAR;
     LOGOP *range;
     OP *flip;
     OP *flop;
@@ -3490,9 +3747,11 @@ Perl_newLOOPOP(pTHX_ I32 flags, I32 debuggable, OP *expr, OP *block)
 {
     OP* listop;
     OP* o;
-    int once = block && block->op_flags & OPf_SPECIAL &&
+    const bool once = block && block->op_flags & OPf_SPECIAL &&
       (block->op_type == OP_ENTERSUB || block->op_type == OP_NULL);
 
+    PERL_UNUSED_ARG(debuggable);
+
     if (expr) {
        if (once && expr->op_type == OP_CONST && !SvTRUE(((SVOP*)expr)->op_sv))
            return block;       /* do {} while 0 does once */
@@ -3501,8 +3760,8 @@ Perl_newLOOPOP(pTHX_ I32 flags, I32 debuggable, OP *expr, OP *block)
            expr = newUNOP(OP_DEFINED, 0,
                newASSIGNOP(0, newDEFSVOP(), 0, expr) );
        } else if (expr->op_flags & OPf_KIDS) {
-           OP *k1 = ((UNOP*)expr)->op_first;
-           OP *k2 = (k1) ? k1->op_sibling : NULL;
+           const OP * const k1 = ((UNOP*)expr)->op_first;
+           const OP * const k2 = k1 ? k1->op_sibling : NULL;
            switch (expr->op_type) {
              case OP_NULL:
                if (k2 && k2->op_type == OP_READLINE
@@ -3522,6 +3781,10 @@ Perl_newLOOPOP(pTHX_ I32 flags, I32 debuggable, OP *expr, OP *block)
        }
     }
 
+    /* if block is null, the next append_elem() would put UNSTACK, a scalar
+     * op, in listop. This is wrong. [perl #27024] */
+    if (!block)
+       block = newOP(OP_NULL, 0);
     listop = append_elem(OP_LINESEQ, block, newOP(OP_UNSTACK, 0));
     o = new_logop(OP_AND, 0, &expr, &listop);
 
@@ -3541,42 +3804,48 @@ Perl_newLOOPOP(pTHX_ I32 flags, I32 debuggable, OP *expr, OP *block)
 }
 
 OP *
-Perl_newWHILEOP(pTHX_ I32 flags, I32 debuggable, LOOP *loop, I32 whileline, OP *expr, OP *block, OP *cont)
+Perl_newWHILEOP(pTHX_ I32 flags, I32 debuggable, LOOP *loop, I32
+whileline, OP *expr, OP *block, OP *cont, I32 has_my)
 {
+    dVAR;
     OP *redo;
     OP *next = 0;
     OP *listop;
     OP *o;
     U8 loopflags = 0;
 
-    if (expr && (expr->op_type == OP_READLINE || expr->op_type == OP_GLOB
-                || (expr->op_type == OP_NULL && expr->op_targ == OP_GLOB))) {
-       expr = newUNOP(OP_DEFINED, 0,
-           newASSIGNOP(0, newDEFSVOP(), 0, expr) );
-    } else if (expr && (expr->op_flags & OPf_KIDS)) {
-       OP *k1 = ((UNOP*)expr)->op_first;
-       OP *k2 = (k1) ? k1->op_sibling : NULL;
-       switch (expr->op_type) {
-         case OP_NULL:
-           if (k2 && k2->op_type == OP_READLINE
-                 && (k2->op_flags & OPf_STACKED)
-                 && ((k1->op_flags & OPf_WANT) == OPf_WANT_SCALAR))
-               expr = newUNOP(OP_DEFINED, 0, expr);
-           break;
+    PERL_UNUSED_ARG(debuggable);
 
-         case OP_SASSIGN:
-           if (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)
-               expr = newUNOP(OP_DEFINED, 0, expr);
-           break;
+    if (expr) {
+       if (expr->op_type == OP_READLINE || expr->op_type == OP_GLOB
+                    || (expr->op_type == OP_NULL && expr->op_targ == OP_GLOB)) {
+           expr = newUNOP(OP_DEFINED, 0,
+               newASSIGNOP(0, newDEFSVOP(), 0, expr) );
+       } else if (expr->op_flags & OPf_KIDS) {
+           const OP * const k1 = ((UNOP*)expr)->op_first;
+           const OP * const k2 = (k1) ? k1->op_sibling : NULL;
+           switch (expr->op_type) {
+             case OP_NULL:
+               if (k2 && k2->op_type == OP_READLINE
+                     && (k2->op_flags & OPf_STACKED)
+                     && ((k1->op_flags & OPf_WANT) == OPf_WANT_SCALAR))
+                   expr = newUNOP(OP_DEFINED, 0, expr);
+               break;
+
+             case OP_SASSIGN:
+               if (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)
+                   expr = newUNOP(OP_DEFINED, 0, expr);
+               break;
+           }
        }
     }
 
     if (!block)
        block = newOP(OP_NULL, 0);
-    else if (cont) {
+    else if (cont || has_my) {
        block = scope(block);
     }
 
@@ -3588,11 +3857,6 @@ Perl_newWHILEOP(pTHX_ I32 flags, I32 debuggable, LOOP *loop, I32 whileline, OP *
        if (!next)
            next = unstack;
        cont = append_elem(OP_LINESEQ, cont, unstack);
-       if ((line_t)whileline != NOLINE) {
-           PL_copline = (line_t)whileline;
-           cont = append_elem(OP_LINESEQ, cont,
-                              newSTATEOP(0, Nullch, Nullop));
-       }
     }
 
     listop = append_list(OP_LINESEQ, (LISTOP*)block, (LISTOP*)cont);
@@ -3639,19 +3903,23 @@ Perl_newWHILEOP(pTHX_ I32 flags, I32 debuggable, LOOP *loop, I32 whileline, OP *
 }
 
 OP *
-Perl_newFOROP(pTHX_ I32 flags,char *label,line_t forline,OP *sv,OP *expr,OP *block,OP *cont)
+Perl_newFOROP(pTHX_ I32 flags, char *label, line_t forline, OP *sv, OP *expr, OP *block, OP *cont)
 {
+    dVAR;
     LOOP *loop;
     OP *wop;
     PADOFFSET padoff = 0;
     I32 iterflags = 0;
+    I32 iterpflags = 0;
 
     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];
        }
        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);
@@ -3668,7 +3936,13 @@ Perl_newFOROP(pTHX_ I32 flags,char *label,line_t forline,OP *sv,OP *expr,OP *blo
            Perl_croak(aTHX_ "Can't use %s for loop variable", PL_op_desc[sv->op_type]);
     }
     else {
-       sv = newGVOP(OP_GV, 0, PL_defgv);
+        const I32 offset = pad_findmy("$_");
+       if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS(offset) & SVpad_OUR) {
+           sv = newGVOP(OP_GV, 0, PL_defgv);
+       }
+       else {
+           padoff = offset;
+       }
     }
     if (expr->op_type == OP_RV2AV || expr->op_type == OP_PADAV) {
        expr = mod(force_list(scalar(ref(expr, OP_ITER))), OP_GREPSTART);
@@ -3684,8 +3958,8 @@ Perl_newFOROP(pTHX_ I32 flags,char *label,line_t forline,OP *sv,OP *expr,OP *blo
         */
        UNOP* flip = (UNOP*)((UNOP*)((BINOP*)expr)->op_first)->op_first;
        LOGOP* range = (LOGOP*) flip->op_first;
-       OP* left  = range->op_first;
-       OP* right = left->op_sibling;
+       OP* const left  = range->op_first;
+       OP* const right = left->op_sibling;
        LISTOP* listop;
 
        range->op_flags &= ~OPf_KIDS;
@@ -3706,15 +3980,17 @@ Perl_newFOROP(pTHX_ I32 flags,char *label,line_t forline,OP *sv,OP *expr,OP *blo
         expr = mod(force_list(expr), OP_GREPSTART);
     }
 
-
     loop = (LOOP*)list(convert(OP_ENTERITER, iterflags,
                               append_elem(OP_LIST, expr, scalar(sv))));
     assert(!loop->op_next);
+    /* for my  $x () sets OPpLVAL_INTRO;
+     * for our $x () sets OPpOUR_INTRO */
+    loop->op_private = (U8)iterpflags;
 #ifdef PL_OP_SLAB_ALLOC
     {
        LOOP *tmp;
        NewOp(1234,tmp,1,LOOP);
-       Copy(loop,tmp,1,LOOP);
+       Copy(loop,tmp,1,LISTOP);
        FreeOp(loop);
        loop = tmp;
     }
@@ -3722,7 +3998,7 @@ Perl_newFOROP(pTHX_ I32 flags,char *label,line_t forline,OP *sv,OP *expr,OP *blo
     Renew(loop, 1, LOOP);
 #endif
     loop->op_targ = padoff;
-    wop = newWHILEOP(flags, 1, loop, forline, newOP(OP_ITER, 0), block, cont);
+    wop = newWHILEOP(flags, 1, loop, forline, newOP(OP_ITER, 0), block, cont, 0);
     PL_copline = forline;
     return newSTATEOP(0, label, wop);
 }
@@ -3731,7 +4007,6 @@ OP*
 Perl_newLOOPEX(pTHX_ I32 type, OP *label)
 {
     OP *o;
-    STRLEN n_a;
 
     if (type != OP_GOTO || label->op_type == OP_CONST) {
        /* "last()" means "last" */
@@ -3739,13 +4014,15 @@ Perl_newLOOPEX(pTHX_ I32 type, OP *label)
            o = newOP(type, OPf_SPECIAL);
        else {
            o = newPVOP(type, 0, savepv(label->op_type == OP_CONST
-                                       ? SvPVx(((SVOP*)label)->op_sv, n_a)
+                                       ? SvPVx_nolen_const(((SVOP*)label)->op_sv)
                                        : ""));
        }
        op_free(label);
     }
     else {
-       if (label->op_type == OP_ENTERSUB)
+       /* Check whether it's going to be a goto &function */
+       if (label->op_type == OP_ENTERSUB
+               && !(label->op_flags & OPf_STACKED))
            label = newUNOP(OP_REFGEN, 0, mod(label, OP_REFGEN));
        o = newUNOP(type, OPf_STACKED, label);
     }
@@ -3767,6 +4044,7 @@ children can still follow the full lexical scope chain.
 void
 Perl_cv_undef(pTHX_ CV *cv)
 {
+    dVAR;
 #ifdef USE_ITHREADS
     if (CvFILE(cv) && !CvXSUB(cv)) {
        /* for XSUBs CvFILE point directly to static memory; __FILE__ */
@@ -3784,6 +4062,7 @@ Perl_cv_undef(pTHX_ CV *cv)
 
        op_free(CvROOT(cv));
        CvROOT(cv) = Nullop;
+       CvSTART(cv) = Nullop;
        LEAVE;
     }
     SvPOK_off((SV*)cv);                /* forget prototype */
@@ -3809,10 +4088,10 @@ Perl_cv_undef(pTHX_ CV *cv)
 }
 
 void
-Perl_cv_ckproto(pTHX_ CV *cv, GV *gv, char *p)
+Perl_cv_ckproto(pTHX_ const CV *cv, const GV *gv, const char *p)
 {
-    if (((!p != !SvPOK(cv)) || (p && strNE(p, SvPVX(cv)))) && ckWARN_d(WARN_PROTOTYPE)) {
-       SV* msg = sv_newmortal();
+    if (((!p != !SvPOK(cv)) || (p && strNE(p, SvPVX_const(cv)))) && ckWARN_d(WARN_PROTOTYPE)) {
+       SV* const msg = sv_newmortal();
        SV* name = Nullsv;
 
        if (gv)
@@ -3821,7 +4100,9 @@ Perl_cv_ckproto(pTHX_ CV *cv, GV *gv, char *p)
        if (name)
            Perl_sv_catpvf(aTHX_ msg, " sub %"SVf, name);
        if (SvPOK(cv))
-           Perl_sv_catpvf(aTHX_ msg, " (%"SVf")", (SV *)cv);
+           Perl_sv_catpvf(aTHX_ msg, " (%"SVf")", (const SV *)cv);
+       else
+           Perl_sv_catpv(aTHX_ msg, ": none");
        sv_catpv(msg, " vs ");
        if (p)
            Perl_sv_catpvf(aTHX_ msg, "(%s)", p);
@@ -3855,8 +4136,28 @@ Perl_cv_const_sv(pTHX_ CV *cv)
     return (SV*)CvXSUBANY(cv).any_ptr;
 }
 
+/* op_const_sv:  examine an optree to determine whether it's in-lineable.
+ * Can be called in 3 ways:
+ *
+ * !cv
+ *     look for a single OP_CONST with attached value: return the value
+ *
+ * cv && CvCLONE(cv) && !CvCONST(cv)
+ *
+ *     examine the clone prototype, and if contains only a single
+ *     OP_CONST referencing a pad const, or a single PADSV referencing
+ *     an outer lexical, return a non-zero value to indicate the CV is
+ *     a candidate for "constizing" at clone time
+ *
+ * cv && CvCONST(cv)
+ *
+ *     We have just cloned an anon prototype that was marked as a const
+ *     candidiate. Try to grab the current value, and in the case of
+ *     PADSV, ignore it if it has multiple references. Return the value.
+ */
+
 SV *
-Perl_op_const_sv(pTHX_ OP *o, CV *cv)
+Perl_op_const_sv(pTHX_ const OP *o, CV *cv)
 {
     SV *sv = Nullsv;
 
@@ -3867,7 +4168,7 @@ Perl_op_const_sv(pTHX_ OP *o, CV *cv)
        o = cLISTOPo->op_first->op_sibling;
 
     for (; o; o = o->op_next) {
-       OPCODE type = o->op_type;
+       const OPCODE type = o->op_type;
 
        if (sv && o->op_next == o)
            return sv;
@@ -3883,32 +4184,39 @@ Perl_op_const_sv(pTHX_ OP *o, CV *cv)
            return Nullsv;
        if (type == OP_CONST && cSVOPo->op_sv)
            sv = cSVOPo->op_sv;
-       else if ((type == OP_PADSV || type == OP_CONST) && cv) {
+       else if (cv && type == OP_CONST) {
            sv = PAD_BASE_SV(CvPADLIST(cv), o->op_targ);
            if (!sv)
                return Nullsv;
-           if (CvCONST(cv)) {
-               /* We get here only from cv_clone2() while creating a closure.
-                  Copy the const value here instead of in cv_clone2 so that
-                  SvREADONLY_on doesn't lead to problems when leaving
-                  scope.
-               */
+       }
+       else if (cv && type == OP_PADSV) {
+           if (CvCONST(cv)) { /* newly cloned anon */
+               sv = PAD_BASE_SV(CvPADLIST(cv), o->op_targ);
+               /* the candidate should have 1 ref from this pad and 1 ref
+                * from the parent */
+               if (!sv || SvREFCNT(sv) != 2)
+                   return Nullsv;
                sv = newSVsv(sv);
+               SvREADONLY_on(sv);
+               return sv;
+           }
+           else {
+               if (PAD_COMPNAME_FLAGS(o->op_targ) & SVf_FAKE)
+                   sv = &PL_sv_undef; /* an arbitrary non-null value */
            }
-           if (!SvREADONLY(sv) && SvREFCNT(sv) > 1)
-               return Nullsv;
        }
-       else
+       else {
            return Nullsv;
+       }
     }
-    if (sv)
-       SvREADONLY_on(sv);
     return sv;
 }
 
 void
 Perl_newMYSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
 {
+    PERL_UNUSED_ARG(floor);
+
     if (o)
        SAVEFREEOP(o);
     if (proto)
@@ -3929,28 +4237,40 @@ Perl_newSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *block)
 CV *
 Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
 {
-    STRLEN n_a;
-    char *name;
-    char *aname;
+    dVAR;
+    const char *aname;
     GV *gv;
-    char *ps = proto ? SvPVx(((SVOP*)proto)->op_sv, n_a) : Nullch;
+    const char *ps;
+    STRLEN ps_len;
     register CV *cv=0;
     SV *const_sv;
+    I32 gv_fetch_flags;
+
+    const char * const name = o ? SvPVx_nolen_const(cSVOPo->op_sv) : Nullch;
+
+    if (proto) {
+       assert(proto->op_type == OP_CONST);
+       ps = SvPVx_const(((SVOP*)proto)->op_sv, ps_len);
+    }
+    else
+       ps = Nullch;
 
-    name = o ? SvPVx(cSVOPo->op_sv, n_a) : Nullch;
     if (!name && PERLDB_NAMEANON && CopLINE(PL_curcop)) {
-       SV *sv = sv_newmortal();
+       SV * const sv = sv_newmortal();
        Perl_sv_setpvf(aTHX_ sv, "%s[%s:%"IVdf"]",
                       PL_curstash ? "__ANON__" : "__ANON__::__ANON__",
                       CopFILE(PL_curcop), (IV)CopLINE(PL_curcop));
-       aname = SvPVX(sv);
+       aname = SvPVX_const(sv);
     }
     else
        aname = Nullch;
-    gv = gv_fetchpv(name ? name : (aname ? aname : 
-                   (PL_curstash ? "__ANON__" : "__ANON__::__ANON__")),
-                   GV_ADDMULTI | ((block || attrs) ? 0 : GV_NOINIT),
-                   SVt_PVCV);
+
+    gv_fetch_flags = (block || attrs || (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS))
+       ? GV_ADDMULTI : GV_ADDMULTI | GV_NOINIT;
+    gv = name ? gv_fetchsv(cSVOPo->op_sv, gv_fetch_flags, SVt_PVCV)
+       : gv_fetchpv(aname ? aname
+                    : (PL_curstash ? "__ANON__" : "__ANON__::__ANON__"),
+                    gv_fetch_flags, SVt_PVCV);
 
     if (o)
        SAVEFREEOP(o);
@@ -3970,7 +4290,7 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            cv_ckproto((CV*)gv, NULL, ps);
        }
        if (ps)
-           sv_setpv((SV*)gv, ps);
+           sv_setpvn((SV*)gv, ps, ps_len);
        else
            sv_setiv((SV*)gv, -1);
        SvREFCNT_dec(PL_compcv);
@@ -3987,13 +4307,13 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
     }
 #endif
 
-    if (!block || !ps || *ps || attrs)
+    if (!block || !ps || *ps || attrs || (CvFLAGS(PL_compcv) & CVf_BUILTIN_ATTRS))
        const_sv = Nullsv;
     else
        const_sv = op_const_sv(block, Nullcv);
 
     if (cv) {
-        bool exists = CvROOT(cv) || CvXSUB(cv);
+        const bool exists = CvROOT(cv) || CvXSUB(cv);
 
 #ifdef GV_UNIQUE_CHECK
         if (exists && GvUNIQUE(gv)) {
@@ -4026,7 +4346,7 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                    || (CvCONST(cv)
                        && (!const_sv || sv_cmp(cv_const_sv(cv), const_sv))))
                {
-                   line_t oldline = CopLINE(PL_curcop);
+                   const line_t oldline = CopLINE(PL_curcop);
                    if (PL_copline != NOLINE)
                        CopLINE_set(PL_curcop, PL_copline);
                    Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
@@ -4040,10 +4360,10 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        }
     }
     if (const_sv) {
-       SvREFCNT_inc(const_sv);
+       (void)SvREFCNT_inc(const_sv);
        if (cv) {
            assert(!CvROOT(cv) && !CvCONST(cv));
-           sv_setpv((SV*)cv, "");  /* prototype is "" */
+           sv_setpvn((SV*)cv, "", 0);  /* prototype is "" */
            CvXSUBANY(cv).any_ptr = const_sv;
            CvXSUB(cv) = const_sv_xsub;
            CvCONST_on(cv);
@@ -4095,6 +4415,8 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        /* transfer PL_compcv to cv */
        cv_undef(cv);
        CvFLAGS(cv) = CvFLAGS(PL_compcv);
+       if (!CvWEAKOUTSIDE(cv))
+           SvREFCNT_dec(CvOUTSIDE(cv));
        CvOUTSIDE(cv) = CvOUTSIDE(PL_compcv);
        CvOUTSIDE_SEQ(cv) = CvOUTSIDE_SEQ(PL_compcv);
        CvOUTSIDE(PL_compcv) = 0;
@@ -4104,6 +4426,7 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        pad_fixup_inner_anons(CvPADLIST(cv), PL_compcv, cv);
        /* ... before we throw it away */
        SvREFCNT_dec(PL_compcv);
+       PL_compcv = cv;
        if (PERLDB_INTER)/* Advice debugger on the new sub. */
          ++PL_sub_generation;
     }
@@ -4120,16 +4443,16 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
     CvSTASH(cv) = PL_curstash;
 
     if (ps)
-       sv_setpv((SV*)cv, ps);
+       sv_setpvn((SV*)cv, ps, ps_len);
 
     if (PL_error_count) {
        op_free(block);
        block = Nullop;
        if (name) {
-           char *s = strrchr(name, ':');
+           const char *s = strrchr(name, ':');
            s = s ? s+1 : name;
            if (strEQ(s, "BEGIN")) {
-               char *not_safe =
+               const char not_safe[] =
                    "BEGIN not safe after errors--compilation aborted";
                if (PL_in_eval & EVAL_KEEPERR)
                    Perl_croak(aTHX_ not_safe);
@@ -4149,6 +4472,11 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                             mod(scalarseq(block), OP_LEAVESUBLV));
     }
     else {
+       /* This makes sub {}; work as expected.  */
+       if (block->op_type == OP_STUB) {
+           op_free(block);
+           block = newSTATEOP(0, Nullch, 0);
+       }
        CvROOT(cv) = newUNOP(OP_LEAVESUB, 0, scalarseq(block));
     }
     CvROOT(cv)->op_private |= OPpREFCOUNTED;
@@ -4168,8 +4496,8 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
     }
 
     if (name || aname) {
-       char *s;
-       char *tname = (name ? name : aname);
+       const char *s;
+       const char *tname = (name ? name : aname);
 
        if (PERLDB_SUBLINE && PL_curstash != PL_debstash) {
            SV *sv = NEWSV(0,0);
@@ -4182,9 +4510,9 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                           CopFILE(PL_curcop),
                           (long)PL_subline, (long)CopLINE(PL_curcop));
            gv_efullname3(tmpstr, gv, Nullch);
-           hv_store(GvHV(PL_DBsub), SvPVX(tmpstr), SvCUR(tmpstr), sv, 0);
+           hv_store(GvHV(PL_DBsub), SvPVX_const(tmpstr), SvCUR(tmpstr), sv, 0);
            hv = GvHVn(db_postponed);
-           if (HvFILL(hv) > 0 && hv_exists(hv, SvPVX(tmpstr), SvCUR(tmpstr))
+           if (HvFILL(hv) > 0 && hv_exists(hv, SvPVX_const(tmpstr), SvCUR(tmpstr))
                && (pcv = GvCV(db_postponed)))
            {
                dSP;
@@ -4203,8 +4531,8 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        if (*s != 'B' && *s != 'E' && *s != 'C' && *s != 'I')
            goto done;
 
-       if (strEQ(s, "BEGIN")) {
-           I32 oldscope = PL_scopestack_ix;
+       if (strEQ(s, "BEGIN") && !PL_error_count) {
+           const I32 oldscope = PL_scopestack_ix;
            ENTER;
            SAVECOPFILE(&PL_compiling);
            SAVECOPLINE(&PL_compiling);
@@ -4266,8 +4594,9 @@ eligible for inlining at compile-time.
 */
 
 CV *
-Perl_newCONSTSUB(pTHX_ HV *stash, char *name, SV *sv)
+Perl_newCONSTSUB(pTHX_ HV *stash, const char *name, SV *sv)
 {
+    dVAR;
     CV* cv;
 
     ENTER;
@@ -4285,10 +4614,13 @@ Perl_newCONSTSUB(pTHX_ HV *stash, char *name, SV *sv)
        CopSTASH_set(PL_curcop,stash);
     }
 
-    cv = newXS(name, const_sv_xsub, __FILE__);
+    cv = newXS(name, const_sv_xsub, savepv(CopFILE(PL_curcop)));
     CvXSUBANY(cv).any_ptr = sv;
     CvCONST_on(cv);
-    sv_setpv((SV*)cv, "");  /* prototype is "" */
+    sv_setpvn((SV*)cv, "", 0);  /* prototype is "" */
+
+    if (stash)
+       CopSTASH_free(PL_curcop);
 
     LEAVE;
 
@@ -4304,9 +4636,9 @@ Used by C<xsubpp> to hook up XSUBs as Perl subs.
 */
 
 CV *
-Perl_newXS(pTHX_ char *name, XSUBADDR_t subaddr, char *filename)
+Perl_newXS(pTHX_ const char *name, XSUBADDR_t subaddr, const char *filename)
 {
-    GV *gv = gv_fetchpv(name ? name :
+    GV * const gv = gv_fetchpv(name ? name :
                        (PL_curstash ? "__ANON__" : "__ANON__::__ANON__"),
                        GV_ADDMULTI, SVt_PVCV);
     register CV *cv;
@@ -4318,23 +4650,32 @@ Perl_newXS(pTHX_ char *name, XSUBADDR_t subaddr, char *filename)
        if (GvCVGEN(gv)) {
            /* just a cached method */
            SvREFCNT_dec(cv);
-           cv = 0;
+           cv = Nullcv;
        }
        else if (CvROOT(cv) || CvXSUB(cv) || GvASSUMECV(gv)) {
            /* already defined (or promised) */
-           if (ckWARN(WARN_REDEFINE) && !(CvGV(cv) && GvSTASH(CvGV(cv))
-                           && strEQ(HvNAME(GvSTASH(CvGV(cv))), "autouse"))) {
-               line_t oldline = CopLINE(PL_curcop);
-               if (PL_copline != NOLINE)
-                   CopLINE_set(PL_curcop, PL_copline);
-               Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
-                           CvCONST(cv) ? "Constant subroutine %s redefined"
-                                       : "Subroutine %s redefined"
-                           ,name);
-               CopLINE_set(PL_curcop, oldline);
+           /* XXX It's possible for this HvNAME_get to return null, and get passed into strEQ */
+           if (ckWARN(WARN_REDEFINE)) {
+               GV * const gvcv = CvGV(cv);
+               if (gvcv) {
+                   HV * const stash = GvSTASH(gvcv);
+                   if (stash) {
+                       const char *name = HvNAME_get(stash);
+                       if ( strEQ(name,"autouse") ) {
+                           const line_t oldline = CopLINE(PL_curcop);
+                           if (PL_copline != NOLINE)
+                               CopLINE_set(PL_curcop, PL_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 = 0;
+           cv = Nullcv;
        }
     }
 
@@ -4351,12 +4692,12 @@ Perl_newXS(pTHX_ char *name, XSUBADDR_t subaddr, char *filename)
     }
     CvGV(cv) = gv;
     (void)gv_fetchfile(filename);
-    CvFILE(cv) = filename;     /* NOTE: not copied, as it is expected to be
+    CvFILE(cv) = (char *)filename; /* NOTE: not copied, as it is expected to be
                                   an external constant string */
     CvXSUB(cv) = subaddr;
 
     if (name) {
-       char *s = strrchr(name,':');
+       const char *s = strrchr(name,':');
        if (s)
            s++;
        else
@@ -4407,15 +4748,13 @@ void
 Perl_newFORM(pTHX_ I32 floor, OP *o, OP *block)
 {
     register CV *cv;
-    char *name;
     GV *gv;
-    STRLEN n_a;
 
     if (o)
-       name = SvPVx(cSVOPo->op_sv, n_a);
+       gv = gv_fetchsv(cSVOPo->op_sv, TRUE, SVt_PVFM);
     else
-       name = "STDOUT";
-    gv = gv_fetchpv(name,TRUE, SVt_PVFM);
+       gv = gv_fetchpv("STDOUT", TRUE, SVt_PVFM);
+    
 #ifdef GV_UNIQUE_CHECK
     if (GvUNIQUE(gv)) {
         Perl_croak(aTHX_ "Bad symbol for form (GV is unique)");
@@ -4424,10 +4763,12 @@ Perl_newFORM(pTHX_ I32 floor, OP *o, OP *block)
     GvMULTI_on(gv);
     if ((cv = GvFORM(gv))) {
        if (ckWARN(WARN_REDEFINE)) {
-           line_t oldline = CopLINE(PL_curcop);
+           const line_t oldline = CopLINE(PL_curcop);
            if (PL_copline != NOLINE)
                CopLINE_set(PL_curcop, PL_copline);
-           Perl_warner(aTHX_ packWARN(WARN_REDEFINE), "Format %s redefined",name);
+           Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
+                       o ? "Format %"SVf" redefined"
+                       : "Format STDOUT redefined" ,cSVOPo->op_sv);
            CopLINE_set(PL_curcop, oldline);
        }
        SvREFCNT_dec(cv);
@@ -4481,6 +4822,7 @@ Perl_newANONATTRSUB(pTHX_ I32 floor, OP *proto, OP *attrs, OP *block)
 OP *
 Perl_oopsAV(pTHX_ OP *o)
 {
+    dVAR;
     switch (o->op_type) {
     case OP_PADSV:
        o->op_type = OP_PADAV;
@@ -4504,6 +4846,7 @@ Perl_oopsAV(pTHX_ OP *o)
 OP *
 Perl_oopsHV(pTHX_ OP *o)
 {
+    dVAR;
     switch (o->op_type) {
     case OP_PADSV:
     case OP_PADAV:
@@ -4529,6 +4872,7 @@ Perl_oopsHV(pTHX_ OP *o)
 OP *
 Perl_newAVREF(pTHX_ OP *o)
 {
+    dVAR;
     if (o->op_type == OP_PADANY) {
        o->op_type = OP_PADAV;
        o->op_ppaddr = PL_ppaddr[OP_PADAV];
@@ -4553,6 +4897,7 @@ Perl_newGVREF(pTHX_ I32 type, OP *o)
 OP *
 Perl_newHVREF(pTHX_ OP *o)
 {
+    dVAR;
     if (o->op_type == OP_PADANY) {
        o->op_type = OP_PADHV;
        o->op_ppaddr = PL_ppaddr[OP_PADHV];
@@ -4571,7 +4916,8 @@ Perl_oopsCV(pTHX_ OP *o)
 {
     Perl_croak(aTHX_ "NOT IMPL LINE %d",__LINE__);
     /* STUB */
-    return o;
+    PERL_UNUSED_ARG(o);
+    NORETURN_FUNCTION_END;
 }
 
 OP *
@@ -4583,6 +4929,7 @@ Perl_newCVREF(pTHX_ I32 flags, OP *o)
 OP *
 Perl_newSVREF(pTHX_ OP *o)
 {
+    dVAR;
     if (o->op_type == OP_PADANY) {
        o->op_type = OP_PADSV;
        o->op_ppaddr = PL_ppaddr[OP_PADSV];
@@ -4595,7 +4942,8 @@ Perl_newSVREF(pTHX_ OP *o)
     return newUNOP(OP_RV2SV, 0, scalar(o));
 }
 
-/* Check routines. */
+/* Check routines. See the comments at the top of this file for details
+ * on when these are called */
 
 OP *
 Perl_ck_anoncode(pTHX_ OP *o)
@@ -4617,13 +4965,17 @@ Perl_ck_bitop(pTHX_ OP *o)
         (op) == OP_NE   || (op) == OP_I_NE || \
         (op) == OP_NCMP || (op) == OP_I_NCMP)
     o->op_private = (U8)(PL_hints & HINT_PRIVATE_MASK);
-    if (o->op_type == OP_BIT_OR
-           || o->op_type == OP_BIT_AND
-           || o->op_type == OP_BIT_XOR)
+    if (!(o->op_flags & OPf_STACKED) /* Not an assignment */
+           && (o->op_type == OP_BIT_OR
+            || o->op_type == OP_BIT_AND
+            || o->op_type == OP_BIT_XOR))
     {
-       OPCODE typfirst = cBINOPo->op_first->op_type;
-       OPCODE typlast  = cBINOPo->op_first->op_sibling->op_type;
-       if (OP_IS_NUMCOMPARE(typfirst) || OP_IS_NUMCOMPARE(typlast))
+       const OP * const left = cBINOPo->op_first;
+       const OP * const right = left->op_sibling;
+       if ((OP_IS_NUMCOMPARE(left->op_type) &&
+               (left->op_flags & OPf_PARENS) == 0) ||
+           (OP_IS_NUMCOMPARE(right->op_type) &&
+               (right->op_flags & OPf_PARENS) == 0))
            if (ckWARN(WARN_PRECEDENCE))
                Perl_warner(aTHX_ packWARN(WARN_PRECEDENCE),
                        "Possible precedence problem on bitwise %c operator",
@@ -4637,18 +4989,21 @@ Perl_ck_bitop(pTHX_ OP *o)
 OP *
 Perl_ck_concat(pTHX_ OP *o)
 {
-    if (cUNOPo->op_first->op_type == OP_CONCAT)
-       o->op_flags |= OPf_STACKED;
+    const OP *kid = cUNOPo->op_first;
+    if (kid->op_type == OP_CONCAT && !(kid->op_private & OPpTARGET_MY) &&
+           !(kUNOP->op_first->op_flags & OPf_MOD))
+        o->op_flags |= OPf_STACKED;
     return o;
 }
 
 OP *
 Perl_ck_spair(pTHX_ OP *o)
 {
+    dVAR;
     if (o->op_flags & OPf_KIDS) {
        OP* newop;
        OP* kid;
-       OPCODE type = o->op_type;
+       const OPCODE type = o->op_type;
        o = modkids(ck_fun(o), type);
        kid = cUNOPo->op_first;
        newop = kUNOP->op_first->op_sibling;
@@ -4707,13 +5062,12 @@ Perl_ck_die(pTHX_ OP *o)
 OP *
 Perl_ck_eof(pTHX_ OP *o)
 {
-    I32 type = o->op_type;
+    const I32 type = o->op_type;
 
     if (o->op_flags & OPf_KIDS) {
        if (cLISTOPo->op_first->op_type == OP_STUB) {
            op_free(o);
-           o = newUNOP(type, OPf_SPECIAL,
-               newGVOP(OP_GV, 0, gv_fetchpv("main::ARGV", TRUE, SVt_PVAV)));
+           o = newUNOP(type, OPf_SPECIAL, newGVOP(OP_GV, 0, PL_argvgv));
        }
        return ck_fun(o);
     }
@@ -4723,18 +5077,18 @@ Perl_ck_eof(pTHX_ OP *o)
 OP *
 Perl_ck_eval(pTHX_ OP *o)
 {
+    dVAR;
     PL_hints |= HINT_BLOCK_SCOPE;
     if (o->op_flags & OPf_KIDS) {
-       SVOP *kid = (SVOP*)cUNOPo->op_first;
+       SVOP * const kid = (SVOP*)cUNOPo->op_first;
 
        if (!kid) {
            o->op_flags &= ~OPf_KIDS;
            op_null(o);
        }
-       else if (kid->op_type == OP_LINESEQ) {
+       else if (kid->op_type == OP_LINESEQ || kid->op_type == OP_STUB) {
            LOGOP *enter;
 
-           kid->op_next = o->op_next;
            cUNOPo->op_first = 0;
            op_free(o);
 
@@ -4752,8 +5106,10 @@ Perl_ck_eval(pTHX_ OP *o)
            enter->op_other = o;
            return o;
        }
-       else
+       else {
            scalar((OP*)kid);
+           PL_cv_has_eval = 1;
+       }
     }
     else {
        op_free(o);
@@ -4781,8 +5137,8 @@ Perl_ck_exit(pTHX_ OP *o)
 OP *
 Perl_ck_exec(pTHX_ OP *o)
 {
-    OP *kid;
     if (o->op_flags & OPf_STACKED) {
+        OP *kid;
        o = ck_fun(o);
        kid = cUNOPo->op_first->op_sibling;
        if (kid->op_type == OP_RV2GV)
@@ -4798,7 +5154,7 @@ Perl_ck_exists(pTHX_ OP *o)
 {
     o = ck_fun(o);
     if (o->op_flags & OPf_KIDS) {
-       OP *kid = cUNOPo->op_first;
+       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)
@@ -4816,35 +5172,23 @@ Perl_ck_exists(pTHX_ OP *o)
     return o;
 }
 
-#if 0
-OP *
-Perl_ck_gvconst(pTHX_ register OP *o)
-{
-    o = fold_constants(o);
-    if (o->op_type == OP_CONST)
-       o->op_type = OP_GV;
-    return o;
-}
-#endif
-
 OP *
 Perl_ck_rvconst(pTHX_ register OP *o)
 {
+    dVAR;
     SVOP *kid = (SVOP*)cUNOPo->op_first;
 
     o->op_private |= (PL_hints & HINT_STRICT_REFS);
     if (kid->op_type == OP_CONST) {
-       char *name;
        int iscv;
        GV *gv;
-       SV *kidsv = kid->op_sv;
-       STRLEN n_a;
+       SV * const kidsv = kid->op_sv;
 
        /* Is it a constant from cv_const_sv()? */
        if (SvROK(kidsv) && SvREADONLY(kidsv)) {
            SV *rsv = SvRV(kidsv);
-           int svtype = SvTYPE(rsv);
-           char *badtype = Nullch;
+           const int svtype = SvTYPE(rsv);
+            const char *badtype = Nullch;
 
            switch (o->op_type) {
            case OP_RV2SV:
@@ -4868,9 +5212,8 @@ Perl_ck_rvconst(pTHX_ register OP *o)
                Perl_croak(aTHX_ "Constant is not %s reference", badtype);
            return o;
        }
-       name = SvPV(kidsv, n_a);
        if ((PL_hints & HINT_STRICT_REFS) && (kid->op_private & OPpCONST_BARE)) {
-           char *badthing = Nullch;
+            const char *badthing = Nullch;
            switch (o->op_type) {
            case OP_RV2SV:
                badthing = "a SCALAR";
@@ -4884,8 +5227,8 @@ Perl_ck_rvconst(pTHX_ register OP *o)
            }
            if (badthing)
                Perl_croak(aTHX_
-         "Can't use bareword (\"%s\") as %s ref while \"strict refs\" in use",
-                     name, badthing);
+         "Can't use bareword (\"%"SVf"\") as %s ref while \"strict refs\" in use",
+                     kidsv, badthing);
        }
        /*
         * This is a little tricky.  We only want to add the symbol if we
@@ -4897,7 +5240,7 @@ Perl_ck_rvconst(pTHX_ register OP *o)
         */
        iscv = (o->op_type == OP_RV2CV) * 2;
        do {
-           gv = gv_fetchpv(name,
+           gv = gv_fetchsv(kidsv,
                iscv | !(kid->op_private & OPpCONST_ENTERED),
                iscv
                    ? SVt_PVCV
@@ -4931,7 +5274,8 @@ Perl_ck_rvconst(pTHX_ register OP *o)
 OP *
 Perl_ck_ftst(pTHX_ OP *o)
 {
-    I32 type = o->op_type;
+    dVAR;
+    const I32 type = o->op_type;
 
     if (o->op_flags & OPf_REF) {
        /* nothing */
@@ -4940,18 +5284,25 @@ Perl_ck_ftst(pTHX_ OP *o)
        SVOP *kid = (SVOP*)cUNOPo->op_first;
 
        if (kid->op_type == OP_CONST && (kid->op_private & OPpCONST_BARE)) {
-           STRLEN n_a;
            OP *newop = newGVOP(type, OPf_REF,
-               gv_fetchpv(SvPVx(kid->op_sv, n_a), TRUE, SVt_PVIO));
+               gv_fetchsv(kid->op_sv, TRUE, SVt_PVIO));
            op_free(o);
            o = newop;
+           return o;
        }
+       else {
+         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)
+           o->op_private |= OPpFT_STACKED;
     }
     else {
        op_free(o);
        if (type == OP_FTTTY)
-           o =  newGVOP(type, OPf_REF, gv_fetchpv("main::STDIN", TRUE,
-                               SVt_PVIO));
+           o = newGVOP(type, OPf_REF, PL_stdingv);
        else
            o = newUNOP(type, 0, newDEFSVOP());
     }
@@ -4961,11 +5312,7 @@ Perl_ck_ftst(pTHX_ OP *o)
 OP *
 Perl_ck_fun(pTHX_ OP *o)
 {
-    register OP *kid;
-    OP **tokid;
-    OP *sibl;
-    I32 numargs = 0;
-    int type = o->op_type;
+    const int type = o->op_type;
     register I32 oa = PL_opargs[type] >> OASHIFT;
 
     if (o->op_flags & OPf_STACKED) {
@@ -4976,9 +5323,11 @@ Perl_ck_fun(pTHX_ OP *o)
     }
 
     if (o->op_flags & OPf_KIDS) {
-       STRLEN n_a;
-       tokid = &cLISTOPo->op_first;
-       kid = cLISTOPo->op_first;
+        OP **tokid = &cLISTOPo->op_first;
+        register OP *kid = cLISTOPo->op_first;
+        OP *sibl;
+        I32 numargs = 0;
+
        if (kid->op_type == OP_PUSHMARK ||
            (kid->op_type == OP_NULL && kid->op_targ == OP_PUSHMARK))
        {
@@ -5019,13 +5368,12 @@ Perl_ck_fun(pTHX_ OP *o)
                if (kid->op_type == OP_CONST &&
                    (kid->op_private & OPpCONST_BARE))
                {
-                   char *name = SvPVx(((SVOP*)kid)->op_sv, n_a);
                    OP *newop = newAVREF(newGVOP(OP_GV, 0,
-                       gv_fetchpv(name, TRUE, SVt_PVAV) ));
+                       gv_fetchsv(((SVOP*)kid)->op_sv, TRUE, SVt_PVAV) ));
                    if (ckWARN2(WARN_DEPRECATED, WARN_SYNTAX))
                        Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
-                           "Array @%s missing the @ in argument %"IVdf" of %s()",
-                           name, (IV)numargs, PL_op_desc[type]);
+                           "Array @%"SVf" missing the @ in argument %"IVdf" of %s()",
+                           ((SVOP*)kid)->op_sv, (IV)numargs, PL_op_desc[type]);
                    op_free(kid);
                    kid = newop;
                    kid->op_sibling = sibl;
@@ -5039,13 +5387,12 @@ Perl_ck_fun(pTHX_ OP *o)
                if (kid->op_type == OP_CONST &&
                    (kid->op_private & OPpCONST_BARE))
                {
-                   char *name = SvPVx(((SVOP*)kid)->op_sv, n_a);
                    OP *newop = newHVREF(newGVOP(OP_GV, 0,
-                       gv_fetchpv(name, TRUE, SVt_PVHV) ));
+                       gv_fetchsv(((SVOP*)kid)->op_sv, TRUE, SVt_PVHV) ));
                    if (ckWARN2(WARN_DEPRECATED, WARN_SYNTAX))
                        Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
-                           "Hash %%%s missing the %% in argument %"IVdf" of %s()",
-                           name, (IV)numargs, PL_op_desc[type]);
+                           "Hash %%%"SVf" missing the %% in argument %"IVdf" of %s()",
+                           ((SVOP*)kid)->op_sv, (IV)numargs, PL_op_desc[type]);
                    op_free(kid);
                    kid = newop;
                    kid->op_sibling = sibl;
@@ -5072,8 +5419,7 @@ Perl_ck_fun(pTHX_ OP *o)
                        (kid->op_private & OPpCONST_BARE))
                    {
                        OP *newop = newGVOP(OP_GV, 0,
-                           gv_fetchpv(SvPVx(((SVOP*)kid)->op_sv, n_a), TRUE,
-                                       SVt_PVIO) );
+                           gv_fetchsv(((SVOP*)kid)->op_sv, TRUE, SVt_PVIO) );
                        if (!(o->op_private & 1) && /* if not unop */
                            kid == cLISTOPo->op_last)
                            cLISTOPo->op_last = newop;
@@ -5091,7 +5437,7 @@ Perl_ck_fun(pTHX_ OP *o)
 
                        /* is this op a FH constructor? */
                        if (is_handle_constructor(o,numargs)) {
-                           char *name = Nullch;
+                            const char *name = Nullch;
                            STRLEN len = 0;
 
                            flags = 0;
@@ -5101,10 +5447,6 @@ Perl_ck_fun(pTHX_ OP *o)
                             */
                            priv = OPpDEREF;
                            if (kid->op_type == OP_PADSV) {
-                               /*XXX DAPM 2002.08.25 tmp assert test */
-                               /*XXX*/ assert(av_fetch(PL_comppad_name, (kid->op_targ), FALSE));
-                               /*XXX*/ assert(*av_fetch(PL_comppad_name, (kid->op_targ), FALSE));
-
                                name = PAD_COMPNAME_PV(kid->op_targ);
                                /* SvCUR of a pad namesv can't be trusted
                                 * (see PL_generation), so calc its length
@@ -5123,15 +5465,56 @@ Perl_ck_fun(pTHX_ OP *o)
                            else if (kid->op_type == OP_AELEM
                                     || kid->op_type == OP_HELEM)
                            {
-                               name = "__ANONIO__";
-                               len = 10;
-                               mod(kid,type);
+                                OP *op;
+
+                                name = 0;
+                                if ((op = ((BINOP*)kid)->op_first)) {
+                                     SV *tmpstr = Nullsv;
+                                     const char *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)) {
+                                          /* packagevar $a[] or $h{} */
+                                          GV *gv = cGVOPx_gv(op);
+                                          if (gv)
+                                               tmpstr =
+                                                    Perl_newSVpvf(aTHX_
+                                                                  "%s%c...%c",
+                                                                  GvNAME(gv),
+                                                                  a[0], a[1]);
+                                     }
+                                     else if (op->op_type == OP_PADAV
+                                              || op->op_type == OP_PADHV) {
+                                          /* lexicalvar $a[] or $h{} */
+                                          const char *padname =
+                                               PAD_COMPNAME_PV(op->op_targ);
+                                          if (padname)
+                                               tmpstr =
+                                                    Perl_newSVpvf(aTHX_
+                                                                  "%s%c...%c",
+                                                                  padname + 1,
+                                                                  a[0], a[1]);
+                                          
+                                     }
+                                     if (tmpstr) {
+                                          name = SvPV_const(tmpstr, len);
+                                          sv_2mortal(tmpstr);
+                                     }
+                                }
+                                if (!name) {
+                                     name = "__ANONIO__";
+                                     len = 10;
+                                }
+                                mod(kid, type);
                            }
                            if (name) {
                                SV *namesv;
                                targ = pad_alloc(OP_RV2GV, SVs_PADTMP);
                                namesv = PAD_SVl(targ);
-                               (void)SvUPGRADE(namesv, SVt_PV);
+                               SvUPGRADE(namesv, SVt_PV);
                                if (*name != '$')
                                    sv_setpvn(namesv, "$", 1);
                                sv_catpvn(namesv, name, len);
@@ -5177,6 +5560,7 @@ Perl_ck_fun(pTHX_ OP *o)
 OP *
 Perl_ck_glob(pTHX_ OP *o)
 {
+    dVAR;
     GV *gv;
 
     o = ck_fun(o);
@@ -5191,7 +5575,7 @@ Perl_ck_glob(pTHX_ OP *o)
 
 #if !defined(PERL_EXTERNAL_GLOB)
     /* XXX this can be tightened up and made more failsafe. */
-    if (!gv) {
+    if (!(gv && GvCVu(gv) && GvIMPORTED_CV(gv))) {
        GV *glob_gv;
        ENTER;
        Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT,
@@ -5199,7 +5583,7 @@ Perl_ck_glob(pTHX_ OP *o)
        gv = gv_fetchpv("CORE::GLOBAL::glob", FALSE, SVt_PVCV);
        glob_gv = gv_fetchpv("File::Glob::csh_glob", FALSE, SVt_PVCV);
        GvCV(gv) = GvCV(glob_gv);
-       SvREFCNT_inc((SV*)GvCV(gv));
+       (void)SvREFCNT_inc((SV*)GvCV(gv));
        GvIMPORTED_CV_on(gv);
        LEAVE;
     }
@@ -5212,6 +5596,7 @@ Perl_ck_glob(pTHX_ OP *o)
        o->op_ppaddr = PL_ppaddr[OP_LIST];
        cLISTOPo->op_first->op_type = OP_PUSHMARK;
        cLISTOPo->op_first->op_ppaddr = PL_ppaddr[OP_PUSHMARK];
+       cLISTOPo->op_first->op_targ = 0;
        o = newUNOP(OP_ENTERSUB, OPf_STACKED,
                    append_elem(OP_LIST, o,
                                scalar(newUNOP(OP_RV2CV, 0,
@@ -5230,9 +5615,11 @@ Perl_ck_glob(pTHX_ OP *o)
 OP *
 Perl_ck_grep(pTHX_ OP *o)
 {
+    dVAR;
     LOGOP *gwop;
     OP *kid;
-    OPCODE type = o->op_type == OP_GREPSTART ? OP_GREPWHILE : OP_MAPWHILE;
+    const OPCODE type = o->op_type == OP_GREPSTART ? OP_GREPWHILE : OP_MAPWHILE;
+    I32 offset;
 
     o->op_ppaddr = PL_ppaddr[OP_GREPSTART];
     NewOp(1101, gwop, 1, LOGOP);
@@ -5241,7 +5628,9 @@ Perl_ck_grep(pTHX_ OP *o)
        OP* k;
        o = ck_sort(o);
         kid = cLISTOPo->op_first->op_sibling;
-       for (k = cLISTOPo->op_first->op_sibling->op_next; k; k = k->op_next) {
+       if (!cUNOPx(kid)->op_next)
+           Perl_croak(aTHX_ "panic: ck_grep");
+       for (k = cUNOPx(kid)->op_first; k; k = k->op_next) {
            kid = k;
        }
        kid->op_next = (OP*)gwop;
@@ -5264,10 +5653,17 @@ Perl_ck_grep(pTHX_ OP *o)
     gwop->op_ppaddr = PL_ppaddr[type];
     gwop->op_first = listkids(o);
     gwop->op_flags |= OPf_KIDS;
-    gwop->op_private = 1;
     gwop->op_other = LINKLIST(kid);
-    gwop->op_targ = pad_alloc(type, SVs_PADTMP);
     kid->op_next = (OP*)gwop;
+    offset = pad_findmy("$_");
+    if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS(offset) & SVpad_OUR) {
+       o->op_private = gwop->op_private = 0;
+       gwop->op_targ = pad_alloc(type, SVs_PADTMP);
+    }
+    else {
+       o->op_private = gwop->op_private = OPpGREP_LEX;
+       gwop->op_targ = o->op_targ = offset;
+    }
 
     kid = cLISTOPo->op_first->op_sibling;
     if (!kid || !kid->op_sibling)
@@ -5301,7 +5697,7 @@ Perl_ck_lengthconst(pTHX_ OP *o)
 OP *
 Perl_ck_lfun(pTHX_ OP *o)
 {
-    OPCODE type = o->op_type;
+    const OPCODE type = o->op_type;
     return modkids(ck_fun(o), type);
 }
 
@@ -5346,7 +5742,7 @@ Perl_ck_defined(pTHX_ OP *o)              /* 19990527 MJD */
 OP *
 Perl_ck_rfun(pTHX_ OP *o)
 {
-    OPCODE type = o->op_type;
+    const OPCODE type = o->op_type;
     return refkids(ck_fun(o), type);
 }
 
@@ -5407,13 +5803,34 @@ Perl_ck_sassign(pTHX_ OP *o)
            return kid;
        }
     }
+    /* optimise C<my $x = undef> to C<my $x> */
+    if (kid->op_type == OP_UNDEF) {
+       OP *kkid = kid->op_sibling;
+       if (kkid && kkid->op_type == OP_PADSV
+               && (kkid->op_private & OPpLVAL_INTRO))
+       {
+           cLISTOPo->op_first = NULL;
+           kid->op_sibling = NULL;
+           op_free(o);
+           op_free(kid);
+           return kkid;
+       }
+    }
     return o;
 }
 
 OP *
 Perl_ck_match(pTHX_ OP *o)
 {
-    o->op_private |= OPpRUNTIME;
+    if (o->op_type != OP_QR) {
+       const I32 offset = pad_findmy("$_");
+       if (offset != NOT_IN_PAD && !(PAD_COMPNAME_FLAGS(offset) & SVpad_OUR)) {
+           o->op_targ = offset;
+           o->op_private |= OPpTARGET_MY;
+       }
+    }
+    if (o->op_type == OP_MATCH || o->op_type == OP_QR)
+       o->op_private |= OPpRUNTIME;
     return o;
 }
 
@@ -5423,10 +5840,10 @@ Perl_ck_method(pTHX_ OP *o)
     OP *kid = cUNOPo->op_first;
     if (kid->op_type == OP_CONST) {
        SV* sv = kSVOP->op_sv;
-       if (!(strchr(SvPVX(sv), ':') || strchr(SvPVX(sv), '\''))) {
+       if (!(strchr(SvPVX_const(sv), ':') || strchr(SvPVX_const(sv), '\''))) {
            OP *cmop;
            if (!SvREADONLY(sv) || !SvFAKE(sv)) {
-               sv = newSVpvn_share(SvPVX(sv), SvCUR(sv), 0);
+               sv = newSVpvn_share(SvPVX_const(sv), SvCUR(sv), 0);
            }
            else {
                kSVOP->op_sv = Nullsv;
@@ -5472,6 +5889,26 @@ Perl_ck_open(pTHX_ OP *o)
     }
     if (o->op_type == OP_BACKTICK)
        return o;
+    {
+        /* In case of three-arg dup open remove strictness
+         * from the last arg if it is a bareword. */
+        OP *first = cLISTOPx(o)->op_first; /* The pushmark. */
+        OP *last  = cLISTOPx(o)->op_last;  /* The bareword. */
+        OP *oa;
+        const char *mode;
+
+        if ((last->op_type == OP_CONST) &&             /* The bareword. */
+            (last->op_private & OPpCONST_BARE) &&
+            (last->op_private & OPpCONST_STRICT) &&
+            (oa = first->op_sibling) &&                /* The fh. */
+            (oa = oa->op_sibling) &&                   /* The mode. */
+            (oa->op_type == OP_CONST) &&
+            SvPOK(((SVOP*)oa)->op_sv) &&
+            (mode = SvPVX_const(((SVOP*)oa)->op_sv)) &&
+            mode[0] == '>' && mode[1] == '&' &&        /* A dup open. */
+            (last == oa->op_sibling))                  /* The bareword. */
+             last->op_private &= ~OPpCONST_STRICT;
+    }
     return ck_fun(o);
 }
 
@@ -5490,34 +5927,46 @@ Perl_ck_repeat(pTHX_ OP *o)
 OP *
 Perl_ck_require(pTHX_ OP *o)
 {
-    GV* gv;
+    GV* gv = Nullgv;
 
     if (o->op_flags & OPf_KIDS) {      /* Shall we supply missing .pm? */
        SVOP *kid = (SVOP*)cUNOPo->op_first;
 
        if (kid->op_type == OP_CONST && (kid->op_private & OPpCONST_BARE)) {
+           SV *sv = kid->op_sv;
+           U32 was_readonly = SvREADONLY(sv);
            char *s;
-           for (s = SvPVX(kid->op_sv); *s; s++) {
+
+           if (was_readonly) {
+               if (SvFAKE(sv)) {
+                   sv_force_normal_flags(sv, 0);
+                   assert(!SvREADONLY(sv));
+                   was_readonly = 0;
+               } else {
+                   SvREADONLY_off(sv);
+               }
+           }   
+
+           for (s = SvPVX(sv); *s; s++) {
                if (*s == ':' && s[1] == ':') {
                    *s = '/';
                    Move(s+2, s+1, strlen(s+2)+1, char);
-                   --SvCUR(kid->op_sv);
+                   SvCUR_set(sv, SvCUR(sv) - 1);
                }
            }
-           if (SvREADONLY(kid->op_sv)) {
-               SvREADONLY_off(kid->op_sv);
-               sv_catpvn(kid->op_sv, ".pm", 3);
-               SvREADONLY_on(kid->op_sv);
-           }
-           else
-               sv_catpvn(kid->op_sv, ".pm", 3);
+           sv_catpvn(sv, ".pm", 3);
+           SvFLAGS(sv) |= was_readonly;
        }
     }
 
-    /* handle override, if any */
-    gv = gv_fetchpv("require", FALSE, SVt_PVCV);
-    if (!(gv && GvCVu(gv) && GvIMPORTED_CV(gv)))
-       gv = gv_fetchpv("CORE::GLOBAL::require", FALSE, SVt_PVCV);
+    if (!(o->op_flags & OPf_SPECIAL)) { /* Wasn't written as CORE::require */
+       /* handle override, if any */
+       gv = gv_fetchpv("require", FALSE, SVt_PVCV);
+       if (!(gv && GvCVu(gv) && GvIMPORTED_CV(gv))) {
+           GV **gvp = (GV**)hv_fetch(PL_globalstash, "require", 7, FALSE);
+           if (gvp) gv = *gvp; else gv = Nullgv;
+       }
+    }
 
     if (gv && GvCVu(gv) && GvIMPORTED_CV(gv)) {
        OP *kid = cUNOPo->op_first;
@@ -5536,8 +5985,8 @@ Perl_ck_require(pTHX_ OP *o)
 OP *
 Perl_ck_return(pTHX_ OP *o)
 {
-    OP *kid;
     if (CvLVALUE(PL_compcv)) {
+        OP *kid;
        for (kid = cLISTOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
            mod(kid, OP_LEAVESUBLV);
     }
@@ -5557,6 +6006,7 @@ Perl_ck_retarget(pTHX_ OP *o)
 OP *
 Perl_ck_select(pTHX_ OP *o)
 {
+    dVAR;
     OP* kid;
     if (o->op_flags & OPf_KIDS) {
        kid = cLISTOPo->op_first->op_sibling;   /* get past pushmark */
@@ -5577,15 +6027,14 @@ Perl_ck_select(pTHX_ OP *o)
 OP *
 Perl_ck_shift(pTHX_ OP *o)
 {
-    I32 type = o->op_type;
+    const I32 type = o->op_type;
 
     if (!(o->op_flags & OPf_KIDS)) {
        OP *argop;
 
        op_free(o);
        argop = newUNOP(OP_RV2AV, 0,
-           scalar(newGVOP(OP_GV, 0, !CvUNIQUE(PL_compcv) ?
-                          PL_defgv : gv_fetchpv("ARGV", TRUE, SVt_PVAV))));
+           scalar(newGVOP(OP_GV, 0, CvUNIQUE(PL_compcv) ? PL_argvgv : PL_defgv)));
        return newUNOP(type, 0, scalar(argop));
     }
     return scalar(modkids(ck_fun(o), type));
@@ -5659,8 +6108,9 @@ S_simplify_sort(pTHX_ OP *o)
 {
     register OP *kid = cLISTOPo->op_first->op_sibling; /* get past pushmark */
     OP *k;
-    int reversed;
+    int descending;
     GV *gv;
+    const char *gvname;
     if (!(o->op_flags & OPf_STACKED))
        return;
     GvMULTI_on(gv_fetchpv("a", TRUE, SVt_PV));
@@ -5687,12 +6137,14 @@ S_simplify_sort(pTHX_ OP *o)
     gv = kGVOP_gv;
     if (GvSTASH(gv) != PL_curstash)
        return;
-    if (strEQ(GvNAME(gv), "a"))
-       reversed = 0;
-    else if (strEQ(GvNAME(gv), "b"))
-       reversed = 1;
+    gvname = GvNAME(gv);
+    if (*gvname == 'a' && gvname[1] == '\0')
+       descending = 0;
+    else if (*gvname == 'b' && gvname[1] == '\0')
+       descending = 1;
     else
        return;
+
     kid = k;                                           /* back to cmp */
     if (kBINOP->op_last->op_type != OP_RV2SV)
        return;
@@ -5701,14 +6153,16 @@ S_simplify_sort(pTHX_ OP *o)
        return;
     kid = kUNOP->op_first;                             /* get past rv2sv */
     gv = kGVOP_gv;
-    if (GvSTASH(gv) != PL_curstash
-       || ( reversed
-           ? strNE(GvNAME(gv), "a")
-           : strNE(GvNAME(gv), "b")))
+    if (GvSTASH(gv) != PL_curstash)
+       return;
+    gvname = GvNAME(gv);
+    if ( descending
+        ? !(*gvname == 'a' && gvname[1] == '\0')
+        : !(*gvname == 'b' && gvname[1] == '\0'))
        return;
     o->op_flags &= ~(OPf_STACKED | OPf_SPECIAL);
-    if (reversed)
-       o->op_private |= OPpSORT_REVERSE;
+    if (descending)
+       o->op_private |= OPpSORT_DESCEND;
     if (k->op_type == OP_NCMP)
        o->op_private |= OPpSORT_NUMERIC;
     if (k->op_type == OP_I_NCMP)
@@ -5721,6 +6175,7 @@ S_simplify_sort(pTHX_ OP *o)
 OP *
 Perl_ck_split(pTHX_ OP *o)
 {
+    dVAR;
     register OP *kid;
 
     if (o->op_flags & OPf_STACKED)
@@ -5740,7 +6195,7 @@ Perl_ck_split(pTHX_ OP *o)
     if (kid->op_type != OP_MATCH || kid->op_flags & OPf_STACKED) {
        OP *sibl = kid->op_sibling;
        kid->op_sibling = 0;
-       kid = pmruntime( newPMOP(OP_MATCH, OPf_SPECIAL), kid, Nullop);
+       kid = pmruntime( newPMOP(OP_MATCH, OPf_SPECIAL), kid, 0);
        if (cLISTOPo->op_first == cLISTOPo->op_last)
            cLISTOPo->op_last = kid;
        cLISTOPo->op_first = kid;
@@ -5750,7 +6205,7 @@ Perl_ck_split(pTHX_ OP *o)
     kid->op_type = OP_PUSHRE;
     kid->op_ppaddr = PL_ppaddr[OP_PUSHRE];
     scalar(kid);
-    if (ckWARN(WARN_REGEXP) && ((PMOP *)kid)->op_pmflags & PMf_GLOBAL) {
+    if (((PMOP *)kid)->op_pmflags & PMf_GLOBAL && ckWARN(WARN_REGEXP)) {
       Perl_warner(aTHX_ packWARN(WARN_REGEXP),
                   "Use of /g modifier is meaningless in split");
     }
@@ -5776,12 +6231,11 @@ Perl_ck_split(pTHX_ OP *o)
 OP *
 Perl_ck_join(pTHX_ OP *o)
 {
-    if (ckWARN(WARN_SYNTAX)) {
-       OP *kid = cLISTOPo->op_first->op_sibling;
-       if (kid && kid->op_type == OP_MATCH) {
-           char *pmstr = "STRING";
-           if (PM_GETRE(kPMOP))
-               pmstr = PM_GETRE(kPMOP)->precomp;
+    const OP *kid = cLISTOPo->op_first->op_sibling;
+    if (kid && kid->op_type == OP_MATCH) {
+       if (ckWARN(WARN_SYNTAX)) {
+            const REGEXP *re = PM_GETRE(kPMOP);
+           const char *pmstr = re ? re->precomp : "STRING";
            Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
                        "/%s/ should probably be written as \"%s\"",
                        pmstr, pmstr);
@@ -5804,7 +6258,7 @@ Perl_ck_subr(pTHX_ OP *o)
     I32 arg = 0;
     I32 contextclass = 0;
     char *e = 0;
-    STRLEN n_a;
+    bool delete_op = 0;
 
     o->op_private |= OPpENTERSUB_HASTARG;
     for (cvop = o2; cvop->op_sibling; cvop = cvop->op_sibling) ;
@@ -5818,9 +6272,24 @@ Perl_ck_subr(pTHX_ OP *o)
            cv = GvCVu(gv);
            if (!cv)
                tmpop->op_private |= OPpEARLY_CV;
-           else if (SvPOK(cv)) {
-               namegv = CvANON(cv) ? gv : CvGV(cv);
-               proto = SvPV((SV*)cv, n_a);
+           else {
+               if (SvPOK(cv)) {
+                   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");
+                       }
+                   }
+               }
            }
        }
     }
@@ -5888,9 +6357,7 @@ Perl_ck_subr(pTHX_ OP *o)
                                OP *sibling = o2->op_sibling;
                                SV *n = newSVpvn("",0);
                                op_free(o2);
-                               gv_fullname3(n, gv, "");
-                               if (SvCUR(n)>6 && strnEQ(SvPVX(n),"main::",6))
-                                   sv_chop(n, SvPVX(n)+6);
+                               gv_fullname4(n, gv, "", FALSE);
                                o2 = newSVOP(OP_CONST, 0, n);
                                prev->op_sibling = o2;
                                o2->op_sibling = sibling;
@@ -5920,8 +6387,8 @@ Perl_ck_subr(pTHX_ OP *o)
                     break;
                case ']':
                     if (contextclass) {
-                        char *p = proto;
-                        char s = *p;
+                        char *p = proto;
+                        const char s = *p;
                         contextclass = 0;
                         *p = '\0';
                         while (*--p != '[');
@@ -6004,6 +6471,10 @@ Perl_ck_subr(pTHX_ OP *o)
     if (proto && !optional &&
          (*proto && *proto != '@' && *proto != '%' && *proto != ';'))
        return too_few_arguments(o, gv_ename(namegv));
+    if(delete_op) {
+       op_free(o);
+       o=newSVOP(OP_CONST, 0, newSViv(0));
+    }
     return o;
 }
 
@@ -6033,6 +6504,18 @@ Perl_ck_trunc(pTHX_ OP *o)
 }
 
 OP *
+Perl_ck_unpack(pTHX_ OP *o)
+{
+    OP *kid = cLISTOPo->op_first;
+    if (kid->op_sibling) {
+       kid = kid->op_sibling;
+       if (!kid->op_sibling)
+           kid->op_sibling = newDEFSVOP();
+    }
+    return ck_fun(o);
+}
+
+OP *
 Perl_ck_substr(pTHX_ OP *o)
 {
     o = ck_fun(o);
@@ -6048,32 +6531,31 @@ Perl_ck_substr(pTHX_ OP *o)
     return o;
 }
 
-/* A peephole optimizer.  We visit the ops in the order they're to execute. */
+/* A peephole optimizer.  We visit the ops in the order they're to execute.
+ * See the comments at the top of this file for more details about when
+ * peep() is called */
 
 void
 Perl_peep(pTHX_ register OP *o)
 {
+    dVAR;
     register OP* oldop = 0;
 
-    if (!o || o->op_seq)
+    if (!o || o->op_opt)
        return;
     ENTER;
     SAVEOP();
     SAVEVPTR(PL_curcop);
     for (; o; o = o->op_next) {
-       if (o->op_seq)
+       if (o->op_opt)
            break;
-        /* The special value -1 is used by the B::C compiler backend to indicate
-         * that an op is statically defined and should not be freed */
-       if (!PL_op_seqmax || PL_op_seqmax == (U16)-1)
-           PL_op_seqmax = 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_seq = PL_op_seqmax++;
+           o->op_opt = 1;
            break;
 
        case OP_CONST:
@@ -6085,8 +6567,8 @@ Perl_peep(pTHX_ register OP *o)
             * Despite being a "constant", the SV is written to,
             * for reference counts, sv_upgrade() etc. */
            if (cSVOP->op_sv) {
-               PADOFFSET ix = pad_alloc(OP_CONST, SVs_PADTMP);
-               if (SvPADTMP(cSVOPo->op_sv)) {
+               const PADOFFSET ix = pad_alloc(OP_CONST, SVs_PADTMP);
+               if (o->op_type == OP_CONST && SvPADTMP(cSVOPo->op_sv)) {
                    /* If op_sv is already a PADTMP then it is being used by
                     * some pad, so make a copy. */
                    sv_setsv(PAD_SVl(ix),cSVOPo->op_sv);
@@ -6104,7 +6586,7 @@ Perl_peep(pTHX_ register OP *o)
                o->op_targ = ix;
            }
 #endif
-           o->op_seq = PL_op_seqmax++;
+           o->op_opt = 1;
            break;
 
        case OP_CONCAT:
@@ -6122,11 +6604,11 @@ Perl_peep(pTHX_ register OP *o)
                op_null(o->op_next);
            }
          ignore_optimization:
-           o->op_seq = PL_op_seqmax++;
+           o->op_opt = 1;
            break;
        case OP_STUB:
            if ((o->op_flags & OPf_WANT) != OPf_WANT_LIST) {
-               o->op_seq = PL_op_seqmax++;
+               o->op_opt = 1;
                break; /* Scalar stub must produce undef.  List stub is noop */
            }
            goto nothin;
@@ -6141,6 +6623,7 @@ Perl_peep(pTHX_ register OP *o)
               to peep() from mistakenly concluding that optimisation
               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;
@@ -6154,25 +6637,17 @@ Perl_peep(pTHX_ register OP *o)
                oldop->op_next = o->op_next;
                continue;
            }
-           o->op_seq = PL_op_seqmax++;
+           o->op_opt = 1;
            break;
 
+       case OP_PADAV:
        case OP_GV:
-           if (o->op_next->op_type == OP_RV2SV) {
-               if (!(o->op_next->op_private & OPpDEREF)) {
-                   op_null(o->op_next);
-                   o->op_private |= o->op_next->op_private & (OPpLVAL_INTRO
-                                                              | OPpOUR_INTRO);
-                   o->op_next = o->op_next->op_next;
-                   o->op_type = OP_GVSV;
-                   o->op_ppaddr = PL_ppaddr[OP_GVSV];
-               }
-           }
-           else if (o->op_next->op_type == OP_RV2AV) {
-               OP* pop = o->op_next->op_next;
+           if (o->op_type == OP_PADAV || o->op_next->op_type == OP_RV2AV) {
+               OP* pop = (o->op_type == OP_PADAV) ?
+                           o->op_next : o->op_next->op_next;
                IV i;
                if (pop && pop->op_type == OP_CONST &&
-                   (PL_op = pop->op_next) &&
+                   ((PL_op = pop->op_next)) &&
                    pop->op_next->op_type == OP_AELEM &&
                    !(pop->op_next->op_private &
                      (OPpLVAL_INTRO|OPpLVAL_DEFER|OPpDEREF|OPpMAYBE_LVSUB)) &&
@@ -6181,21 +6656,41 @@ Perl_peep(pTHX_ register OP *o)
                    i >= 0)
                {
                    GV *gv;
-                   op_null(o->op_next);
+                   if (cSVOPx(pop)->op_private & OPpCONST_STRICT)
+                       no_bareword_allowed(pop);
+                   if (o->op_type == OP_GV)
+                       op_null(o->op_next);
                    op_null(pop->op_next);
                    op_null(pop);
                    o->op_flags |= pop->op_next->op_flags & OPf_MOD;
                    o->op_next = pop->op_next->op_next;
-                   o->op_type = OP_AELEMFAST;
                    o->op_ppaddr = PL_ppaddr[OP_AELEMFAST];
                    o->op_private = (U8)i;
-                   gv = cGVOPo_gv;
-                   GvAVn(gv);
+                   if (o->op_type == OP_GV) {
+                       gv = cGVOPo_gv;
+                       GvAVn(gv);
+                   }
+                   else
+                       o->op_flags |= OPf_SPECIAL;
+                   o->op_type = OP_AELEMFAST;
+               }
+               o->op_opt = 1;
+               break;
+           }
+
+           if (o->op_next->op_type == OP_RV2SV) {
+               if (!(o->op_next->op_private & OPpDEREF)) {
+                   op_null(o->op_next);
+                   o->op_private |= o->op_next->op_private & (OPpLVAL_INTRO
+                                                              | OPpOUR_INTRO);
+                   o->op_next = o->op_next->op_next;
+                   o->op_type = OP_GVSV;
+                   o->op_ppaddr = PL_ppaddr[OP_GVSV];
                }
            }
            else if ((o->op_private & OPpEARLY_CV) && ckWARN(WARN_PROTOTYPE)) {
                GV *gv = cGVOPo_gv;
-               if (SvTYPE(gv) == SVt_PVGV && GvCV(gv) && SvPVX(GvCV(gv))) {
+               if (SvTYPE(gv) == SVt_PVGV && GvCV(gv) && SvPVX_const(GvCV(gv))) {
                    /* XXX could check prototype here instead of just carping */
                    SV *sv = sv_newmortal();
                    gv_efullname3(sv, gv, Nullch);
@@ -6216,7 +6711,7 @@ Perl_peep(pTHX_ register OP *o)
                op_null(o->op_next);
            }
 
-           o->op_seq = PL_op_seqmax++;
+           o->op_opt = 1;
            break;
 
        case OP_MAPWHILE:
@@ -6229,7 +6724,7 @@ Perl_peep(pTHX_ register OP *o)
        case OP_DORASSIGN:
        case OP_COND_EXPR:
        case OP_RANGE:
-           o->op_seq = PL_op_seqmax++;
+           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 */
@@ -6237,7 +6732,7 @@ Perl_peep(pTHX_ register OP *o)
 
        case OP_ENTERLOOP:
        case OP_ENTERITER:
-           o->op_seq = PL_op_seqmax++;
+           o->op_opt = 1;
            while (cLOOP->op_redoop->op_type == OP_NULL)
                cLOOP->op_redoop = cLOOP->op_redoop->op_next;
            peep(cLOOP->op_redoop);
@@ -6252,7 +6747,7 @@ Perl_peep(pTHX_ register OP *o)
        case OP_QR:
        case OP_MATCH:
        case OP_SUBST:
-           o->op_seq = PL_op_seqmax++;
+           o->op_opt = 1;
            while (cPMOP->op_pmreplstart &&
                   cPMOP->op_pmreplstart->op_type == OP_NULL)
                cPMOP->op_pmreplstart = cPMOP->op_pmreplstart->op_next;
@@ -6260,14 +6755,15 @@ Perl_peep(pTHX_ register OP *o)
            break;
 
        case OP_EXEC:
-           o->op_seq = PL_op_seqmax++;
-           if (ckWARN(WARN_SYNTAX) && o->op_next
-               && o->op_next->op_type == OP_NEXTSTATE) {
+           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) {
-                   line_t oldline = CopLINE(PL_curcop);
+                   const line_t oldline = CopLINE(PL_curcop);
 
                    CopLINE_set(PL_curcop, CopLINE((COP*)o->op_next));
                    Perl_warner(aTHX_ packWARN(WARN_EXEC),
@@ -6280,12 +6776,14 @@ Perl_peep(pTHX_ register OP *o)
            break;
 
        case OP_HELEM: {
+           UNOP *rop;
             SV *lexname;
+           GV **fields;
            SV **svp, *sv;
-           char *key = NULL;
+           const char *key = NULL;
            STRLEN keylen;
 
-           o->op_seq = PL_op_seqmax++;
+           o->op_opt = 1;
 
            if (((BINOP*)o)->op_last->op_type != OP_CONST)
                break;
@@ -6293,18 +6791,306 @@ Perl_peep(pTHX_ register OP *o)
            /* Make the CONST have a shared SV */
            svp = cSVOPx_svp(((BINOP*)o)->op_last);
            if ((!SvFAKE(sv = *svp) || !SvREADONLY(sv)) && !IS_PADCONST(sv)) {
-               key = SvPV(sv, keylen);
+               key = SvPV_const(sv, keylen);
                lexname = newSVpvn_share(key,
                                         SvUTF8(sv) ? -(I32)keylen : keylen,
                                         0);
                SvREFCNT_dec(sv);
                *svp = lexname;
            }
+
+           if ((o->op_private & (OPpLVAL_INTRO)))
+               break;
+
+           rop = (UNOP*)((BINOP*)o)->op_first;
+           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))
+               break;
+           fields = (GV**)hv_fetch(SvSTASH(lexname), "FIELDS", 6, FALSE);
+           if (!fields || !GvHV(*fields))
+               break;
+           key = SvPV_const(*svp, keylen);
+           if (!hv_fetch(GvHV(*fields), key,
+                       SvUTF8(*svp) ? -(I32)keylen : keylen, FALSE))
+           {
+               Perl_croak(aTHX_ "No such class field \"%s\" " 
+                          "in variable %s of type %s", 
+                     key, SvPV_nolen_const(lexname), HvNAME_get(SvSTASH(lexname)));
+           }
+
             break;
         }
 
+       case OP_HSLICE: {
+           UNOP *rop;
+           SV *lexname;
+           GV **fields;
+           SV **svp;
+           const char *key;
+           STRLEN keylen;
+           SVOP *first_key_op, *key_op;
+
+           if ((o->op_private & (OPpLVAL_INTRO))
+               /* I bet there's always a pushmark... */
+               || ((LISTOP*)o)->op_first->op_sibling->op_type != OP_LIST)
+               /* hmmm, no optimization if list contains only one key. */
+               break;
+           rop = (UNOP*)((LISTOP*)o)->op_last;
+           if (rop->op_type != OP_RV2HV)
+               break;
+           if (rop->op_first->op_type == OP_PADSV)
+               /* @$hash{qw(keys here)} */
+               rop = (UNOP*)rop->op_first;
+           else {
+               /* @{$hash}{qw(keys here)} */
+               if (rop->op_first->op_type == OP_SCOPE 
+                   && cLISTOPx(rop->op_first)->op_last->op_type == OP_PADSV)
+               {
+                   rop = (UNOP*)cLISTOPx(rop->op_first)->op_last;
+               }
+               else
+                   break;
+           }
+                   
+           lexname = *av_fetch(PL_comppad_name, rop->op_targ, TRUE);
+           if (!(SvFLAGS(lexname) & SVpad_TYPED))
+               break;
+           fields = (GV**)hv_fetch(SvSTASH(lexname), "FIELDS", 6, FALSE);
+           if (!fields || !GvHV(*fields))
+               break;
+           /* Again guessing that the pushmark can be jumped over.... */
+           first_key_op = (SVOP*)((LISTOP*)((LISTOP*)o)->op_first->op_sibling)
+               ->op_first->op_sibling;
+           for (key_op = first_key_op; key_op;
+                key_op = (SVOP*)key_op->op_sibling) {
+               if (key_op->op_type != OP_CONST)
+                   continue;
+               svp = cSVOPx_svp(key_op);
+               key = SvPV_const(*svp, keylen);
+               if (!hv_fetch(GvHV(*fields), key, 
+                           SvUTF8(*svp) ? -(I32)keylen : keylen, FALSE))
+               {
+                   Perl_croak(aTHX_ "No such class field \"%s\" "
+                              "in variable %s of type %s",
+                         key, SvPV_nolen(lexname), HvNAME_get(SvSTASH(lexname)));
+               }
+           }
+           break;
+       }
+
+       case OP_SORT: {
+           /* will point to RV2AV or PADAV op on LHS/RHS of assign */
+           OP *oleft, *oright;
+           OP *o2;
+
+           /* check that RHS of sort is a single plain array */
+           oright = cUNOPo->op_first;
+           if (!oright || oright->op_type != OP_PUSHMARK)
+               break;
+
+           /* reverse sort ... can be optimised.  */
+           if (!cUNOPo->op_sibling) {
+               /* Nothing follows us on the list. */
+               OP *reverse = o->op_next;
+
+               if (reverse->op_type == OP_REVERSE &&
+                   (reverse->op_flags & OPf_WANT) == OPf_WANT_LIST) {
+                   OP *pushmark = cUNOPx(reverse)->op_first;
+                   if (pushmark && (pushmark->op_type == OP_PUSHMARK)
+                       && (cUNOPx(pushmark)->op_sibling == o)) {
+                       /* reverse -> pushmark -> sort */
+                       o->op_private |= OPpSORT_REVERSE;
+                       op_null(reverse);
+                       pushmark->op_next = oright->op_next;
+                       op_null(oright);
+                   }
+               }
+           }
+
+           /* make @a = sort @a act in-place */
+
+           o->op_opt = 1;
+
+           oright = cUNOPx(oright)->op_sibling;
+           if (!oright)
+               break;
+           if (oright->op_type == OP_NULL) { /* skip sort block/sub */
+               oright = cUNOPx(oright)->op_sibling;
+           }
+
+           if (!oright ||
+               (oright->op_type != OP_RV2AV && oright->op_type != OP_PADAV)
+               || oright->op_next != o
+               || (oright->op_private & OPpLVAL_INTRO)
+           )
+               break;
+
+           /* o2 follows the chain of op_nexts through the LHS of the
+            * assign (if any) to the aassign op itself */
+           o2 = o->op_next;
+           if (!o2 || o2->op_type != OP_NULL)
+               break;
+           o2 = o2->op_next;
+           if (!o2 || o2->op_type != OP_PUSHMARK)
+               break;
+           o2 = o2->op_next;
+           if (o2 && o2->op_type == OP_GV)
+               o2 = o2->op_next;
+           if (!o2
+               || (o2->op_type != OP_PADAV && o2->op_type != OP_RV2AV)
+               || (o2->op_private & OPpLVAL_INTRO)
+           )
+               break;
+           oleft = o2;
+           o2 = o2->op_next;
+           if (!o2 || o2->op_type != OP_NULL)
+               break;
+           o2 = o2->op_next;
+           if (!o2 || o2->op_type != OP_AASSIGN
+                   || (o2->op_flags & OPf_WANT) != OPf_WANT_VOID)
+               break;
+
+           /* check that the sort is the first arg on RHS of assign */
+
+           o2 = cUNOPx(o2)->op_first;
+           if (!o2 || o2->op_type != OP_NULL)
+               break;
+           o2 = cUNOPx(o2)->op_first;
+           if (!o2 || o2->op_type != OP_PUSHMARK)
+               break;
+           if (o2->op_sibling != o)
+               break;
+
+           /* check the array is the same on both sides */
+           if (oleft->op_type == OP_RV2AV) {
+               if (oright->op_type != OP_RV2AV
+                   || !cUNOPx(oright)->op_first
+                   || cUNOPx(oright)->op_first->op_type != OP_GV
+                   ||  cGVOPx_gv(cUNOPx(oleft)->op_first) !=
+                       cGVOPx_gv(cUNOPx(oright)->op_first)
+               )
+                   break;
+           }
+           else if (oright->op_type != OP_PADAV
+               || oright->op_targ != oleft->op_targ
+           )
+               break;
+
+           /* transfer MODishness etc from LHS arg to RHS arg */
+           oright->op_flags = oleft->op_flags;
+           o->op_private |= OPpSORT_INPLACE;
+
+           /* excise push->gv->rv2av->null->aassign */
+           o2 = o->op_next->op_next;
+           op_null(o2); /* PUSHMARK */
+           o2 = o2->op_next;
+           if (o2->op_type == OP_GV) {
+               op_null(o2); /* GV */
+               o2 = o2->op_next;
+           }
+           op_null(o2); /* RV2AV or PADAV */
+           o2 = o2->op_next->op_next;
+           op_null(o2); /* AASSIGN */
+
+           o->op_next = o2->op_next;
+
+           break;
+       }
+
+       case OP_REVERSE: {
+           OP *ourmark, *theirmark, *ourlast, *iter, *expushmark, *rv2av;
+           OP *gvop = NULL;
+           LISTOP *enter, *exlist;
+           o->op_opt = 1;
+
+           enter = (LISTOP *) o->op_next;
+           if (!enter)
+               break;
+           if (enter->op_type == OP_NULL) {
+               enter = (LISTOP *) enter->op_next;
+               if (!enter)
+                   break;
+           }
+           /* for $a (...) will have OP_GV then OP_RV2GV here.
+              for (...) just has an OP_GV.  */
+           if (enter->op_type == OP_GV) {
+               gvop = (OP *) enter;
+               enter = (LISTOP *) enter->op_next;
+               if (!enter)
+                   break;
+               if (enter->op_type == OP_RV2GV) {
+                 enter = (LISTOP *) enter->op_next;
+                 if (!enter)
+                   break;
+               }
+           }
+
+           if (enter->op_type != OP_ENTERITER)
+               break;
+
+           iter = enter->op_next;
+           if (!iter || iter->op_type != OP_ITER)
+               break;
+           
+           expushmark = enter->op_first;
+           if (!expushmark || expushmark->op_type != OP_NULL
+               || expushmark->op_targ != OP_PUSHMARK)
+               break;
+
+           exlist = (LISTOP *) expushmark->op_sibling;
+           if (!exlist || exlist->op_type != OP_NULL
+               || exlist->op_targ != OP_LIST)
+               break;
+
+           if (exlist->op_last != o) {
+               /* Mmm. Was expecting to point back to this op.  */
+               break;
+           }
+           theirmark = exlist->op_first;
+           if (!theirmark || theirmark->op_type != OP_PUSHMARK)
+               break;
+
+           if (theirmark->op_sibling != o) {
+               /* There's something between the mark and the reverse, eg
+                  for (1, reverse (...))
+                  so no go.  */
+               break;
+           }
+
+           ourmark = ((LISTOP *)o)->op_first;
+           if (!ourmark || ourmark->op_type != OP_PUSHMARK)
+               break;
+
+           ourlast = ((LISTOP *)o)->op_last;
+           if (!ourlast || ourlast->op_next != o)
+               break;
+
+           rv2av = ourmark->op_sibling;
+           if (rv2av && rv2av->op_type == OP_RV2AV && rv2av->op_sibling == 0
+               && rv2av->op_flags == (OPf_WANT_LIST | OPf_KIDS)
+               && enter->op_flags == (OPf_WANT_LIST | OPf_KIDS)) {
+               /* We're just reversing a single array.  */
+               rv2av->op_flags = OPf_WANT_SCALAR | OPf_KIDS | OPf_REF;
+               enter->op_flags |= OPf_STACKED;
+           }
+
+           /* We don't have control over who points to theirmark, so sacrifice
+              ours.  */
+           theirmark->op_next = ourmark->op_next;
+           theirmark->op_flags = ourmark->op_flags;
+           ourlast->op_next = gvop ? gvop : (OP *) enter;
+           op_null(ourmark);
+           op_null(o);
+           enter->op_private |= OPpITER_REVERSED;
+           iter->op_private |= OPpITER_REVERSED;
+           
+           break;
+       }
+       
        default:
-           o->op_seq = PL_op_seqmax++;
+           o->op_opt = 1;
            break;
        }
        oldop = o;
@@ -6312,45 +7098,44 @@ Perl_peep(pTHX_ register OP *o)
     LEAVE;
 }
 
-
-
-char* Perl_custom_op_name(pTHX_ OP* o)
+char*
+Perl_custom_op_name(pTHX_ const OP* o)
 {
-    IV  index = PTR2IV(o->op_ppaddr);
+    const IV index = PTR2IV(o->op_ppaddr);
     SV* keysv;
     HE* he;
 
     if (!PL_custom_op_names) /* This probably shouldn't happen */
-        return PL_op_name[OP_CUSTOM];
+        return (char *)PL_op_name[OP_CUSTOM];
 
     keysv = sv_2mortal(newSViv(index));
 
     he = hv_fetch_ent(PL_custom_op_names, keysv, 0, 0);
     if (!he)
-        return PL_op_name[OP_CUSTOM]; /* Don't know who you are */
+        return (char *)PL_op_name[OP_CUSTOM]; /* Don't know who you are */
 
     return SvPV_nolen(HeVAL(he));
 }
 
-char* Perl_custom_op_desc(pTHX_ OP* o)
+char*
+Perl_custom_op_desc(pTHX_ const OP* o)
 {
-    IV  index = PTR2IV(o->op_ppaddr);
+    const IV index = PTR2IV(o->op_ppaddr);
     SV* keysv;
     HE* he;
 
     if (!PL_custom_op_descs)
-        return PL_op_desc[OP_CUSTOM];
+        return (char *)PL_op_desc[OP_CUSTOM];
 
     keysv = sv_2mortal(newSViv(index));
 
     he = hv_fetch_ent(PL_custom_op_descs, keysv, 0, 0);
     if (!he)
-        return PL_op_desc[OP_CUSTOM];
+        return (char *)PL_op_desc[OP_CUSTOM];
 
     return SvPV_nolen(HeVAL(he));
 }
 
-
 #include "XSUB.h"
 
 /* Efficient sub that returns a constant scalar value. */
@@ -6361,10 +7146,20 @@ const_sv_xsub(pTHX_ CV* cv)
     if (items != 0) {
 #if 0
         Perl_croak(aTHX_ "usage: %s::%s()",
-                   HvNAME(GvSTASH(CvGV(cv))), GvNAME(CvGV(cv)));
+                   HvNAME_get(GvSTASH(CvGV(cv))), GvNAME(CvGV(cv)));
 #endif
     }
     EXTEND(sp, 1);
     ST(0) = (SV*)XSANY.any_ptr;
     XSRETURN(1);
 }
+
+/*
+ * Local variables:
+ * c-indentation-style: bsd
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ *
+ * ex: set ts=8 sts=4 sw=4 noet:
+ */