This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix memory leak in C<sub X { sub {} }> arising from a refcount
[perl5.git] / op.c
diff --git a/op.c b/op.c
index ea58e6f..7cca17b 100644 (file)
--- a/op.c
+++ b/op.c
 
 /* #define PL_OP_SLAB_ALLOC */
 
-/* XXXXXX testing */
-#ifdef USE_ITHREADS
-#  define OP_REFCNT_LOCK               NOOP
-#  define OP_REFCNT_UNLOCK             NOOP
-#  define OpREFCNT_set(o,n)            ((o)->op_targ = (n))
-#  define OpREFCNT_dec(o)              (--(o)->op_targ)
-#else
-#  define OP_REFCNT_LOCK               NOOP
-#  define OP_REFCNT_UNLOCK             NOOP
-#  define OpREFCNT_set(o,n)            NOOP
-#  define OpREFCNT_dec(o)              0
-#endif
-
 #ifdef PL_OP_SLAB_ALLOC 
 #define SLAB_SIZE 8192
 static char    *PL_OpPtr  = NULL;
@@ -68,6 +55,7 @@ S_Slab_Alloc(pTHX_ int m, size_t sz)
      : CALL_FPTR(PL_check[type])(aTHX_ (OP*)o))
 
 #define PAD_MAX 999999999
+#define RETURN_UNLIMITED_NUMBER (PERL_INT_MAX / 2)
 
 STATIC char*
 S_gv_ename(pTHX_ GV *gv)
@@ -115,20 +103,42 @@ S_no_bareword_allowed(pTHX_ OP *o)
                     SvPV_nolen(cSVOPo_sv)));
 }
 
+STATIC U8*
+S_trlist_upgrade(pTHX_ U8** sp, U8** ep)
+{
+    U8 *s = *sp;
+    U8 *e = *ep;
+    U8 *d;
+
+    Newz(801, d, (e - s) * 2, U8);
+    *sp = d;
+
+    while (s < e) {
+        if (*s < 0x80 || *s == 0xff)
+            *d++ = *s++;
+       else {
+            U8 c = *s++;
+            *d++ = ((c >> 6)         | 0xc0);
+            *d++ = ((c       & 0x3f) | 0x80);
+        }
+    }
+    *ep = d;
+    return *sp;
+}
+  
+
 /* "register" allocation */
 
 PADOFFSET
 Perl_pad_allocmy(pTHX_ char *name)
 {
-    dTHR;
     PADOFFSET off;
     SV *sv;
 
-    if (!(
-       PL_in_my == KEY_our ||
-       isALPHA(name[1]) ||
-       (PL_hints & HINT_UTF8 && (name[1] & 0xc0) == 0xc0) ||
-       name[1] == '_' && (int)strlen(name) > 2 ))
+    if (!(PL_in_my == KEY_our ||
+         isALPHA(name[1]) ||
+         (PL_hints & HINT_UTF8 && UTF8_IS_START(name[1])) ||
+         (name[1] == '_' && (int)strlen(name) > 2)))
     {
        if (!isPRINT(name[1]) || strchr("\t\n\r\f", name[1])) {
            /* 1999-02-27 mjd@plover.com */
@@ -151,7 +161,7 @@ Perl_pad_allocmy(pTHX_ char *name)
        }
        yyerror(Perl_form(aTHX_ "Can't use global %s in \"my\"",name));
     }
-    if (ckWARN(WARN_UNSAFE) && AvFILLp(PL_comppad_name) >= 0) {
+    if (ckWARN(WARN_MISC) && AvFILLp(PL_comppad_name) >= 0) {
        SV **svp = AvARRAY(PL_comppad_name);
        HV *ourstash = (PL_curstash ? PL_curstash : PL_defstash);
        PADOFFSET top = AvFILLp(PL_comppad_name);
@@ -163,7 +173,7 @@ Perl_pad_allocmy(pTHX_ char *name)
                    || ((SvFLAGS(sv) & SVpad_OUR) && GvSTASH(sv) == ourstash))
                && strEQ(name, SvPVX(sv)))
            {
-               Perl_warner(aTHX_ WARN_UNSAFE,
+               Perl_warner(aTHX_ WARN_MISC,
                    "\"%s\" variable %s masks earlier declaration in same %s", 
                    (PL_in_my == KEY_our ? "our" : "my"),
                    name,
@@ -173,20 +183,20 @@ Perl_pad_allocmy(pTHX_ char *name)
            }
        }
        if (PL_in_my == KEY_our) {
-           while (off >= 0 && off <= top) {
+           do {
                if ((sv = svp[off])
                    && sv != &PL_sv_undef
+                   && (SvIVX(sv) == PAD_MAX || SvIVX(sv) == 0)
                    && ((SvFLAGS(sv) & SVpad_OUR) && GvSTASH(sv) == ourstash)
                    && strEQ(name, SvPVX(sv)))
                {
-                   Perl_warner(aTHX_ WARN_UNSAFE,
+                   Perl_warner(aTHX_ WARN_MISC,
                        "\"our\" variable %s redeclared", name);
-                   Perl_warner(aTHX_ WARN_UNSAFE,
-                       "(Did you mean \"local\" instead of \"our\"?)\n");
+                   Perl_warner(aTHX_ WARN_MISC,
+                       "\t(Did you mean \"local\" instead of \"our\"?)\n");
                    break;
                }
-               --off;
-           }
+           } while ( off-- > 0 );
        }
     }
     off = pad_alloc(OP_PADSV, SVs_PADMY);
@@ -204,7 +214,7 @@ Perl_pad_allocmy(pTHX_ char *name)
     }
     if (PL_in_my == KEY_our) {
        (void)SvUPGRADE(sv, SVt_PVGV);
-       GvSTASH(sv) = (HV*)SvREFCNT_inc(PL_curstash ? PL_curstash : PL_defstash);
+       GvSTASH(sv) = (HV*)SvREFCNT_inc(PL_curstash ? (SV*)PL_curstash : (SV*)PL_defstash);
        SvFLAGS(sv) |= SVpad_OUR;
     }
     av_store(PL_comppad_name, off, sv);
@@ -252,7 +262,6 @@ STATIC PADOFFSET
 S_pad_findlex(pTHX_ char *name, PADOFFSET newoff, U32 seq, CV* startcv,
            I32 cx_ix, I32 saweval, U32 flags)
 {
-    dTHR;
     CV *cv;
     I32 off;
     SV *sv;
@@ -336,9 +345,12 @@ S_pad_findlex(pTHX_ char *name, PADOFFSET newoff, U32 seq, CV* startcv,
                        }
                    }
                    else if (!CvUNIQUE(PL_compcv)) {
-                       if (ckWARN(WARN_CLOSURE) && !SvFAKE(sv) && !CvUNIQUE(cv))
+                       if (ckWARN(WARN_CLOSURE) && !SvFAKE(sv) && !CvUNIQUE(cv)
+                           && !(SvFLAGS(sv) & SVpad_OUR))
+                       {
                            Perl_warner(aTHX_ WARN_CLOSURE,
                                "Variable \"%s\" will not stay shared", name);
+                       }
                    }
                }
                av_store(PL_comppad, newoff, SvREFCNT_inc(oldsv));
@@ -370,8 +382,9 @@ S_pad_findlex(pTHX_ char *name, PADOFFSET newoff, U32 seq, CV* startcv,
                if (CxREALEVAL(cx))
                    saweval = i;
                break;
+           case OP_DOFILE:
            case OP_REQUIRE:
-               /* require must have its own scope */
+               /* require/do must have their own scope */
                return 0;
            }
            break;
@@ -395,7 +408,6 @@ S_pad_findlex(pTHX_ char *name, PADOFFSET newoff, U32 seq, CV* startcv,
 PADOFFSET
 Perl_pad_findmy(pTHX_ char *name)
 {
-    dTHR;
     I32 off;
     I32 pendoff = 0;
     SV *sv;
@@ -458,7 +470,6 @@ Perl_pad_findmy(pTHX_ char *name)
 void
 Perl_pad_leavemy(pTHX_ I32 fill)
 {
-    dTHR;
     I32 off;
     SV **svp = AvARRAY(PL_comppad_name);
     SV *sv;
@@ -478,7 +489,6 @@ Perl_pad_leavemy(pTHX_ I32 fill)
 PADOFFSET
 Perl_pad_alloc(pTHX_ I32 optype, U32 tmptype)
 {
-    dTHR;
     SV *sv;
     I32 retval;
 
@@ -529,7 +539,6 @@ Perl_pad_alloc(pTHX_ I32 optype, U32 tmptype)
 SV *
 Perl_pad_sv(pTHX_ PADOFFSET po)
 {
-    dTHR;
 #ifdef USE_THREADS
     DEBUG_X(PerlIO_printf(Perl_debug_log,
                          "0x%"UVxf" Pad 0x%"UVxf" sv %"IVdf"\n",
@@ -546,7 +555,6 @@ Perl_pad_sv(pTHX_ PADOFFSET po)
 void
 Perl_pad_free(pTHX_ PADOFFSET po)
 {
-    dTHR;
     if (!PL_curpad)
        return;
     if (AvARRAY(PL_comppad) != PL_curpad)
@@ -574,7 +582,6 @@ Perl_pad_free(pTHX_ PADOFFSET po)
 void
 Perl_pad_swipe(pTHX_ PADOFFSET po)
 {
-    dTHR;
     if (AvARRAY(PL_comppad) != PL_curpad)
        Perl_croak(aTHX_ "panic: pad_swipe curpad");
     if (!po)
@@ -604,7 +611,6 @@ void
 Perl_pad_reset(pTHX)
 {
 #ifdef USE_BROKEN_PAD_RESET
-    dTHR;
     register I32 po;
 
     if (AvARRAY(PL_comppad) != PL_curpad)
@@ -633,7 +639,6 @@ Perl_pad_reset(pTHX)
 PADOFFSET
 Perl_find_threadsv(pTHX_ const char *name)
 {
-    dTHR;
     char *p;
     PADOFFSET key;
     SV **svp;
@@ -794,6 +799,7 @@ S_op_clear(pTHX_ OP *o)
        cSVOPo->op_sv = Nullsv;
 #endif
        break;
+    case OP_METHOD_NAMED:
     case OP_CONST:
        SvREFCNT_dec(cSVOPo->op_sv);
        cSVOPo->op_sv = Nullsv;
@@ -853,8 +859,8 @@ S_cop_free(pTHX_ COP* cop)
 {
     Safefree(cop->cop_label);
 #ifdef USE_ITHREADS
-    Safefree(CopFILE(cop));            /* XXXXX share in a pvtable? */
-    Safefree(CopSTASHPV(cop));         /* XXXXX share in a pvtable? */
+    Safefree(CopFILE(cop));            /* XXX share in a pvtable? */
+    Safefree(CopSTASHPV(cop));         /* XXX share in a pvtable? */
 #else
     /* NOTE: COP.cop_stash is not refcounted */
     SvREFCNT_dec(CopFILEGV(cop));
@@ -917,7 +923,6 @@ STATIC OP *
 S_scalarboolean(pTHX_ OP *o)
 {
     if (o->op_type == OP_SASSIGN && cBINOPo->op_first->op_type == OP_CONST) {
-       dTHR;
        if (ckWARN(WARN_SYNTAX)) {
            line_t oldline = CopLINE(PL_curcop);
 
@@ -976,7 +981,7 @@ Perl_scalar(pTHX_ OP *o)
     case OP_LEAVETRY:
        kid = cLISTOPo->op_first;
        scalar(kid);
-       while (kid = kid->op_sibling) {
+       while ((kid = kid->op_sibling)) {
            if (kid->op_sibling)
                scalarvoid(kid);
            else
@@ -1013,10 +1018,7 @@ Perl_scalarvoid(pTHX_ OP *o)
        || (o->op_type == OP_NULL && (o->op_targ == OP_NEXTSTATE
                                      || o->op_targ == OP_SETSTATE
                                      || o->op_targ == OP_DBSTATE)))
-    {
-       dTHR;
        PL_curcop = (COP*)o;            /* for warning below */
-    }
 
     /* assumes no premature commitment */
     want = o->op_flags & OPf_WANT;
@@ -1133,7 +1135,6 @@ Perl_scalarvoid(pTHX_ OP *o)
        if (cSVOPo->op_private & OPpCONST_STRICT)
            no_bareword_allowed(o);
        else {
-           dTHR;
            if (ckWARN(WARN_VOID)) {
                useless = "a constant";
                if (SvNIOK(sv) && (SvNV(sv) == 0.0 || SvNV(sv) == 1.0))
@@ -1174,7 +1175,6 @@ Perl_scalarvoid(pTHX_ OP *o)
     case OP_DBSTATE:
     case OP_ENTERTRY:
     case OP_ENTER:
-    case OP_SCALAR:
        if (!(o->op_flags & OPf_KIDS))
            break;
        /* FALL THROUGH */
@@ -1193,6 +1193,8 @@ Perl_scalarvoid(pTHX_ OP *o)
     case OP_REQUIRE:
        /* all requires must return a boolean value */
        o->op_flags &= ~OPf_WANT;
+       /* FALL THROUGH */
+    case OP_SCALAR:
        return scalar(o);
     case OP_SPLIT:
        if ((kid = cLISTOPo->op_first) && kid->op_type == OP_PUSHRE) {
@@ -1201,11 +1203,8 @@ Perl_scalarvoid(pTHX_ OP *o)
        }
        break;
     }
-    if (useless) {
-       dTHR;
-       if (ckWARN(WARN_VOID))
-           Perl_warner(aTHX_ WARN_VOID, "Useless use of %s in void context", useless);
-    }
+    if (useless && ckWARN(WARN_VOID))
+       Perl_warner(aTHX_ WARN_VOID, "Useless use of %s in void context", useless);
     return o;
 }
 
@@ -1269,7 +1268,7 @@ Perl_list(pTHX_ OP *o)
     case OP_LEAVETRY:
        kid = cLISTOPo->op_first;
        list(kid);
-       while (kid = kid->op_sibling) {
+       while ((kid = kid->op_sibling)) {
            if (kid->op_sibling)
                scalarvoid(kid);
            else
@@ -1306,7 +1305,6 @@ Perl_scalarseq(pTHX_ OP *o)
             o->op_type == OP_LEAVE ||
             o->op_type == OP_LEAVETRY)
        {
-           dTHR;
            for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling) {
                if (kid->op_sibling) {
                    scalarvoid(kid);
@@ -1337,9 +1335,7 @@ S_modkids(pTHX_ OP *o, I32 type)
 OP *
 Perl_mod(pTHX_ OP *o, I32 type)
 {
-    dTHR;
     OP *kid;
-    SV *sv;
     STRLEN n_a;
 
     if (!o || PL_error_count)
@@ -1356,6 +1352,31 @@ Perl_mod(pTHX_ OP *o, I32 type)
        PL_modcount++;
        return o;
     case OP_CONST:
+        if (o->op_private & (OPpCONST_BARE) && 
+                !(type == OP_GREPSTART || type == OP_ENTERSUB || type == OP_REFGEN)) {
+            SV *sv = ((SVOP*)o)->op_sv;
+            GV *gv;
+
+            /* Could be a filehandle */
+            if (gv = gv_fetchpv(SvPV_nolen(sv), FALSE, SVt_PVIO)) {
+                OP* gvio = newUNOP(OP_RV2GV, 0, newGVOP(OP_GV, 0, gv));
+                op_free(o);
+                o = gvio;
+            } else {
+                /* OK, it's a sub */
+                OP* enter;
+                gv = gv_fetchpv(SvPV_nolen(sv), TRUE, SVt_PVCV);
+
+                enter = newUNOP(OP_ENTERSUB,0, 
+                        newUNOP(OP_RV2CV, 0, 
+                            newGVOP(OP_GV, 0, gv)
+                        ));
+                enter->op_private |= OPpLVAL_INTRO;
+                op_free(o);
+                o = enter;
+            }
+            break;
+        }
        if (!(o->op_private & (OPpCONST_ARYBASE)))
            goto nomod;
        if (PL_eval_start && PL_eval_start->op_type == OP_CONST) {
@@ -1386,6 +1407,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
        }
        else {                          /* lvalue subroutine call */
            o->op_private |= OPpLVAL_INTRO;
+           PL_modcount = RETURN_UNLIMITED_NUMBER;
            if (type == OP_GREPSTART || type == OP_ENTERSUB || type == OP_REFGEN) {
                /* Backward compatibility mode: */
                o->op_private |= OPpENTERSUB_INARGS;
@@ -1412,18 +1434,19 @@ Perl_mod(pTHX_ OP *o, I32 type)
                    if (kid->op_type == OP_METHOD_NAMED
                        || kid->op_type == OP_METHOD)
                    {
-                       OP *newop;
+                       UNOP *newop;
 
                        if (kid->op_sibling || kid->op_next != kid) {
                            yyerror("panic: unexpected optree near method call");
                            break;
                        }
                        
-                       NewOp(1101, newop, 1, OP);
+                       NewOp(1101, newop, 1, UNOP);
                        newop->op_type = OP_RV2CV;
                        newop->op_ppaddr = PL_ppaddr[OP_RV2CV];
-                       newop->op_next = newop;
-                       kid->op_sibling = newop;
+                       newop->op_first = Nullop;
+                        newop->op_next = (OP*)newop;
+                       kid->op_sibling = (OP*)newop;
                        newop->op_private |= OPpLVAL_INTRO;
                        break;
                    }
@@ -1519,7 +1542,7 @@ Perl_mod(pTHX_ OP *o, I32 type)
        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 = 10000;
+           PL_modcount = RETURN_UNLIMITED_NUMBER;
            return o;           /* Treat \(@foo) like ordinary list. */
        }
        /* FALL THROUGH */
@@ -1528,14 +1551,16 @@ Perl_mod(pTHX_ OP *o, I32 type)
            goto nomod;
        ref(cUNOPo->op_first, o->op_type);
        /* FALL THROUGH */
-    case OP_AASSIGN:
     case OP_ASLICE:
     case OP_HSLICE:
+       if (type == OP_LEAVESUBLV)
+           o->op_private |= OPpMAYBE_LVSUB;
+       /* FALL THROUGH */
+    case OP_AASSIGN:
     case OP_NEXTSTATE:
     case OP_DBSTATE:
-    case OP_REFGEN:
     case OP_CHOMP:
-       PL_modcount = 10000;
+       PL_modcount = RETURN_UNLIMITED_NUMBER;
        break;
     case OP_RV2SV:
        if (!type && cUNOPo->op_first->op_type != OP_GV)
@@ -1554,11 +1579,13 @@ Perl_mod(pTHX_ OP *o, I32 type)
 
     case OP_PADAV:
     case OP_PADHV:
-       PL_modcount = 10000;
+       PL_modcount = RETURN_UNLIMITED_NUMBER;
        if (type == OP_REFGEN && o->op_flags & OPf_PARENS)
            return o;           /* Treat \(@foo) like ordinary list. */
        if (scalar_mod_type(o, type))
            goto nomod;
+       if (type == OP_LEAVESUBLV)
+           o->op_private |= OPpMAYBE_LVSUB;
        /* FALL THROUGH */
     case OP_PADSV:
        PL_modcount++;
@@ -1586,6 +1613,8 @@ Perl_mod(pTHX_ OP *o, I32 type)
        /* FALL THROUGH */
     case OP_POS:
     case OP_VEC:
+       if (type == OP_LEAVESUBLV)
+           o->op_private |= OPpMAYBE_LVSUB;
       lvalue_func:
        pad_free(o->op_targ);
        o->op_targ = pad_alloc(o->op_type, SVs_PADMY);
@@ -1600,12 +1629,15 @@ Perl_mod(pTHX_ OP *o, I32 type)
        if (type == OP_ENTERSUB &&
             !(o->op_private & (OPpLVAL_INTRO | OPpDEREF)))
            o->op_private |= OPpLVAL_DEFER;
+       if (type == OP_LEAVESUBLV)
+           o->op_private |= OPpMAYBE_LVSUB;
        PL_modcount++;
        break;
 
     case OP_SCOPE:
     case OP_LEAVE:
     case OP_ENTER:
+    case OP_LINESEQ:
        if (o->op_flags & OPf_KIDS)
            mod(cLISTOPo->op_last, type);
        break;
@@ -1624,8 +1656,14 @@ Perl_mod(pTHX_ OP *o, I32 type)
        for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
            mod(kid, type);
        break;
+
+    case OP_RETURN:
+       if (type != OP_LEAVESUBLV)
+           goto nomod;
+       break; /* mod()ing was handled by ck_return() */
     }
-    o->op_flags |= OPf_MOD;
+    if (type != OP_LEAVESUBLV)
+        o->op_flags |= OPf_MOD;
 
     if (type == OP_AASSIGN || type == OP_SASSIGN)
        o->op_flags |= OPf_SPECIAL|OPf_REF;
@@ -1634,7 +1672,8 @@ Perl_mod(pTHX_ OP *o, I32 type)
        o->op_flags &= ~OPf_SPECIAL;
        PL_hints |= HINT_BLOCK_SCOPE;
     }
-    else if (type != OP_GREPSTART && type != OP_ENTERSUB)
+    else if (type != OP_GREPSTART && type != OP_ENTERSUB
+             && type != OP_LEAVESUBLV)
        o->op_flags |= OPf_REF;
     return o;
 }
@@ -1835,7 +1874,6 @@ S_dup_attrlist(pTHX_ OP *o)
 STATIC void
 S_apply_attrs(pTHX_ HV *stash, SV *target, OP *attrs)
 {
-    OP *modname;       /* for 'use' */
     SV *stashsv;
 
     /* fake up C<use attributes $pkg,$rv,@attrs> */
@@ -1845,22 +1883,52 @@ S_apply_attrs(pTHX_ HV *stash, SV *target, OP *attrs)
        stashsv = newSVpv(HvNAME(stash), 0);
     else
        stashsv = &PL_sv_no;
+
 #define ATTRSMODULE "attributes"
-    modname = newSVOP(OP_CONST, 0,
-                     newSVpvn(ATTRSMODULE, sizeof(ATTRSMODULE)-1));
-    modname->op_private |= OPpCONST_BARE;
-    /* that flag is required to make 'use' work right */
-    utilize(1, start_subparse(FALSE, 0),
-           Nullop, /* version */
-           modname,
-           prepend_elem(OP_LIST,
-                        newSVOP(OP_CONST, 0, stashsv),
-                        prepend_elem(OP_LIST,
-                                     newSVOP(OP_CONST, 0, newRV(target)),
-                                     dup_attrlist(attrs))));
+
+    Perl_load_module(aTHX_ PERL_LOADMOD_IMPORT_OPS,
+                    newSVpvn(ATTRSMODULE, sizeof(ATTRSMODULE)-1),
+                    Nullsv,
+                    prepend_elem(OP_LIST,
+                                 newSVOP(OP_CONST, 0, stashsv),
+                                 prepend_elem(OP_LIST,
+                                              newSVOP(OP_CONST, 0,
+                                                      newRV(target)),
+                                              dup_attrlist(attrs))));
     LEAVE;
 }
 
+void
+Perl_apply_attrs_string(pTHX_ char *stashpv, CV *cv,
+                        char *attrstr, STRLEN len)
+{
+    OP *attrs = Nullop;
+
+    if (!len) {
+        len = strlen(attrstr);
+    }
+
+    while (len) {
+        for (; isSPACE(*attrstr) && len; --len, ++attrstr) ;
+        if (len) {
+            char *sstr = attrstr;
+            for (; !isSPACE(*attrstr) && len; --len, ++attrstr) ;
+            attrs = append_elem(OP_LIST, attrs,
+                                newSVOP(OP_CONST, 0,
+                                        newSVpvn(sstr, attrstr-sstr)));
+        }
+    }
+
+    Perl_load_module(aTHX_ PERL_LOADMOD_IMPORT_OPS,
+                     newSVpvn(ATTRSMODULE, sizeof(ATTRSMODULE)-1),
+                     Nullsv, prepend_elem(OP_LIST,
+                                 newSVOP(OP_CONST, 0, newSVpv(stashpv,0)),
+                                 prepend_elem(OP_LIST,
+                                              newSVOP(OP_CONST, 0,
+                                                      newRV((SV*)cv)),
+                                               attrs)));
+}
+
 STATIC OP *
 S_my_kid(pTHX_ OP *o, OP *attrs)
 {
@@ -1943,10 +2011,9 @@ Perl_sawparens(pTHX_ OP *o)
 OP *
 Perl_bind_match(pTHX_ I32 type, OP *left, OP *right)
 {
-    dTHR;
     OP *o;
 
-    if (ckWARN(WARN_UNSAFE) &&
+    if (ckWARN(WARN_MISC) &&
       (left->op_type == OP_RV2AV ||
        left->op_type == OP_RV2HV ||
        left->op_type == OP_PADAV ||
@@ -1957,16 +2024,19 @@ Perl_bind_match(pTHX_ I32 type, OP *left, OP *right)
       const char *sample = ((left->op_type == OP_RV2AV ||
                             left->op_type == OP_PADAV)
                            ? "@array" : "%hash");
-      Perl_warner(aTHX_ WARN_UNSAFE,
+      Perl_warner(aTHX_ WARN_MISC,
              "Applying %s to %s will act on scalar(%s)", 
              desc, sample, sample);
     }
 
-    if (right->op_type == OP_MATCH ||
+    if (!(right->op_flags & OPf_STACKED) &&
+       (right->op_type == OP_MATCH ||
        right->op_type == OP_SUBST ||
-       right->op_type == OP_TRANS) {
+       right->op_type == OP_TRANS)) {
        right->op_flags |= OPf_STACKED;
-       if (right->op_type != OP_MATCH)
+       if (right->op_type != OP_MATCH &&
+            ! (right->op_type == OP_TRANS &&
+               right->op_private & OPpTRANS_IDENTICAL))
            left = mod(left, right->op_type);
        if (right->op_type == OP_TRANS)
            o = newBINOP(OP_NULL, OPf_STACKED, scalar(left), right);
@@ -2027,7 +2097,6 @@ Perl_save_hints(pTHX)
 int
 Perl_block_start(pTHX_ int full)
 {
-    dTHR;
     int retval = PL_savestack_ix;
 
     SAVEI32(PL_comppad_name_floor);
@@ -2056,7 +2125,6 @@ Perl_block_start(pTHX_ int full)
 OP*
 Perl_block_end(pTHX_ I32 floor, OP *seq)
 {
-    dTHR;
     int needblockscope = PL_hints & HINT_BLOCK_SCOPE;
     OP* retval = scalarseq(seq);
     LEAVE_SCOPE(floor);
@@ -2084,7 +2152,6 @@ S_newDEFSVOP(pTHX)
 void
 Perl_newPROG(pTHX_ OP *o)
 {
-    dTHR;
     if (PL_in_eval) {
        if (PL_eval_root)
                return;
@@ -2129,10 +2196,9 @@ Perl_localize(pTHX_ OP *o, I32 lex)
     if (o->op_flags & OPf_PARENS)
        list(o);
     else {
-       dTHR;
        if (ckWARN(WARN_PARENTHESIS) && PL_bufptr > PL_oldbufptr && PL_bufptr[-1] == ',') {
            char *s;
-           for (s = PL_bufptr; *s && (isALNUM(*s) || (*s & 0x80) || strchr("@$%, ",*s)); s++) ;
+           for (s = PL_bufptr; *s && (isALNUM(*s) || UTF8_IS_CONTINUED(*s) || strchr("@$%, ",*s)); s++) ;
            if (*s == ';' || *s == '=')
                Perl_warner(aTHX_ WARN_PARENTHESIS,
                            "Parentheses missing around \"%s\" list",
@@ -2167,7 +2233,6 @@ Perl_jmaybe(pTHX_ OP *o)
 OP *
 Perl_fold_constants(pTHX_ register OP *o)
 {
-    dTHR;
     register OP *curop;
     I32 type = o->op_type;
     SV *sv;
@@ -2285,7 +2350,6 @@ Perl_fold_constants(pTHX_ register OP *o)
 OP *
 Perl_gen_constant_list(pTHX_ register OP *o)
 {
-    dTHR;
     register OP *curop;
     I32 oldtmps_floor = PL_tmps_floor;
 
@@ -2333,13 +2397,6 @@ Perl_convert(pTHX_ I32 type, I32 flags, OP *o)
     if (o->op_type != type)
        return o;
 
-    if (cLISTOPo->op_children < 7) {
-       /* XXX do we really need to do this if we're done appending?? */
-       for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
-           last = kid;
-       cLISTOPo->op_last = last;       /* in case check substituted last arg */
-    }
-
     return fold_constants(o);
 }
 
@@ -2354,8 +2411,11 @@ Perl_append_elem(pTHX_ I32 type, OP *first, OP *last)
     if (!last)
        return first;
 
-    if (first->op_type != type || type==OP_LIST && first->op_flags & OPf_PARENS)
-           return newLISTOP(type, 0, first, last);
+    if (first->op_type != type
+       || (type == OP_LIST && (first->op_flags & OPf_PARENS)))
+    {
+       return newLISTOP(type, 0, first, last);
+    }
 
     if (first->op_flags & OPf_KIDS)
        ((LISTOP*)first)->op_last->op_sibling = last;
@@ -2364,7 +2424,6 @@ Perl_append_elem(pTHX_ I32 type, OP *first, OP *last)
        ((LISTOP*)first)->op_first = last;
     }
     ((LISTOP*)first)->op_last = last;
-    ((LISTOP*)first)->op_children++;
     return first;
 }
 
@@ -2385,10 +2444,8 @@ Perl_append_list(pTHX_ I32 type, LISTOP *first, LISTOP *last)
 
     first->op_last->op_sibling = last->op_first;
     first->op_last = last->op_last;
-    first->op_children += last->op_children;
-    if (first->op_children)
-       first->op_flags |= OPf_KIDS;
-    
+    first->op_flags |= (last->op_flags & OPf_KIDS);
+
 #ifdef PL_OP_SLAB_ALLOC
 #else
     Safefree(last);     
@@ -2418,7 +2475,7 @@ Perl_prepend_elem(pTHX_ I32 type, OP *first, OP *last)
            first->op_sibling = ((LISTOP*)last)->op_first;
            ((LISTOP*)last)->op_first = first;
        }
-       ((LISTOP*)last)->op_children++;
+       last->op_flags |= OPf_KIDS;
        return last;
     }
 
@@ -2451,7 +2508,8 @@ Perl_newLISTOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
 
     listop->op_type = type;
     listop->op_ppaddr = PL_ppaddr[type];
-    listop->op_children = (first != 0) + (last != 0);
+    if (first || last)
+       flags |= OPf_KIDS;
     listop->op_flags = flags;
 
     if (!last && first)
@@ -2471,8 +2529,6 @@ Perl_newLISTOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
        if (!last)
            listop->op_last = pushop;
     }
-    else if (listop->op_children)
-       listop->op_flags |= OPf_KIDS;
 
     return (OP*)listop;
 }
@@ -2569,25 +2625,32 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
     SV *rstr = ((SVOP*)repl)->op_sv;
     STRLEN tlen;
     STRLEN rlen;
-    register U8 *t = (U8*)SvPV(tstr, tlen);
-    register U8 *r = (U8*)SvPV(rstr, rlen);
+    U8 *t = (U8*)SvPV(tstr, tlen);
+    U8 *r = (U8*)SvPV(rstr, rlen);
     register I32 i;
     register I32 j;
     I32 del;
     I32 complement;
     I32 squash;
+    I32 grows = 0;
     register short *tbl;
 
     complement = o->op_private & OPpTRANS_COMPLEMENT;
     del                = o->op_private & OPpTRANS_DELETE;
     squash     = o->op_private & OPpTRANS_SQUASH;
+    
+    if (SvUTF8(tstr))
+        o->op_private |= OPpTRANS_FROM_UTF;
+    
+    if (SvUTF8(rstr)) 
+        o->op_private |= OPpTRANS_TO_UTF;
 
     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;
-       I32 ulen;
+       STRLEN ulen;
        U32 tfirst = 1;
        U32 tlast = 0;
        I32 tdiff;
@@ -2598,16 +2661,17 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
        I32 none = 0;
        U32 max = 0;
        I32 bits;
-       I32 grows = 0;
        I32 havefinal = 0;
        U32 final;
-       HV *hv;
        I32 from_utf    = o->op_private & OPpTRANS_FROM_UTF;
        I32 to_utf      = o->op_private & OPpTRANS_TO_UTF;
+       U8* tsave = from_utf ? NULL : trlist_upgrade(&t, &tend);
+       U8* rsave = to_utf   ? NULL : trlist_upgrade(&r, &rend);
 
        if (complement) {
-           U8 tmpbuf[10];
+           U8 tmpbuf[UTF8_MAXLEN+1];
            U8** cp;
+           I32* cl;
            UV nextmin = 0;
            New(1109, cp, tlen, U8*);
            i = 0;
@@ -2615,7 +2679,7 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
            while (t < tend) {
                cp[i++] = t;
                t += UTF8SKIP(t);
-               if (*t == 0xff) {
+               if (t < tend && *t == 0xff) {
                    t++;
                    t += UTF8SKIP(t);
                }
@@ -2623,7 +2687,8 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
            qsort(cp, i, sizeof(U8*), utf8compare);
            for (j = 0; j < i; j++) {
                U8 *s = cp[j];
-               UV val = utf8_to_uv(s, &ulen);
+               I32 cur = j < i - 1 ? cp[j+1] - s : tend - s;
+               UV  val = utf8_to_uv(s, cur, &ulen, 0);
                s += ulen;
                diff = val - nextmin;
                if (diff > 0) {
@@ -2635,8 +2700,8 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
                        sv_catpvn(transv, (char*)tmpbuf, t - tmpbuf);
                    }
                }
-               if (*s == 0xff)
-                   val = utf8_to_uv(s+1, &ulen);
+               if (s < tend && *s == 0xff)
+                   val = utf8_to_uv(s+1, cur - 1, &ulen, 0);
                if (val >= nextmin)
                    nextmin = val + 1;
            }
@@ -2648,29 +2713,27 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
            t = (U8*)SvPVX(transv);
            tlen = SvCUR(transv);
            tend = t + tlen;
+           Safefree(cp);
        }
        else if (!rlen && !del) {
            r = t; rlen = tlen; rend = tend;
        }
        if (!squash) {
-           if (to_utf && from_utf) {   /* only counting characters */
-               if (t == r || (tlen == rlen && memEQ(t, r, tlen)))
-                   o->op_private |= OPpTRANS_IDENTICAL;
-           }
-           else {      /* straight latin-1 translation */
-               if (tlen == 4 && memEQ(t, "\0\377\303\277", 4) &&
-                   rlen == 4 && memEQ(r, "\0\377\303\277", 4))
+               if (t == r ||
+                   (tlen == rlen && memEQ((char *)t, (char *)r, tlen)))
+               {
                    o->op_private |= OPpTRANS_IDENTICAL;
-           }
+               }
        }
 
        while (t < tend || tfirst <= tlast) {
            /* see if we need more "t" chars */
            if (tfirst > tlast) {
-               tfirst = (I32)utf8_to_uv(t, &ulen);
+               tfirst = (I32)utf8_to_uv(t, tend - t, &ulen, 0);
                t += ulen;
                if (t < tend && *t == 0xff) {   /* illegal utf8 val indicates range */
-                   tlast = (I32)utf8_to_uv(++t, &ulen);
+                   t++;
+                   tlast = (I32)utf8_to_uv(t, tend - t, &ulen, 0);
                    t += ulen;
                }
                else
@@ -2680,10 +2743,11 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
            /* now see if we need more "r" chars */
            if (rfirst > rlast) {
                if (r < rend) {
-                   rfirst = (I32)utf8_to_uv(r, &ulen);
+                   rfirst = (I32)utf8_to_uv(r, rend - r, &ulen, 0);
                    r += ulen;
                    if (r < rend && *r == 0xff) {       /* illegal utf8 val indicates range */
-                       rlast = (I32)utf8_to_uv(++r, &ulen);
+                       r++;
+                       rlast = (I32)utf8_to_uv(r, rend - r, &ulen, 0);
                        r += ulen;
                    }
                    else
@@ -2725,20 +2789,8 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
                if (rfirst + diff > max)
                    max = rfirst + diff;
                rfirst += diff + 1;
-               if (!grows) {
-                   if (rfirst <= 0x80)
-                       ;
-                   else if (rfirst <= 0x800)
-                       grows |= (tfirst < 0x80);
-                   else if (rfirst <= 0x10000)
-                       grows |= (tfirst < 0x800);
-                   else if (rfirst <= 0x200000)
-                       grows |= (tfirst < 0x10000);
-                   else if (rfirst <= 0x4000000)
-                       grows |= (tfirst < 0x200000);
-                   else if (rfirst <= 0x80000000)
-                       grows |= (tfirst < 0x4000000);
-               }
+               if (!grows)
+                   grows = (UNISKIP(tfirst) < UNISKIP(rfirst));
            }
            tfirst += diff + 1;
        }
@@ -2754,17 +2806,24 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
        else
            bits = 8;
 
+       Safefree(cPVOPo->op_pv);
        cSVOPo->op_sv = (SV*)swash_init("utf8", "", listsv, bits, none);
        SvREFCNT_dec(listsv);
        if (transv)
            SvREFCNT_dec(transv);
 
        if (!del && havefinal)
-           (void)hv_store((HV*)SvRV((cSVOPo->op_sv)), "FINAL", 5, newSViv((IV)final), 0);
+           (void)hv_store((HV*)SvRV((cSVOPo->op_sv)), "FINAL", 5,
+                          newSVuv((UV)final), 0);
 
-       if (grows && to_utf)
+       if (grows)
            o->op_private |= OPpTRANS_GROWS;
 
+       if (tsave)
+           Safefree(tsave);
+       if (rsave)
+           Safefree(rsave);
+
        op_free(expr);
        op_free(repl);
        return o;
@@ -2785,10 +2844,22 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
                    else
                        tbl[i] = i;
                }
-               else
+               else {
+                   if (i < 128 && r[j] >= 128)
+                       grows = 1;
                    tbl[i] = r[j++];
+               }
            }
        }
+       if (!del) {
+           if (j >= rlen)
+               j = rlen - 1;
+           else
+               cPVOPo->op_pv = (char*)Renew(tbl, 0x101+rlen-j, short);
+           tbl[0x100] = rlen - j;
+           for (i=0; i < rlen - j; i++)
+               tbl[0x101+i] = r[j+i];
+       }
     }
     else {
        if (!rlen && !del) {
@@ -2807,10 +2878,15 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
                }
                --j;
            }
-           if (tbl[t[i]] == -1)
+           if (tbl[t[i]] == -1) {
+               if (t[i] < 128 && r[j] >= 128)
+                   grows = 1;
                tbl[t[i]] = r[j];
+           }
        }
     }
+    if (grows)
+       o->op_private |= OPpTRANS_GROWS;
     op_free(expr);
     op_free(repl);
 
@@ -2820,7 +2896,6 @@ Perl_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
 OP *
 Perl_newPMOP(pTHX_ I32 type, I32 flags)
 {
-    dTHR;
     PMOP *pmop;
 
     NewOp(1101, pmop, 1, PMOP);
@@ -2847,7 +2922,6 @@ Perl_newPMOP(pTHX_ I32 type, I32 flags)
 OP *
 Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl)
 {
-    dTHR;
     PMOP *pm;
     LOGOP *rcop;
     I32 repl_has_vars = 0;
@@ -2867,7 +2941,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl)
            p = SvPV(pat, plen);
            pm->op_pmflags |= PMf_SKIPWHITE;
        }
-       if ((PL_hints & HINT_UTF8) || (SvUTF8(pat) && !(PL_hints & HINT_BYTE)))
+       if ((PL_hints & HINT_UTF8) || DO_UTF8(pat))
            pm->op_pmdynflags |= PMdf_UTF8;
        pm->op_pmregexp = CALLREGCOMP(aTHX_ p, p + plen, pm);
        if (strEQ("\\s+", pm->op_pmregexp->precomp))
@@ -3038,7 +3112,6 @@ Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
 OP *
 Perl_newGVOP(pTHX_ I32 type, I32 flags, GV *gv)
 {
-    dTHR;
 #ifdef USE_ITHREADS
     GvIN_PAD_on(gv);
     return newPADOP(type, flags, SvREFCNT_inc(gv));
@@ -3067,7 +3140,6 @@ Perl_newPVOP(pTHX_ I32 type, I32 flags, char *pv)
 void
 Perl_package(pTHX_ OP *o)
 {
-    dTHR;
     SV *sv;
 
     save_hptr(&PL_curstash);
@@ -3094,7 +3166,6 @@ void
 Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *id, OP *arg)
 {
     OP *pack;
-    OP *meth;
     OP *rqop;
     OP *imop;
     OP *veop;
@@ -3108,14 +3179,14 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *id, OP *arg)
     if (version != Nullop) {
        SV *vesv = ((SVOP*)version)->op_sv;
 
-       if (arg == Nullop && !SvNIOK(vesv)) {
+       if (arg == Nullop && !SvNIOKp(vesv)) {
            arg = version;
        }
        else {
            OP *pack;
            SV *meth;
 
-           if (version->op_type != OP_CONST || !SvNIOK(vesv))
+           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 */
@@ -3124,7 +3195,7 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *id, OP *arg)
            /* Fake up a method call to VERSION */
            meth = newSVpvn("VERSION",7);
            sv_upgrade(meth, SVt_PVIV);
-           SvIOK_on(meth);
+           (void)SvIOK_on(meth);
            PERL_HASH(SvUVX(meth), SvPVX(meth), SvCUR(meth));
            veop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL,
                            append_elem(OP_LIST,
@@ -3136,7 +3207,7 @@ 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 (SvNIOK(((SVOP*)id)->op_sv)) {
+    else if (SvNIOKp(((SVOP*)id)->op_sv)) {
        imop = Nullop;          /* use 5.0; */
     }
     else {
@@ -3148,7 +3219,7 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *id, OP *arg)
        /* Fake up a method call to import/unimport */
        meth = aver ? newSVpvn("import",6) : newSVpvn("unimport", 8);;
        sv_upgrade(meth, SVt_PVIV);
-       SvIOK_on(meth);
+       (void)SvIOK_on(meth);
        PERL_HASH(SvUVX(meth), SvPVX(meth), SvCUR(meth));
        imop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL,
                       append_elem(OP_LIST,
@@ -3188,6 +3259,65 @@ Perl_utilize(pTHX_ int aver, I32 floor, OP *version, OP *id, OP *arg)
     PL_expect = XSTATE;
 }
 
+void
+Perl_load_module(pTHX_ U32 flags, SV *name, SV *ver, ...)
+{
+    va_list args;
+    va_start(args, ver);
+    vload_module(flags, name, ver, &args);
+    va_end(args);
+}
+
+#ifdef PERL_IMPLICIT_CONTEXT
+void
+Perl_load_module_nocontext(U32 flags, SV *name, SV *ver, ...)
+{
+    dTHX;
+    va_list args;
+    va_start(args, ver);
+    vload_module(flags, name, ver, &args);
+    va_end(args);
+}
+#endif
+
+void
+Perl_vload_module(pTHX_ U32 flags, SV *name, SV *ver, va_list *args)
+{
+    OP *modname, *veop, *imop;
+
+    modname = newSVOP(OP_CONST, 0, name);
+    modname->op_private |= OPpCONST_BARE;
+    if (ver) {
+       veop = newSVOP(OP_CONST, 0, ver);
+    }
+    else
+       veop = Nullop;
+    if (flags & PERL_LOADMOD_NOIMPORT) {
+       imop = sawparens(newNULLLIST());
+    }
+    else if (flags & PERL_LOADMOD_IMPORT_OPS) {
+       imop = va_arg(*args, OP*);
+    }
+    else {
+       SV *sv;
+       imop = Nullop;
+       sv = va_arg(*args, SV*);
+       while (sv) {
+           imop = append_elem(OP_LIST, imop, newSVOP(OP_CONST, 0, sv));
+           sv = va_arg(*args, SV*);
+       }
+    }
+    {
+       line_t ocopline = PL_copline;
+       int oexpect = PL_expect;
+
+       utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0),
+               veop, modname, imop);
+       PL_expect = oexpect;
+       PL_copline = ocopline;
+    }
+}
+
 OP *
 Perl_dofile(pTHX_ OP *term)
 {
@@ -3271,7 +3401,8 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
     }
 
     if (list_assignment(left)) {
-       dTHR;
+       OP *curop;
+
        PL_modcount = 0;
        PL_eval_start = right;  /* Grandfathering $[ assignment here.  Bletch.*/
        left = mod(left, OP_AASSIGN);
@@ -3282,12 +3413,19 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
            op_free(right);
            return Nullop;
        }
-       o = newBINOP(OP_AASSIGN, flags,
-               list(force_list(right)),
-               list(force_list(left)) );
+       curop = list(force_list(left));
+       o = newBINOP(OP_AASSIGN, flags, list(force_list(right)), curop);
        o->op_private = 0 | (flags >> 8);
+       for (curop = ((LISTOP*)curop)->op_first;
+            curop; curop = curop->op_sibling)
+       {
+           if (curop->op_type == OP_RV2HV &&
+               ((UNOP*)curop)->op_first->op_type != OP_GV) {
+               o->op_private |= OPpASSIGN_HASH;
+               break;
+           }
+       }
        if (!(left->op_private & OPpLVAL_INTRO)) {
-           OP *curop;
            OP *lastop = o;
            PL_generation++;
            for (curop = LINKLIST(o); curop != o; curop = LINKLIST(curop)) {
@@ -3319,7 +3457,11 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                    }
                    else if (curop->op_type == OP_PUSHRE) {
                        if (((PMOP*)curop)->op_pmreplroot) {
+#ifdef USE_ITHREADS
+                           GV *gv = (GV*)PL_curpad[(PADOFFSET)((PMOP*)curop)->op_pmreplroot];
+#else
                            GV *gv = (GV*)((PMOP*)curop)->op_pmreplroot;
+#endif
                            if (gv == PL_defgv || SvCUR(gv) == PL_generation)
                                break;
                            SvCUR(gv) = PL_generation;
@@ -3331,7 +3473,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                lastop = curop;
            }
            if (curop != o)
-               o->op_private = OPpASSIGN_COMMON;
+               o->op_private |= OPpASSIGN_COMMON;
        }
        if (right && right->op_type == OP_SPLIT) {
            OP* tmpop;
@@ -3364,7 +3506,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                    }
                }
                else {
-                   if (PL_modcount < 10000 &&
+                   if (PL_modcount < RETURN_UNLIMITED_NUMBER &&
                      ((LISTOP*)right)->op_last->op_type == OP_CONST)
                    {
                        SV *sv = ((SVOP*)((LISTOP*)right)->op_last)->op_sv;
@@ -3399,7 +3541,6 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
 OP *
 Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o)
 {
-    dTHR;
     U32 seq = intro_my();
     register COP *cop;
 
@@ -3439,9 +3580,9 @@ Perl_newSTATEOP(pTHX_ I32 flags, char *label, OP *o)
         PL_copline = NOLINE;
     }
 #ifdef USE_ITHREADS
-    CopFILE_set(cop, CopFILE(PL_curcop));      /* XXXXX share in a pvtable? */
+    CopFILE_set(cop, CopFILE(PL_curcop));      /* XXX share in a pvtable? */
 #else
-    CopFILEGV_set(cop, (GV*)SvREFCNT_inc(CopFILEGV(PL_curcop)));
+    CopFILEGV_set(cop, CopFILEGV(PL_curcop));
 #endif
     CopSTASH_set(cop, PL_curstash);
 
@@ -3488,7 +3629,6 @@ Perl_newLOGOP(pTHX_ I32 type, I32 flags, OP *first, OP *other)
 STATIC OP *
 S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
 {
-    dTHR;
     LOGOP *logop;
     OP *o;
     OP *first = *firstp;
@@ -3514,9 +3654,8 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
        }
     }
     if (first->op_type == OP_CONST) {
-       if (ckWARN(WARN_PRECEDENCE) && (first->op_private & OPpCONST_BARE))
-           Perl_warner(aTHX_ WARN_PRECEDENCE, "Probable precedence problem on %s", 
-                       PL_op_desc[type]);
+       if (ckWARN(WARN_BAREWORD) && (first->op_private & OPpCONST_BARE))
+           Perl_warner(aTHX_ WARN_BAREWORD, "Bareword found in conditional"); 
        if ((type == OP_AND) == (SvTRUE(((SVOP*)first)->op_sv))) {
            op_free(first);
            *firstp = Nullop;
@@ -3534,7 +3673,7 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
        else
            scalar(other);
     }
-    else if (ckWARN(WARN_UNSAFE) && (first->op_flags & OPf_KIDS)) {
+    else if (ckWARN(WARN_MISC) && (first->op_flags & OPf_KIDS)) {
        OP *k1 = ((UNOP*)first)->op_first;
        OP *k2 = k1->op_sibling;
        OPCODE warnop = 0;
@@ -3563,7 +3702,7 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
        if (warnop) {
            line_t oldline = CopLINE(PL_curcop);
            CopLINE_set(PL_curcop, PL_copline);
-           Perl_warner(aTHX_ WARN_UNSAFE,
+           Perl_warner(aTHX_ WARN_MISC,
                 "Value of %s%s can be \"0\"; test with defined()",
                 PL_op_desc[warnop],
                 ((warnop == OP_READLINE || warnop == OP_GLOB)
@@ -3601,7 +3740,6 @@ S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
 OP *
 Perl_newCONDOP(pTHX_ I32 flags, OP *first, OP *trueop, OP *falseop)
 {
-    dTHR;
     LOGOP *logop;
     OP *start;
     OP *o;
@@ -3655,7 +3793,6 @@ Perl_newCONDOP(pTHX_ I32 flags, OP *first, OP *trueop, OP *falseop)
 OP *
 Perl_newRANGE(pTHX_ I32 flags, OP *left, OP *right)
 {
-    dTHR;
     LOGOP *range;
     OP *flip;
     OP *flop;
@@ -3702,7 +3839,6 @@ Perl_newRANGE(pTHX_ I32 flags, OP *left, OP *right)
 OP *
 Perl_newLOOPOP(pTHX_ I32 flags, I32 debuggable, OP *expr, OP *block)
 {
-    dTHR;
     OP* listop;
     OP* o;
     int once = block && block->op_flags & OPf_SPECIAL &&
@@ -3758,12 +3894,12 @@ 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)
 {
-    dTHR;
     OP *redo;
     OP *next = 0;
     OP *listop;
     OP *o;
     OP *condop;
+    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))) {
@@ -3796,10 +3932,14 @@ Perl_newWHILEOP(pTHX_ I32 flags, I32 debuggable, LOOP *loop, I32 whileline, OP *
        block = scope(block);
     }
 
-    if (cont)
+    if (cont) {
        next = LINKLIST(cont);
+    }
     if (expr) {
-       cont = append_elem(OP_LINESEQ, cont, newOP(OP_UNSTACK, 0));
+       OP *unstack = newOP(OP_UNSTACK, 0);
+       if (!next)
+           next = unstack;
+       cont = append_elem(OP_LINESEQ, cont, unstack);
        if ((line_t)whileline != NOLINE) {
            PL_copline = whileline;
            cont = append_elem(OP_LINESEQ, cont,
@@ -3822,8 +3962,6 @@ Perl_newWHILEOP(pTHX_ I32 flags, I32 debuggable, LOOP *loop, I32 whileline, OP *
        if (listop)
            ((LISTOP*)listop)->op_last->op_next = condop =
                (o == listop ? redo : LINKLIST(o));
-       if (!next)
-           next = condop;
     }
     else
        o = listop;
@@ -3840,6 +3978,7 @@ Perl_newWHILEOP(pTHX_ I32 flags, I32 debuggable, LOOP *loop, I32 whileline, OP *
 
     loop->op_redoop = redo;
     loop->op_lastop = o;
+    o->op_private |= loopflags;
 
     if (next)
        loop->op_nextop = next;
@@ -3855,7 +3994,6 @@ OP *
 Perl_newFOROP(pTHX_ I32 flags,char *label,line_t forline,OP *sv,OP *expr,OP *block,OP *cont)
 {
     LOOP *loop;
-    LOOP *tmp;
     OP *wop;
     int padoff = 0;
     I32 iterflags = 0;
@@ -3930,9 +4068,12 @@ Perl_newFOROP(pTHX_ I32 flags,char *label,line_t forline,OP *sv,OP *expr,OP *blo
                               append_elem(OP_LIST, expr, scalar(sv))));
     assert(!loop->op_next);
 #ifdef PL_OP_SLAB_ALLOC
-    NewOp(1234,tmp,1,LOOP);
-    Copy(loop,tmp,1,LOOP);
-    loop = tmp;
+    {
+       LOOP *tmp;
+       NewOp(1234,tmp,1,LOOP);
+       Copy(loop,tmp,1,LOOP);
+       loop = tmp;
+    }
 #else
     Renew(loop, 1, LOOP);
 #endif 
@@ -3945,7 +4086,6 @@ Perl_newFOROP(pTHX_ I32 flags,char *label,line_t forline,OP *sv,OP *expr,OP *blo
 OP*
 Perl_newLOOPEX(pTHX_ I32 type, OP *label)
 {
-    dTHR;
     OP *o;
     STRLEN n_a;
 
@@ -3972,7 +4112,6 @@ Perl_newLOOPEX(pTHX_ I32 type, OP *label)
 void
 Perl_cv_undef(pTHX_ CV *cv)
 {
-    dTHR;
 #ifdef USE_THREADS
     if (CvMUTEXP(cv)) {
        MUTEX_DESTROY(CvMUTEXP(cv));
@@ -3994,16 +4133,19 @@ Perl_cv_undef(pTHX_ CV *cv)
        SAVEVPTR(PL_curpad);
        PL_curpad = 0;
 
-       if (!CvCLONED(cv))
-           op_free(CvROOT(cv));
+       op_free(CvROOT(cv));
        CvROOT(cv) = Nullop;
        LEAVE;
     }
     SvPOK_off((SV*)cv);                /* forget prototype */
-    CvFLAGS(cv) = 0;
-    SvREFCNT_dec(CvGV(cv));
     CvGV(cv) = Nullgv;
-    SvREFCNT_dec(CvOUTSIDE(cv));
+    /* Since closure prototypes have the same lifetime as the containing
+     * CV, they don't hold a refcount on the outside CV.  This avoids
+     * the refcount loop between the outer CV (which keeps a refcount to
+     * the closure prototype in the pad entry for pp_anoncode()) and the
+     * closure prototype, and the ensuing memory leak.  --GSAR */
+    if (!CvANON(cv) || CvCLONED(cv))
+       SvREFCNT_dec(CvOUTSIDE(cv));
     CvOUTSIDE(cv) = Nullcv;
     if (CvPADLIST(cv)) {
        /* may be during global destruction */
@@ -4026,6 +4168,7 @@ Perl_cv_undef(pTHX_ CV *cv)
        }
        CvPADLIST(cv) = Nullav;
     }
+    CvFLAGS(cv) = 0;
 }
 
 STATIC void
@@ -4078,7 +4221,6 @@ S_cv_dump(pTHX_ CV *cv)
 STATIC CV *
 S_cv_clone2(pTHX_ CV *proto, CV *outside)
 {
-    dTHR;
     AV* av;
     I32 ix;
     AV* protopadlist = CvPADLIST(proto);
@@ -4100,9 +4242,8 @@ S_cv_clone2(pTHX_ CV *proto, CV *outside)
 
     cv = PL_compcv = (CV*)NEWSV(1104,0);
     sv_upgrade((SV *)cv, SvTYPE(proto));
+    CvFLAGS(cv) = CvFLAGS(proto) & ~CVf_CLONE;
     CvCLONED_on(cv);
-    if (CvANON(proto))
-       CvANON_on(cv);
 
 #ifdef USE_THREADS
     New(666, CvMUTEXP(cv), 1, perl_mutex);
@@ -4110,9 +4251,9 @@ S_cv_clone2(pTHX_ CV *proto, CV *outside)
     CvOWNER(cv)                = 0;
 #endif /* USE_THREADS */
     CvFILE(cv)         = CvFILE(proto);
-    CvGV(cv)           = (GV*)SvREFCNT_inc(CvGV(proto));
+    CvGV(cv)           = CvGV(proto);
     CvSTASH(cv)                = CvSTASH(proto);
-    CvROOT(cv)         = CvROOT(proto);
+    CvROOT(cv)         = OpREFCNT_inc(CvROOT(proto));
     CvSTART(cv)                = CvSTART(proto);
     if (outside)
        CvOUTSIDE(cv)   = (CV*)SvREFCNT_inc(outside);
@@ -4222,9 +4363,7 @@ Perl_cv_clone(pTHX_ CV *proto)
 void
 Perl_cv_ckproto(pTHX_ CV *cv, GV *gv, char *p)
 {
-    dTHR;
-
-    if (((!p != !SvPOK(cv)) || (p && strNE(p, SvPVX(cv)))) && ckWARN_d(WARN_UNSAFE)) {
+    if (((!p != !SvPOK(cv)) || (p && strNE(p, SvPVX(cv)))) && ckWARN_d(WARN_PROTOTYPE)) {
        SV* msg = sv_newmortal();
        SV* name = Nullsv;
 
@@ -4240,7 +4379,7 @@ Perl_cv_ckproto(pTHX_ CV *cv, GV *gv, char *p)
            Perl_sv_catpvf(aTHX_ msg, "(%s)", p);
        else
            sv_catpv(msg, "none");
-       Perl_warner(aTHX_ WARN_UNSAFE, "%"SVf, msg);
+       Perl_warner(aTHX_ WARN_PROTOTYPE, "%"SVf, msg);
     }
 }
 
@@ -4313,7 +4452,6 @@ 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)
 {
-    dTHR;
     STRLEN n_a;
     char *name;
     char *aname;
@@ -4346,9 +4484,9 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                                           maximum a prototype before. */
        if (SvTYPE(gv) > SVt_NULL) {
            if (!SvPOK((SV*)gv) && !(SvIOK((SV*)gv) && SvIVX((SV*)gv) == -1)
-               && ckWARN_d(WARN_UNSAFE))
+               && ckWARN_d(WARN_PROTOTYPE))
            {
-               Perl_warner(aTHX_ WARN_UNSAFE, "Runaway prototype");
+               Perl_warner(aTHX_ WARN_PROTOTYPE, "Runaway prototype");
            }
            cv_ckproto((CV*)gv, NULL, ps);
        }
@@ -4364,7 +4502,7 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
 
     if (!name || GvCVGEN(gv))
        cv = Nullcv;
-    else if (cv = GvCV(gv)) {
+    else if ((cv = GvCV(gv))) {
        cv_ckproto(cv, gv, ps);
        /* already defined (or promised)? */
        if (CvROOT(cv) || CvXSUB(cv) || GvASSUMECV(gv)) {
@@ -4376,17 +4514,16 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                goto done;
            }
            /* ahem, death to those who redefine active sort subs */
-           if (PL_curstackinfo->si_type == PERLSI_SORT && PL_sortcop == CvSTART(cv))
+           if (PL_curstackinfo->si_type == PERLSI_SORT &&
+               PL_sortcop == CvSTART(cv)) {
+               op_free(block);
                Perl_croak(aTHX_ "Can't redefine active sort subroutine %s", name);
+           }
            if (!block)
                goto withattrs;
-           if (const_sv = cv_const_sv(cv))
+           if ((const_sv = cv_const_sv(cv)))
                const_changed = sv_cmp(const_sv, op_const_sv(block, Nullcv));
-           if ((const_sv && const_changed) || ckWARN(WARN_REDEFINE) 
-                                       && !(CvGV(cv) && GvSTASH(CvGV(cv))
-                                       && HvNAME(GvSTASH(CvGV(cv)))
-                                       && strEQ(HvNAME(GvSTASH(CvGV(cv))),
-                                                "autouse")))
+           if ((const_sv || const_changed) && ckWARN(WARN_REDEFINE))
            {
                line_t oldline = CopLINE(PL_curcop);
                CopLINE_set(PL_curcop, PL_copline);
@@ -4438,8 +4575,30 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        CvOUTSIDE(PL_compcv) = 0;
        CvPADLIST(cv) = CvPADLIST(PL_compcv);
        CvPADLIST(PL_compcv) = 0;
-       if (SvREFCNT(PL_compcv) > 1) /* XXX Make closures transit through stub. */
-           CvOUTSIDE(PL_compcv) = (CV*)SvREFCNT_inc((SV*)cv);
+       /* inner references to PL_compcv must be fixed up ... */
+       {
+           AV *padlist = CvPADLIST(cv);
+           AV *comppad_name = (AV*)AvARRAY(padlist)[0];
+           AV *comppad = (AV*)AvARRAY(padlist)[1];
+           SV **namepad = AvARRAY(comppad_name);
+           SV **curpad = AvARRAY(comppad);
+           for (ix = AvFILLp(comppad_name); ix > 0; ix--) {
+               SV *namesv = namepad[ix];
+               if (namesv && namesv != &PL_sv_undef
+                   && *SvPVX(namesv) == '&')
+               {
+                   CV *innercv = (CV*)curpad[ix];
+                   if (CvOUTSIDE(innercv) == PL_compcv) {
+                       CvOUTSIDE(innercv) = cv;
+                       if (!CvANON(innercv) || CvCLONED(innercv)) {
+                           (void)SvREFCNT_inc(cv);
+                           SvREFCNT_dec(PL_compcv);
+                       }
+                   }
+               }
+           }
+       }
+       /* ... before we throw it away */
        SvREFCNT_dec(PL_compcv);
     }
     else {
@@ -4450,7 +4609,7 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            PL_sub_generation++;
        }
     }
-    CvGV(cv) = (GV*)SvREFCNT_inc(gv);
+    CvGV(cv) = gv;
     CvFILE(cv) = CopFILE(PL_curcop);
     CvSTASH(cv) = PL_curstash;
 #ifdef USE_THREADS
@@ -4494,7 +4653,8 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        av_store(PL_comppad_name, AvFILLp(PL_comppad), Nullsv);
 
     if (CvLVALUE(cv)) {
-       CvROOT(cv) = newUNOP(OP_LEAVESUBLV, 0, scalarseq(block));
+       CvROOT(cv) = newUNOP(OP_LEAVESUBLV, 0,
+                            mod(scalarseq(block), OP_LEAVESUBLV));
     }
     else {
        CvROOT(cv) = newUNOP(OP_LEAVESUB, 0, scalarseq(block));
@@ -4542,6 +4702,13 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
        }
     }
 
+    /* If a potential closure prototype, don't keep a refcount on outer CV.
+     * This is okay as the lifetime of the prototype is tied to the
+     * lifetime of the outer CV.  Avoids memory leak due to reference
+     * loop. --GSAR */
+    if (!name)
+       SvREFCNT_dec(CvOUTSIDE(cv));
+
     if (name || aname) {
        char *s;
        char *tname = (name ? name : aname);
@@ -4552,7 +4719,6 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            GV *db_postponed = gv_fetchpv("DB::postponed", GV_ADDMULTI, SVt_PVHV);
            CV *pcv;
            HV *hv;
-           char *t;
 
            Perl_sv_setpvf(aTHX_ sv, "%s:%ld-%ld",
                           CopFILE(PL_curcop),
@@ -4590,8 +4756,8 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
            if (!PL_beginav)
                PL_beginav = newAV();
            DEBUG_x( dump_sub(gv) );
-           av_push(PL_beginav, SvREFCNT_inc(cv));
-           GvCV(gv) = 0;
+           av_push(PL_beginav, (SV*)cv);
+           GvCV(gv) = 0;               /* cv has been hijacked */
            call_list(oldscope, PL_beginav);
 
            PL_curcop = &PL_compiling;
@@ -4603,23 +4769,27 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
                PL_endav = newAV();
            DEBUG_x( dump_sub(gv) );
            av_unshift(PL_endav, 1);
-           av_store(PL_endav, 0, SvREFCNT_inc(cv));
-           GvCV(gv) = 0;
+           av_store(PL_endav, 0, (SV*)cv);
+           GvCV(gv) = 0;               /* cv has been hijacked */
        }
        else if (strEQ(s, "CHECK") && !PL_error_count) {
            if (!PL_checkav)
                PL_checkav = newAV();
            DEBUG_x( dump_sub(gv) );
+           if (PL_main_start && ckWARN(WARN_VOID))
+               Perl_warner(aTHX_ WARN_VOID, "Too late to run CHECK block");
            av_unshift(PL_checkav, 1);
-           av_store(PL_checkav, 0, SvREFCNT_inc(cv));
-           GvCV(gv) = 0;
+           av_store(PL_checkav, 0, (SV*)cv);
+           GvCV(gv) = 0;               /* cv has been hijacked */
        }
        else if (strEQ(s, "INIT") && !PL_error_count) {
            if (!PL_initav)
                PL_initav = newAV();
            DEBUG_x( dump_sub(gv) );
-           av_push(PL_initav, SvREFCNT_inc(cv));
-           GvCV(gv) = 0;
+           if (PL_main_start && ckWARN(WARN_VOID))
+               Perl_warner(aTHX_ WARN_VOID, "Too late to run INIT block");
+           av_push(PL_initav, (SV*)cv);
+           GvCV(gv) = 0;               /* cv has been hijacked */
        }
     }
 
@@ -4642,13 +4812,13 @@ eligible for inlining at compile-time.
 void
 Perl_newCONSTSUB(pTHX_ HV *stash, char *name, SV *sv)
 {
-    dTHR;
 
     ENTER;
-    SAVECOPLINE(PL_curcop);
-    SAVEHINTS();
 
+    SAVECOPLINE(PL_curcop);
     CopLINE_set(PL_curcop, PL_copline);
+
+    SAVEHINTS();
     PL_hints &= ~HINT_BLOCK_SCOPE;
 
     if (stash) {
@@ -4684,11 +4854,10 @@ Used by C<xsubpp> to hook up XSUBs as Perl subs.
 CV *
 Perl_newXS(pTHX_ char *name, XSUBADDR_t subaddr, char *filename)
 {
-    dTHR;
     GV *gv = gv_fetchpv(name ? name : "__ANON__", GV_ADDMULTI, SVt_PVCV);
     register CV *cv;
 
-    if (cv = (name ? GvCV(gv) : Nullcv)) {
+    if ((cv = (name ? GvCV(gv) : Nullcv))) {
        if (GvCVGEN(gv)) {
            /* just a cached method */
            SvREFCNT_dec(cv);
@@ -4721,7 +4890,7 @@ Perl_newXS(pTHX_ char *name, XSUBADDR_t subaddr, char *filename)
            PL_sub_generation++;
        }
     }
-    CvGV(cv) = (GV*)SvREFCNT_inc(gv);
+    CvGV(cv) = gv;
 #ifdef USE_THREADS
     New(666, CvMUTEXP(cv), 1, perl_mutex);
     MUTEX_INIT(CvMUTEXP(cv));
@@ -4745,28 +4914,32 @@ Perl_newXS(pTHX_ char *name, XSUBADDR_t subaddr, char *filename)
        if (strEQ(s, "BEGIN")) {
            if (!PL_beginav)
                PL_beginav = newAV();
-           av_push(PL_beginav, SvREFCNT_inc(cv));
-           GvCV(gv) = 0;
+           av_push(PL_beginav, (SV*)cv);
+           GvCV(gv) = 0;               /* cv has been hijacked */
        }
        else if (strEQ(s, "END")) {
            if (!PL_endav)
                PL_endav = newAV();
            av_unshift(PL_endav, 1);
-           av_store(PL_endav, 0, SvREFCNT_inc(cv));
-           GvCV(gv) = 0;
+           av_store(PL_endav, 0, (SV*)cv);
+           GvCV(gv) = 0;               /* cv has been hijacked */
        }
        else if (strEQ(s, "CHECK")) {
            if (!PL_checkav)
                PL_checkav = newAV();
+           if (PL_main_start && ckWARN(WARN_VOID))
+               Perl_warner(aTHX_ WARN_VOID, "Too late to run CHECK block");
            av_unshift(PL_checkav, 1);
-           av_store(PL_checkav, 0, SvREFCNT_inc(cv));
-           GvCV(gv) = 0;
+           av_store(PL_checkav, 0, (SV*)cv);
+           GvCV(gv) = 0;               /* cv has been hijacked */
        }
        else if (strEQ(s, "INIT")) {
            if (!PL_initav)
                PL_initav = newAV();
-           av_push(PL_initav, SvREFCNT_inc(cv));
-           GvCV(gv) = 0;
+           if (PL_main_start && ckWARN(WARN_VOID))
+               Perl_warner(aTHX_ WARN_VOID, "Too late to run INIT block");
+           av_push(PL_initav, (SV*)cv);
+           GvCV(gv) = 0;               /* cv has been hijacked */
        }
     }
     else
@@ -4779,7 +4952,6 @@ done:
 void
 Perl_newFORM(pTHX_ I32 floor, OP *o, OP *block)
 {
-    dTHR;
     register CV *cv;
     char *name;
     GV *gv;
@@ -4792,7 +4964,7 @@ Perl_newFORM(pTHX_ I32 floor, OP *o, OP *block)
        name = "STDOUT";
     gv = gv_fetchpv(name,TRUE, SVt_PVFM);
     GvMULTI_on(gv);
-    if (cv = GvFORM(gv)) {
+    if ((cv = GvFORM(gv))) {
        if (ckWARN(WARN_REDEFINE)) {
            line_t oldline = CopLINE(PL_curcop);
 
@@ -4804,7 +4976,7 @@ Perl_newFORM(pTHX_ I32 floor, OP *o, OP *block)
     }
     cv = PL_compcv;
     GvFORM(gv) = cv;
-    CvGV(cv) = (GV*)SvREFCNT_inc(gv);
+    CvGV(cv) = gv;
     CvFILE(cv) = CopFILE(PL_curcop);
 
     for (ix = AvFILLp(PL_comppad); ix > 0; ix--) {
@@ -4877,8 +5049,6 @@ Perl_oopsAV(pTHX_ OP *o)
 OP *
 Perl_oopsHV(pTHX_ OP *o)
 {
-    dTHR;
-    
     switch (o->op_type) {
     case OP_PADSV:
     case OP_PADAV:
@@ -5110,6 +5280,20 @@ Perl_ck_eval(pTHX_ OP *o)
 }
 
 OP *
+Perl_ck_exit(pTHX_ OP *o)
+{
+#ifdef VMS
+    HV *table = GvHV(PL_hintgv);
+    if (table) {
+       SV **svp = hv_fetch(table, "vmsish_exit", 11, FALSE);
+       if (svp && *svp && SvTRUE(*svp))
+           o->op_private |= OPpEXIT_VMSISH;
+    }
+#endif
+    return ck_fun(o);
+}
+
+OP *
 Perl_ck_exec(pTHX_ OP *o)
 {
     OP *kid;
@@ -5161,7 +5345,6 @@ Perl_ck_gvconst(pTHX_ register OP *o)
 OP *
 Perl_ck_rvconst(pTHX_ register OP *o)
 {
-    dTHR;
     SVOP *kid = (SVOP*)cUNOPo->op_first;
 
     o->op_private |= (PL_hints & HINT_STRICT_REFS);
@@ -5256,11 +5439,13 @@ Perl_ck_rvconst(pTHX_ register OP *o)
 #ifdef USE_ITHREADS
            /* XXX hack: dependence on sizeof(PADOP) <= sizeof(SVOP) */
            kPADOP->op_padix = pad_alloc(OP_GV, SVs_PADTMP);
+           SvREFCNT_dec(PL_curpad[kPADOP->op_padix]);
            GvIN_PAD_on(gv);
            PL_curpad[kPADOP->op_padix] = SvREFCNT_inc(gv);
 #else
            kid->op_sv = SvREFCNT_inc(gv);
 #endif
+           kid->op_private = 0;
            kid->op_ppaddr = PL_ppaddr[OP_GV];
        }
     }
@@ -5270,7 +5455,6 @@ Perl_ck_rvconst(pTHX_ register OP *o)
 OP *
 Perl_ck_ftst(pTHX_ OP *o)
 {
-    dTHR;
     I32 type = o->op_type;
 
     if (o->op_flags & OPf_REF) {
@@ -5308,7 +5492,6 @@ Perl_ck_ftst(pTHX_ OP *o)
 OP *
 Perl_ck_fun(pTHX_ OP *o)
 {
-    dTHR;
     register OP *kid;
     OP **tokid;
     OP *sibl;
@@ -5328,7 +5511,7 @@ Perl_ck_fun(pTHX_ OP *o)
        tokid = &cLISTOPo->op_first;
        kid = cLISTOPo->op_first;
        if (kid->op_type == OP_PUSHMARK ||
-           kid->op_type == OP_NULL && kid->op_targ == OP_PUSHMARK)
+           (kid->op_type == OP_NULL && kid->op_targ == OP_PUSHMARK))
        {
            tokid = &kid->op_sibling;
            kid = kid->op_sibling;
@@ -5364,8 +5547,8 @@ Perl_ck_fun(pTHX_ OP *o)
                    char *name = SvPVx(((SVOP*)kid)->op_sv, n_a);
                    OP *newop = newAVREF(newGVOP(OP_GV, 0,
                        gv_fetchpv(name, TRUE, SVt_PVAV) ));
-                   if (ckWARN(WARN_SYNTAX))
-                       Perl_warner(aTHX_ WARN_SYNTAX,
+                   if (ckWARN(WARN_DEPRECATED))
+                       Perl_warner(aTHX_ WARN_DEPRECATED,
                            "Array @%s missing the @ in argument %"IVdf" of %s()",
                            name, (IV)numargs, PL_op_desc[type]);
                    op_free(kid);
@@ -5384,8 +5567,8 @@ Perl_ck_fun(pTHX_ OP *o)
                    char *name = SvPVx(((SVOP*)kid)->op_sv, n_a);
                    OP *newop = newHVREF(newGVOP(OP_GV, 0,
                        gv_fetchpv(name, TRUE, SVt_PVHV) ));
-                   if (ckWARN(WARN_SYNTAX))
-                       Perl_warner(aTHX_ WARN_SYNTAX,
+                   if (ckWARN(WARN_DEPRECATED))
+                       Perl_warner(aTHX_ WARN_DEPRECATED,
                            "Hash %%%s missing the %% in argument %"IVdf" of %s()",
                            name, (IV)numargs, PL_op_desc[type]);
                    op_free(kid);
@@ -5452,11 +5635,18 @@ Perl_ck_fun(pTHX_ OP *o)
                                name = GvNAME(gv);
                                len = GvNAMELEN(gv);
                            }
+                           else if (kid->op_type == OP_AELEM
+                                    || kid->op_type == OP_HELEM)
+                           {
+                               name = "__ANONIO__";
+                               len = 10;
+                               mod(kid,type);
+                           }
                            if (name) {
                                SV *namesv;
                                targ = pad_alloc(OP_RV2GV, SVs_PADTMP);
                                namesv = PL_curpad[targ];
-                               SvUPGRADE(namesv, SVt_PV);
+                               (void)SvUPGRADE(namesv, SVt_PV);
                                if (*name != '$')
                                    sv_setpvn(namesv, "$", 1);
                                sv_catpvn(namesv, name, len);
@@ -5504,6 +5694,7 @@ Perl_ck_glob(pTHX_ OP *o)
 {
     GV *gv;
 
+    o = ck_fun(o);
     if ((o->op_flags & OPf_KIDS) && !cLISTOPo->op_first->op_sibling)
        append_elem(OP_GLOB, o, newDEFSVOP());
 
@@ -5513,11 +5704,10 @@ Perl_ck_glob(pTHX_ OP *o)
 #if !defined(PERL_EXTERNAL_GLOB)
     /* XXX this can be tightened up and made more failsafe. */
     if (!gv) {
-       OP *modname = newSVOP(OP_CONST, 0, newSVpvn("File::Glob", 10));
-       modname->op_private |= OPpCONST_BARE;
        ENTER;
-       utilize(1, start_subparse(FALSE, 0), Nullop, modname,
-               newSVOP(OP_CONST, 0, newSVpvn(":globally", 9)));
+       Perl_load_module(aTHX_ 0, newSVpvn("File::Glob", 10), Nullsv,
+                        /* null-terminated import list */
+                        newSVpvn(":globally", 9), Nullsv);
        gv = gv_fetchpv("CORE::GLOBAL::glob", FALSE, SVt_PVCV);
        LEAVE;
     }
@@ -5541,8 +5731,9 @@ Perl_ck_glob(pTHX_ OP *o)
     gv = newGVgen("main");
     gv_IOadd(gv);
     append_elem(OP_GLOB, o, newGVOP(OP_GV, 0, gv));
+    SvREFCNT_dec((SV*)gv); /* had excess refcnt */
     scalarkids(o);
-    return ck_fun(o);
+    return o;
 }
 
 OP *
@@ -5626,25 +5817,32 @@ Perl_ck_lfun(pTHX_ OP *o)
 OP *
 Perl_ck_defined(pTHX_ OP *o)           /* 19990527 MJD */
 {
-    dTHR;
     if ((o->op_flags & OPf_KIDS) && ckWARN(WARN_DEPRECATED)) {
        switch (cUNOPo->op_first->op_type) {
        case OP_RV2AV:
+           /* This is needed for
+              if (defined %stash::)
+              to work.   Do not break Tk.
+              */
            break;                      /* Globals via GV can be undef */ 
        case OP_PADAV:
        case OP_AASSIGN:                /* Is this a good idea? */
            Perl_warner(aTHX_ WARN_DEPRECATED,
                        "defined(@array) is deprecated");
            Perl_warner(aTHX_ WARN_DEPRECATED,
-                       "(Maybe you should just omit the defined()?)\n");
+                       "\t(Maybe you should just omit the defined()?)\n");
        break;
        case OP_RV2HV:
+           /* This is needed for
+              if (defined %stash::)
+              to work.   Do not break Tk.
+              */
            break;                      /* Globals via GV can be undef */ 
        case OP_PADHV:
            Perl_warner(aTHX_ WARN_DEPRECATED,
                        "defined(%%hash) is deprecated");
            Perl_warner(aTHX_ WARN_DEPRECATED,
-                       "(Maybe you should just omit the defined()?)\n");
+                       "\t(Maybe you should just omit the defined()?)\n");
            break;
        default:
            /* no warning */
@@ -5770,8 +5968,8 @@ Perl_ck_method(pTHX_ OP *o)
        SV* sv = kSVOP->op_sv;
        if (!(strchr(SvPVX(sv), ':') || strchr(SvPVX(sv), '\''))) {
            OP *cmop;
-           sv_upgrade(sv, SVt_PVIV);
-           SvIOK_on(sv);
+           (void)SvUPGRADE(sv, SVt_PVIV);
+           (void)SvIOK_on(sv);
            PERL_HASH(SvUVX(sv), SvPVX(sv), SvCUR(sv));
            cmop = newSVOP(OP_METHOD_NAMED, 0, sv);
            kSVOP->op_sv = Nullsv;
@@ -5789,6 +5987,36 @@ Perl_ck_null(pTHX_ OP *o)
 }
 
 OP *
+Perl_ck_open(pTHX_ OP *o)
+{
+    HV *table = GvHV(PL_hintgv);
+    if (table) {
+       SV **svp;
+       I32 mode;
+       svp = hv_fetch(table, "open_IN", 7, FALSE);
+       if (svp && *svp) {
+           mode = mode_from_discipline(*svp);
+           if (mode & O_BINARY)
+               o->op_private |= OPpOPEN_IN_RAW;
+           else if (mode & O_TEXT)
+               o->op_private |= OPpOPEN_IN_CRLF;
+       }
+
+       svp = hv_fetch(table, "open_OUT", 8, FALSE);
+       if (svp && *svp) {
+           mode = mode_from_discipline(*svp);
+           if (mode & O_BINARY)
+               o->op_private |= OPpOPEN_OUT_RAW;
+           else if (mode & O_TEXT)
+               o->op_private |= OPpOPEN_OUT_CRLF;
+       }
+    }
+    if (o->op_type == OP_BACKTICK)
+       return o;
+    return ck_fun(o);
+}
+
+OP *
 Perl_ck_repeat(pTHX_ OP *o)
 {
     if (cBINOPo->op_first->op_flags & OPf_PARENS) {
@@ -5815,12 +6043,29 @@ Perl_ck_require(pTHX_ OP *o)
                    --SvCUR(kid->op_sv);
                }
            }
-           sv_catpvn(kid->op_sv, ".pm", 3);
+           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);
        }
     }
     return ck_fun(o);
 }
 
+OP *
+Perl_ck_return(pTHX_ OP *o)
+{
+    OP *kid;
+    if (CvLVALUE(PL_compcv)) {
+       for (kid = cLISTOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
+           mod(kid, OP_LEAVESUBLV);
+    }
+    return o;
+}
+
 #if 0
 OP *
 Perl_ck_retarget(pTHX_ OP *o)
@@ -5883,6 +6128,7 @@ Perl_ck_shift(pTHX_ OP *o)
 OP *
 Perl_ck_sort(pTHX_ OP *o)
 {
+    OP *firstkid;
     o->op_private = 0;
 #ifdef USE_LOCALE
     if (PL_hints & HINT_LOCALE)
@@ -5891,10 +6137,10 @@ Perl_ck_sort(pTHX_ OP *o)
 
     if (o->op_type == OP_SORT && o->op_flags & OPf_STACKED)
        simplify_sort(o);
-    if (o->op_flags & OPf_STACKED) {                /* may have been cleared */
-       OP *kid = cLISTOPo->op_first->op_sibling;       /* get past pushmark */
+    firstkid = cLISTOPo->op_first->op_sibling;         /* get past pushmark */
+    if (o->op_flags & OPf_STACKED) {                   /* may have been cleared */
        OP *k;
-       kid = kUNOP->op_first;                          /* get past null */
+       OP *kid = cUNOPx(firstkid)->op_first;           /* get past null */
 
        if (kid->op_type == OP_SCOPE || kid->op_type == OP_LEAVE) {
            linklist(kid);
@@ -5910,6 +6156,12 @@ Perl_ck_sort(pTHX_ OP *o)
                    for (k = kLISTOP->op_first->op_next; k; k = k->op_next) {
                        if (k->op_next == kid)
                            k->op_next = 0;
+                       /* don't descend into loops */
+                       else if (k->op_type == OP_ENTERLOOP
+                                || k->op_type == OP_ENTERITER)
+                       {
+                           k = cLOOPx(k)->op_lastop;
+                       }
                    }
                }
                else
@@ -5918,24 +6170,32 @@ Perl_ck_sort(pTHX_ OP *o)
            }
            peep(k);
 
-           kid = cLISTOPo->op_first->op_sibling;       /* get past pushmark */
-           if (o->op_type == OP_SORT)
+           kid = firstkid;
+           if (o->op_type == OP_SORT) {
+               /* provide scalar context for comparison function/block */
+               kid = scalar(kid);
                kid->op_next = kid;
+           }
            else
                kid->op_next = k;
            o->op_flags |= OPf_SPECIAL;
        }
        else if (kid->op_type == OP_RV2SV || kid->op_type == OP_PADSV)
-           null(cLISTOPo->op_first->op_sibling);
+           null(firstkid);
+
+       firstkid = firstkid->op_sibling;
     }
 
+    /* provide list context for arguments */
+    if (o->op_type == OP_SORT)
+       list(firstkid);
+
     return o;
 }
 
 STATIC void
 S_simplify_sort(pTHX_ OP *o)
 {
-    dTHR;
     register OP *kid = cLISTOPo->op_first->op_sibling; /* get past pushmark */
     OP *k;
     int reversed;
@@ -5995,7 +6255,6 @@ S_simplify_sort(pTHX_ OP *o)
     kid = cLISTOPo->op_first->op_sibling;
     cLISTOPo->op_first->op_sibling = kid->op_sibling; /* bypass old block */
     op_free(kid);                                    /* then delete it */
-    cLISTOPo->op_children--;
 }
 
 OP *
@@ -6017,7 +6276,7 @@ Perl_ck_split(pTHX_ OP *o)
        cLISTOPo->op_last = kid; /* There was only one element previously */
     }
 
-    if (kid->op_type != OP_MATCH) {
+    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);
@@ -6069,7 +6328,6 @@ Perl_ck_join(pTHX_ OP *o)
 OP *
 Perl_ck_subr(pTHX_ OP *o)
 {
-    dTHR;
     OP *prev = ((cUNOPo->op_first->op_sibling)
             ? cUNOPo : ((UNOP*)cUNOPo->op_first))->op_first;
     OP *o2 = prev->op_sibling;
@@ -6134,7 +6392,9 @@ Perl_ck_subr(pTHX_ OP *o)
                proto++;
                arg++;
                if (o2->op_type != OP_REFGEN && o2->op_type != OP_UNDEF)
-                   bad_type(arg, "block", gv_ename(namegv), o2);
+                   bad_type(arg,
+                       arg == 1 ? "block or sub {}" : "sub {}",
+                       gv_ename(namegv), o2);
                break;
            case '*':
                /* '*' allows any scalar type, including bareword */
@@ -6182,8 +6442,8 @@ Perl_ck_subr(pTHX_ OP *o)
                        bad_type(arg, "symbol", gv_ename(namegv), o2);
                    goto wrapref;
                case '&':
-                   if (o2->op_type != OP_RV2CV)
-                       bad_type(arg, "sub", gv_ename(namegv), o2);
+                   if (o2->op_type != OP_ENTERSUB)
+                       bad_type(arg, "subroutine entry", gv_ename(namegv), o2);
                    goto wrapref;
                case '$':
                    if (o2->op_type != OP_RV2SV
@@ -6261,15 +6521,29 @@ Perl_ck_trunc(pTHX_ OP *o)
     return ck_fun(o);
 }
 
+OP *
+Perl_ck_substr(pTHX_ OP *o)
+{
+    o = ck_fun(o);
+    if ((o->op_flags & OPf_KIDS) && o->op_private == 4) {
+       OP *kid = cLISTOPo->op_first;
+
+       if (kid->op_type == OP_NULL)
+           kid = kid->op_sibling;
+       if (kid)
+           kid->op_flags |= OPf_MOD;
+
+    }
+    return o;
+}
+
 /* A peephole optimizer.  We visit the ops in the order they're to execute. */
 
 void
 Perl_peep(pTHX_ register OP *o)
 {
-    dTHR;
     register OP* oldop = 0;
     STRLEN n_a;
-    OP *last_composite = Nullop;
 
     if (!o || o->op_seq)
        return;
@@ -6288,7 +6562,6 @@ Perl_peep(pTHX_ register OP *o)
        case OP_DBSTATE:
            PL_curcop = ((COP*)o);              /* for warnings */
            o->op_seq = PL_op_seqmax++;
-           last_composite = Nullop;
            break;
 
        case OP_CONST:
@@ -6300,26 +6573,32 @@ Perl_peep(pTHX_ register OP *o)
             * for reference counts, sv_upgrade() etc. */
            if (cSVOP->op_sv) {
                PADOFFSET ix = pad_alloc(OP_CONST, SVs_PADTMP);
-               SvREFCNT_dec(PL_curpad[ix]);
-               SvPADTMP_on(cSVOPo->op_sv);
-               PL_curpad[ix] = cSVOPo->op_sv;
+               if (SvPADTMP(cSVOPo->op_sv)) {
+                   /* If op_sv is already a PADTMP then it is being used by
+                    * another pad, so make a copy. */
+                   sv_setsv(PL_curpad[ix],cSVOPo->op_sv);
+                   SvREADONLY_on(PL_curpad[ix]);
+                   SvREFCNT_dec(cSVOPo->op_sv);
+               }
+               else {
+                   SvREFCNT_dec(PL_curpad[ix]);
+                   SvPADTMP_on(cSVOPo->op_sv);
+                   PL_curpad[ix] = cSVOPo->op_sv;
+               }
                cSVOPo->op_sv = Nullsv;
                o->op_targ = ix;
            }
 #endif
-           /* FALL THROUGH */
-       case OP_UC:
-       case OP_UCFIRST:
-       case OP_LC:
-       case OP_LCFIRST:
+           o->op_seq = PL_op_seqmax++;
+           break;
+
        case OP_CONCAT:
-       case OP_JOIN:
-       case OP_QUOTEMETA:
            if (o->op_next && o->op_next->op_type == OP_STRINGIFY) {
                if (o->op_next->op_private & OPpTARGET_MY) {
                    if (o->op_flags & OPf_STACKED) /* chained concats */
                        goto ignore_optimization;
                    else {
+                       /* assert(PL_opargs[o->op_type] & OA_TARGLEX); */
                        o->op_targ = o->op_next->op_targ;
                        o->op_next->op_targ = 0;
                        o->op_private |= OPpTARGET_MY;
@@ -6373,7 +6652,7 @@ Perl_peep(pTHX_ register OP *o)
                    (PL_op = pop->op_next) &&
                    pop->op_next->op_type == OP_AELEM &&
                    !(pop->op_next->op_private &
-                     (OPpLVAL_INTRO|OPpLVAL_DEFER|OPpDEREF)) &&
+                     (OPpLVAL_INTRO|OPpLVAL_DEFER|OPpDEREF|OPpMAYBE_LVSUB)) &&
                    (i = SvIV(((SVOP*)pop)->op_sv) - PL_compiling.cop_arybase)
                                <= 255 &&
                    i >= 0)
@@ -6391,13 +6670,13 @@ Perl_peep(pTHX_ register OP *o)
                    GvAVn(gv);
                }
            }
-           else if ((o->op_private & OPpEARLY_CV) && ckWARN(WARN_UNSAFE)) {
+           else if ((o->op_private & OPpEARLY_CV) && ckWARN(WARN_PROTOTYPE)) {
                GV *gv = cGVOPo_gv;
                if (SvTYPE(gv) == SVt_PVGV && GvCV(gv) && SvPVX(GvCV(gv))) {
                    /* XXX could check prototype here instead of just carping */
                    SV *sv = sv_newmortal();
                    gv_efullname3(sv, gv, Nullch);
-                   Perl_warner(aTHX_ WARN_UNSAFE,
+                   Perl_warner(aTHX_ WARN_PROTOTYPE,
                                "%s() called too early to check prototype",
                                SvPV_nolen(sv));
                }
@@ -6422,8 +6701,14 @@ Perl_peep(pTHX_ register OP *o)
 
        case OP_ENTERLOOP:
            o->op_seq = PL_op_seqmax++;
+           while (cLOOP->op_redoop->op_type == OP_NULL)
+               cLOOP->op_redoop = cLOOP->op_redoop->op_next;
            peep(cLOOP->op_redoop);
+           while (cLOOP->op_nextop->op_type == OP_NULL)
+               cLOOP->op_nextop = cLOOP->op_nextop->op_next;
            peep(cLOOP->op_nextop);
+           while (cLOOP->op_lastop->op_type == OP_NULL)
+               cLOOP->op_lastop = cLOOP->op_lastop->op_next;
            peep(cLOOP->op_lastop);
            break;
 
@@ -6431,6 +6716,9 @@ Perl_peep(pTHX_ register OP *o)
        case OP_MATCH:
        case OP_SUBST:
            o->op_seq = PL_op_seqmax++;
+           while (cPMOP->op_pmreplstart && 
+                  cPMOP->op_pmreplstart->op_type == OP_NULL)
+               cPMOP->op_pmreplstart = cPMOP->op_pmreplstart->op_next;
            peep(cPMOP->op_pmreplstart);
            break;
 
@@ -6448,7 +6736,7 @@ Perl_peep(pTHX_ register OP *o)
                    Perl_warner(aTHX_ WARN_EXEC,
                                "Statement unlikely to be reached");
                    Perl_warner(aTHX_ WARN_EXEC,
-                               "(Maybe you meant system() when you said exec()?)\n");
+                               "\t(Maybe you meant system() when you said exec()?)\n");
                    CopLINE_set(PL_curcop, oldline);
                }
            }
@@ -6458,11 +6746,12 @@ Perl_peep(pTHX_ register OP *o)
            UNOP *rop;
            SV *lexname;
            GV **fields;
-           SV **svp, **indsvp;
+           SV **svp, **indsvp, *sv;
            I32 ind;
            char *key;
            STRLEN keylen;
        
+           o->op_seq = PL_op_seqmax++;
            if ((o->op_private & (OPpLVAL_INTRO))
                || ((BINOP*)o)->op_last->op_type != OP_CONST)
                break;
@@ -6489,8 +6778,13 @@ Perl_peep(pTHX_ register OP *o)
            rop->op_ppaddr = PL_ppaddr[OP_RV2AV];
            o->op_type = OP_AELEM;
            o->op_ppaddr = PL_ppaddr[OP_AELEM];
+           sv = newSViv(ind);
+           if (SvREADONLY(*svp))
+               SvREADONLY_on(sv);
+           SvFLAGS(sv) |= (SvFLAGS(*svp)
+                           & (SVs_PADBUSY|SVs_PADTMP|SVs_PADMY));
            SvREFCNT_dec(*svp);
-           *svp = newSViv(ind);
+           *svp = sv;
            break;
        }
        
@@ -6498,12 +6792,13 @@ Perl_peep(pTHX_ register OP *o)
            UNOP *rop;
            SV *lexname;
            GV **fields;
-           SV **svp, **indsvp;
+           SV **svp, **indsvp, *sv;
            I32 ind;
            char *key;
            STRLEN keylen;
            SVOP *first_key_op, *key_op;
-       
+
+           o->op_seq = PL_op_seqmax++;
            if ((o->op_private & (OPpLVAL_INTRO))
                /* I bet there's always a pushmark... */
                || ((LISTOP*)o)->op_first->op_sibling->op_type != OP_LIST)
@@ -6538,54 +6833,24 @@ Perl_peep(pTHX_ register OP *o)
                key = SvPV(*svp, keylen);
                indsvp = hv_fetch(GvHV(*fields), key, keylen, FALSE);
                if (!indsvp) {
-                   Perl_croak(aTHX_ "No such pseudo-hash field \"%s\" in variable %s of type %s",
+                   Perl_croak(aTHX_ "No such pseudo-hash field \"%s\" "
+                              "in variable %s of type %s",
                          key, SvPV(lexname, n_a), HvNAME(SvSTASH(lexname)));
                }
                ind = SvIV(*indsvp);
                if (ind < 1)
                    Perl_croak(aTHX_ "Bad index while coercing array into hash");
+               sv = newSViv(ind);
+               if (SvREADONLY(*svp))
+                   SvREADONLY_on(sv);
+               SvFLAGS(sv) |= (SvFLAGS(*svp)
+                               & (SVs_PADBUSY|SVs_PADTMP|SVs_PADMY));
                SvREFCNT_dec(*svp);
-               *svp = newSViv(ind);
+               *svp = sv;
            }
            break;
        }
 
-       case OP_RV2AV:
-       case OP_RV2HV:
-           if (!(o->op_flags & OPf_WANT)
-               || (o->op_flags & OPf_WANT) == OPf_WANT_LIST)
-           {
-               last_composite = o;
-           }
-           o->op_seq = PL_op_seqmax++;
-           break;
-
-       case OP_RETURN:
-           if (o->op_next && o->op_next->op_type != OP_LEAVESUBLV) {
-               o->op_seq = PL_op_seqmax++;
-               break;
-           }
-           /* FALL THROUGH */
-
-       case OP_LEAVESUBLV:
-           if (last_composite) {
-               OP *r = last_composite;
-
-               while (r->op_sibling)
-                  r = r->op_sibling;
-               if (r->op_next == o 
-                   || (r->op_next->op_type == OP_LIST
-                       && r->op_next->op_next == o))
-               {
-                   if (last_composite->op_type == OP_RV2AV)
-                       yyerror("Lvalue subs returning arrays not implemented yet");
-                   else
-                       yyerror("Lvalue subs returning hashes not implemented yet");
-                       ;
-               }               
-           }
-           /* FALL THROUGH */
-
        default:
            o->op_seq = PL_op_seqmax++;
            break;