This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Implement use attrs qw(locked package);
[perl5.git] / pp_hot.c
index fcf3d22..41f2aee 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
 #include "EXTERN.h"
 #include "perl.h"
 
+#ifdef I_UNISTD
+#include <unistd.h>
+#endif
+
 /* Hot code. */
 
 #ifdef USE_THREADS
 static void
-unset_cvowner(cvarg)
-void *cvarg;
+unset_cvowner(void *cvarg)
 {
     register CV* cv = (CV *) cvarg;
 #ifdef DEBUGGING
     dTHR;
 #endif /* DEBUGGING */
 
-    DEBUG_L((PerlIO_printf(PerlIO_stderr(), "0x%lx unsetting CvOWNER of 0x%lx:%s\n",
-                    (unsigned long)thr, (unsigned long)cv, SvPEEK((SV*)cv))));
+    DEBUG_L((PerlIO_printf(PerlIO_stderr(), "%p unsetting CvOWNER of %p:%s\n",
+                          thr, cv, SvPEEK((SV*)cv))));
     MUTEX_LOCK(CvMUTEXP(cv));
     DEBUG_L(if (CvDEPTH(cv) != 0)
                PerlIO_printf(PerlIO_stderr(), "depth %ld != 0\n",
@@ -45,7 +48,7 @@ void *cvarg;
 
 PP(pp_const)
 {
-    dSP;
+    djSP;
     XPUSHs(cSVOP->op_sv);
     RETURN;
 }
@@ -61,8 +64,8 @@ PP(pp_nextstate)
 
 PP(pp_gvsv)
 {
-    dSP;
-    EXTEND(sp,1);
+    djSP;
+    EXTEND(SP,1);
     if (op->op_private & OPpLVAL_INTRO)
        PUSHs(save_scalar(cGVOP->op_gv));
     else
@@ -83,7 +86,7 @@ PP(pp_pushmark)
 
 PP(pp_stringify)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     STRLEN len;
     char *s;
     s = SvPV(TOPs,len);
@@ -94,76 +97,14 @@ PP(pp_stringify)
 
 PP(pp_gv)
 {
-    dSP;
+    djSP;
     XPUSHs((SV*)cGVOP->op_gv);
     RETURN;
 }
 
-PP(pp_gelem)
-{
-    GV *gv;
-    SV *sv;
-    SV *ref;
-    char *elem;
-    dSP;
-
-    sv = POPs;
-    elem = SvPV(sv, na);
-    gv = (GV*)POPs;
-    ref = Nullsv;
-    sv = Nullsv;
-    switch (elem ? *elem : '\0')
-    {
-    case 'A':
-       if (strEQ(elem, "ARRAY"))
-           ref = (SV*)GvAV(gv);
-       break;
-    case 'C':
-       if (strEQ(elem, "CODE"))
-           ref = (SV*)GvCVu(gv);
-       break;
-    case 'F':
-       if (strEQ(elem, "FILEHANDLE")) /* XXX deprecate in 5.005 */
-           ref = (SV*)GvIOp(gv);
-       break;
-    case 'G':
-       if (strEQ(elem, "GLOB"))
-           ref = (SV*)gv;
-       break;
-    case 'H':
-       if (strEQ(elem, "HASH"))
-           ref = (SV*)GvHV(gv);
-       break;
-    case 'I':
-       if (strEQ(elem, "IO"))
-           ref = (SV*)GvIOp(gv);
-       break;
-    case 'N':
-       if (strEQ(elem, "NAME"))
-           sv = newSVpv(GvNAME(gv), GvNAMELEN(gv));
-       break;
-    case 'P':
-       if (strEQ(elem, "PACKAGE"))
-           sv = newSVpv(HvNAME(GvSTASH(gv)), 0);
-       break;
-    case 'S':
-       if (strEQ(elem, "SCALAR"))
-           ref = GvSV(gv);
-       break;
-    }
-    if (ref)
-       sv = newRV(ref);
-    if (sv)
-       sv_2mortal(sv);
-    else
-       sv = &sv_undef;
-    XPUSHs(sv);
-    RETURN;
-}
-
 PP(pp_and)
 {
-    dSP;
+    djSP;
     if (!SvTRUE(TOPs))
        RETURN;
     else {
@@ -174,7 +115,7 @@ PP(pp_and)
 
 PP(pp_sassign)
 {
-    dSP; dPOPTOPssrl;
+    djSP; dPOPTOPssrl;
     MAGIC *mg;
 
     if (op->op_private & OPpASSIGN_BACKWARDS) {
@@ -190,7 +131,7 @@ PP(pp_sassign)
 
 PP(pp_cond_expr)
 {
-    dSP;
+    djSP;
     if (SvTRUEx(POPs))
        RETURNOP(cCONDOP->op_true);
     else
@@ -210,7 +151,7 @@ PP(pp_unstack)
 
 PP(pp_concat)
 {
-  dSP; dATARGET; tryAMAGICbin(concat,opASSIGN);
+  djSP; dATARGET; tryAMAGICbin(concat,opASSIGN);
   {
     dPOPTOPssrl;
     STRLEN len;
@@ -237,13 +178,16 @@ PP(pp_concat)
 
 PP(pp_padsv)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     XPUSHs(TARG);
     if (op->op_flags & OPf_MOD) {
        if (op->op_private & OPpLVAL_INTRO)
            SAVECLEARSV(curpad[op->op_targ]);
-        else if (op->op_private & OPpDEREF)
+        else if (op->op_private & OPpDEREF) {
+           PUTBACK;
            vivify_ref(curpad[op->op_targ], op->op_private & OPpDEREF);
+           SPAGAIN;
+       }
     }
     RETURN;
 }
@@ -256,7 +200,7 @@ PP(pp_readline)
 
 PP(pp_eq)
 {
-    dSP; tryAMAGICbinSET(eq,0); 
+    djSP; tryAMAGICbinSET(eq,0); 
     {
       dPOPnv;
       SETs(boolSV(TOPn == value));
@@ -266,7 +210,7 @@ PP(pp_eq)
 
 PP(pp_preinc)
 {
-    dSP;
+    djSP;
     if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
        croak(no_modify);
     if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
@@ -283,7 +227,7 @@ PP(pp_preinc)
 
 PP(pp_or)
 {
-    dSP;
+    djSP;
     if (SvTRUE(TOPs))
        RETURN;
     else {
@@ -294,7 +238,7 @@ PP(pp_or)
 
 PP(pp_add)
 {
-    dSP; dATARGET; tryAMAGICbin(add,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(add,opASSIGN); 
     {
       dPOPTOPnnrl_ul;
       SETn( left + right );
@@ -304,7 +248,7 @@ PP(pp_add)
 
 PP(pp_aelemfast)
 {
-    dSP;
+    djSP;
     AV *av = GvAV((GV*)cSVOP->op_sv);
     SV** svp = av_fetch(av, op->op_private, op->op_flags & OPf_MOD);
     PUSHs(svp ? *svp : &sv_undef);
@@ -313,7 +257,7 @@ PP(pp_aelemfast)
 
 PP(pp_join)
 {
-    dSP; dMARK; dTARGET;
+    djSP; dMARK; dTARGET;
     MARK++;
     do_join(TARG, *MARK, MARK, SP);
     SP = MARK;
@@ -323,7 +267,7 @@ PP(pp_join)
 
 PP(pp_pushre)
 {
-    dSP;
+    djSP;
 #ifdef DEBUGGING
     /*
      * We ass_u_me that LvTARGOFF() comes first, and that two STRLENs
@@ -344,7 +288,7 @@ PP(pp_pushre)
 
 PP(pp_print)
 {
-    dSP; dMARK; dORIGMARK;
+    djSP; dMARK; dORIGMARK;
     GV *gv;
     IO *io;
     register PerlIO *fp;
@@ -354,9 +298,12 @@ PP(pp_print)
        gv = (GV*)*++MARK;
     else
        gv = defoutgv;
-    if (SvMAGICAL(gv) && (mg = mg_find((SV*)gv, 'q'))) {
+    if (SvRMAGICAL(gv) && (mg = mg_find((SV*)gv, 'q'))) {
        if (MARK == ORIGMARK) {
-           EXTEND(SP, 1);
+           /* If using default handle then we need to make space to 
+            * pass object as 1st arg, so move other args up ...
+            */
+           MEXTEND(SP, 1);
            ++MARK;
            Move(MARK, MARK + 1, (SP - MARK) + 1, SV*);
            ++SP;
@@ -441,7 +388,7 @@ PP(pp_print)
 
 PP(pp_rv2av)
 {
-    dSP; dPOPss;
+    djSP; dPOPss;
     AV *av;
 
     if (SvROK(sv)) {
@@ -502,8 +449,17 @@ PP(pp_rv2av)
 
     if (GIMME == G_ARRAY) {
        I32 maxarg = AvFILL(av) + 1;
-       EXTEND(SP, maxarg);
-       Copy(AvARRAY(av), SP+1, maxarg, SV*);
+       EXTEND(SP, maxarg);          
+       if (SvRMAGICAL(av)) {
+           U32 i; 
+           for (i=0; i < maxarg; i++) {
+               SV **svp = av_fetch(av, i, FALSE);
+               SP[i+1] = (svp) ? *svp : &sv_undef;
+           }
+       } 
+       else {
+           Copy(AvARRAY(av), SP+1, maxarg, SV*);
+       }
        SP += maxarg;
     }
     else {
@@ -516,7 +472,7 @@ PP(pp_rv2av)
 
 PP(pp_rv2hv)
 {
-    dSP; dTOPss;
+    djSP; dTOPss;
     HV *hv;
 
     if (SvROK(sv)) {
@@ -597,7 +553,7 @@ PP(pp_rv2hv)
 
 PP(pp_aassign)
 {
-    dSP;
+    djSP;
     SV **lastlelem = stack_sp;
     SV **lastrelem = stack_base + POPMARK;
     SV **firstrelem = stack_base + POPMARK + 1;
@@ -653,7 +609,8 @@ PP(pp_aassign)
                *(relem++) = sv;
                didstore = av_store(ary,i++,sv);
                if (magic) {
-                   mg_set(sv);
+                   if (SvSMAGICAL(sv))
+                       mg_set(sv);
                    if (!didstore)
                        SvREFCNT_dec(sv);
                }
@@ -680,14 +637,22 @@ PP(pp_aassign)
                    *(relem++) = tmpstr;
                    didstore = hv_store_ent(hash,sv,tmpstr,0);
                    if (magic) {
-                       mg_set(tmpstr);
+                       if (SvSMAGICAL(tmpstr))
+                           mg_set(tmpstr);
                        if (!didstore)
                            SvREFCNT_dec(tmpstr);
                    }
                    TAINT_NOT;
                }
-               if (relem == lastrelem)
-                   warn("Odd number of elements in hash list");
+               if (relem == lastrelem && dowarn) {
+                   if (relem == firstrelem &&
+                       SvROK(*relem) &&
+                       ( SvTYPE(SvRV(*relem)) == SVt_PVAV ||
+                         SvTYPE(SvRV(*relem)) == SVt_PVHV ) )
+                       warn("Reference found where even-sized list expected");
+                   else
+                       warn("Odd number of elements in hash assignment");
+               }
            }
            break;
        default:
@@ -797,7 +762,7 @@ PP(pp_aassign)
 
 PP(pp_match)
 {
-    dSP; dTARG;
+    djSP; dTARG;
     register PMOP *pm = cPMOP;
     register char *t;
     register char *s;
@@ -811,13 +776,15 @@ PP(pp_match)
     I32 minmatch = 0;
     I32 oldsave = savestack_ix;
     I32 update_minmatch = 1;
+    SV *screamer;
 
     if (op->op_flags & OPf_STACKED)
        TARG = POPs;
     else {
-       TARG = GvSV(defgv);
+       TARG = DEFSV;
        EXTEND(SP,1);
     }
+    PUTBACK;                           /* EVAL blocks need stack_sp. */
     s = SvPV(TARG, len);
     strend = s + len;
     if (!s)
@@ -825,6 +792,7 @@ PP(pp_match)
     TAINT_NOT;
 
     if (pm->op_pmflags & PMf_USED) {
+      failure:
        if (gimme == G_ARRAY)
            RETURN;
        RETPUSHNO;
@@ -834,6 +802,12 @@ PP(pp_match)
        pm = curpm;
        rx = pm->op_pmregexp;
     }
+    if (rx->minlen > len) goto failure;
+
+    screamer = ( (SvSCREAM(TARG) && rx->check_substr
+                 && SvTYPE(rx->check_substr) == SVt_PVBM
+                 && SvVALID(rx->check_substr)) 
+               ? TARG : Nullsv);
     truebase = t = s;
     if (global = pm->op_pmflags & PMf_GLOBAL) {
        rx->startp[0] = 0;
@@ -850,6 +824,7 @@ PP(pp_match)
        gimme = G_SCALAR;                       /* accidental array context? */
     safebase = (((gimme == G_ARRAY) || global || !rx->nparens)
                && !sawampersand);
+    safebase = safebase ? 0  : REXEC_COPY_STR ;
     if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
        SAVEINT(multiline);
        multiline = pm->op_pmflags & PMf_MULTILINE;
@@ -863,43 +838,52 @@ play_it_again:
        if (update_minmatch++)
            minmatch = (s == rx->startp[0]);
     }
-    if (pm->op_pmshort) {
-       if (pm->op_pmflags & PMf_SCANFIRST) {
-           if (SvSCREAM(TARG)) {
-               if (screamfirst[BmRARE(pm->op_pmshort)] < 0)
+    if (rx->check_substr) {
+       if (!(rx->reganch & ROPT_NOSCAN)) { /* Floating checkstring. */
+           if ( screamer ) {
+               I32 p = -1;
+               
+               if (screamfirst[BmRARE(rx->check_substr)] < 0)
                    goto nope;
-               else if (!(s = screaminstr(TARG, pm->op_pmshort)))
+               else if (!(s = screaminstr(TARG, rx->check_substr, 
+                                          rx->check_offset_min, 0, &p, 0)))
                    goto nope;
-               else if (pm->op_pmflags & PMf_ALL)
+               else if ((rx->reganch & ROPT_CHECK_ALL)
+                        && !sawampersand && !SvTAIL(rx->check_substr))
                    goto yup;
            }
-           else if (!(s = fbm_instr((unsigned char*)s,
-             (unsigned char*)strend, pm->op_pmshort)))
+           else if (!(s = fbm_instr((unsigned char*)s + rx->check_offset_min,
+                                    (unsigned char*)strend, 
+                                    rx->check_substr)))
                goto nope;
-           else if (pm->op_pmflags & PMf_ALL)
+           else if ((rx->reganch & ROPT_CHECK_ALL) && !sawampersand)
                goto yup;
-           if (s && rx->regback >= 0) {
-               ++BmUSEFUL(pm->op_pmshort);
-               s -= rx->regback;
-               if (s < t)
-                   s = t;
+           if (s && rx->check_offset_max < t - s) {
+               ++BmUSEFUL(rx->check_substr);
+               s -= rx->check_offset_max;
            }
            else
                s = t;
        }
-       else if (!multiline) {
-           if (*SvPVX(pm->op_pmshort) != *s
-               || (pm->op_pmslen > 1
-                   && memNE(SvPVX(pm->op_pmshort), s, pm->op_pmslen)))
+       /* Now checkstring is fixed, i.e. at fixed offset from the
+          beginning of match, and the match is anchored at s. */
+       else if (!multiline) {  /* Anchored near beginning of string. */
+           I32 slen;
+           if (*SvPVX(rx->check_substr) != s[rx->check_offset_min]
+               || ((slen = SvCUR(rx->check_substr)) > 1
+                   && memNE(SvPVX(rx->check_substr), 
+                            s + rx->check_offset_min, slen)))
                goto nope;
        }
-       if (!rx->naughty && --BmUSEFUL(pm->op_pmshort) < 0) {
-           SvREFCNT_dec(pm->op_pmshort);
-           pm->op_pmshort = Nullsv;    /* opt is being useless */
+       if (!rx->naughty && --BmUSEFUL(rx->check_substr) < 0
+           && rx->check_substr == rx->float_substr) {
+           SvREFCNT_dec(rx->check_substr);
+           rx->check_substr = Nullsv;  /* opt is being useless */
+           rx->float_substr = Nullsv;
        }
     }
-    if (pregexec(rx, s, strend, truebase, minmatch,
-                SvSCREAM(TARG) ? TARG : Nullsv, safebase))
+    if (regexec_flags(rx, s, strend, truebase, minmatch,
+                     screamer, NULL, safebase))
     {
        curpm = pm;
        if (pm->op_pmflags & PMf_ONCE)
@@ -911,7 +895,7 @@ play_it_again:
     /*NOTREACHED*/
 
   gotcha:
-    TAINT_IF(rx->exec_tainted);
+    TAINT_IF(RX_MATCH_TAINTED(rx));
     if (gimme == G_ARRAY) {
        I32 iters, i, len;
 
@@ -920,6 +904,7 @@ play_it_again:
            i = 1;
        else
            i = 0;
+       SPAGAIN;                        /* EVAL blocks could move the stack. */
        EXTEND(SP, iters + i);
        EXTEND_MORTAL(iters + i);
        for (i = !i; i <= iters; i++) {
@@ -935,6 +920,7 @@ play_it_again:
            strend = rx->subend;
            if (rx->startp[0] && rx->startp[0] == rx->endp[0])
                ++rx->endp[0];
+           PUTBACK;                    /* EVAL blocks may use stack */
            goto play_it_again;
        }
        LEAVE_SCOPE(oldsave);
@@ -961,9 +947,9 @@ play_it_again:
        RETPUSHYES;
     }
 
-yup:
-    TAINT_IF(rx->exec_tainted);
-    ++BmUSEFUL(pm->op_pmshort);
+yup:                                   /* Confirmed by check_substr */
+    TAINT_IF(RX_MATCH_TAINTED(rx));
+    ++BmUSEFUL(rx->check_substr);
     curpm = pm;
     if (pm->op_pmflags & PMf_ONCE)
        pm->op_pmflags |= PMf_USED;
@@ -973,7 +959,7 @@ yup:
        rx->subbeg = truebase;
        rx->subend = strend;
        rx->startp[0] = s;
-       rx->endp[0] = s + SvCUR(pm->op_pmshort);
+       rx->endp[0] = s + SvCUR(rx->check_substr);
        goto gotcha;
     }
     if (sawampersand) {
@@ -983,14 +969,14 @@ yup:
        rx->subbeg = tmps;
        rx->subend = tmps + (strend-t);
        tmps = rx->startp[0] = tmps + (s - t);
-       rx->endp[0] = tmps + SvCUR(pm->op_pmshort);
+       rx->endp[0] = tmps + SvCUR(rx->check_substr);
     }
     LEAVE_SCOPE(oldsave);
     RETPUSHYES;
 
 nope:
-    if (pm->op_pmshort)
-       ++BmUSEFUL(pm->op_pmshort);
+    if (rx->check_substr)
+       ++BmUSEFUL(rx->check_substr);
 
 ret_no:
     if (global && !(pm->op_pmflags & PMf_CONTINUE)) {
@@ -1007,9 +993,8 @@ ret_no:
 }
 
 OP *
-do_readline()
+do_readline(void)
 {
-    dTHR;
     dSP; dTARGETSTACKED;
     register SV *sv;
     STRLEN tmplen = 0;
@@ -1020,7 +1005,7 @@ do_readline()
     I32 gimme = GIMME_V;
     MAGIC *mg;
 
-    if (SvMAGICAL(last_in_gv) && (mg = mg_find((SV*)last_in_gv, 'q'))) {
+    if (SvRMAGICAL(last_in_gv) && (mg = mg_find((SV*)last_in_gv, 'q'))) {
        PUSHMARK(SP);
        XPUSHs(mg->mg_obj);
        PUTBACK;
@@ -1081,7 +1066,7 @@ do_readline()
                       ((struct NAM *)((struct FAB *)cxt)->fab$l_nam)->nam$l_fnb
                       but that's unsupported, so I don't want to do it now and
                       have it bite someone in the future. */
-                   strcat(tmpfnam,tmpnam(NULL));
+                   strcat(tmpfnam,PerlLIO_tmpnam(NULL));
                    cp = SvPV(tmpglob,i);
                    for (; i; i--) {
                       if (cp[i] == ';') hasver = 1;
@@ -1099,7 +1084,10 @@ do_readline()
                       }
                    }
                    if ((tmpfp = PerlIO_open(tmpfnam,"w+","fop=dlt")) != NULL) {
-                       ok = ((wilddsc.dsc$a_pointer = tovmsspec(SvPVX(tmpglob),vmsspec)) != NULL);
+                       Stat_t st;
+                       if (!PerlLIO_stat(SvPVX(tmpglob),&st) && S_ISDIR(st.st_mode))
+                         ok = ((wilddsc.dsc$a_pointer = tovmspath(SvPVX(tmpglob),vmsspec)) != NULL);
+                       else ok = ((wilddsc.dsc$a_pointer = tovmsspec(SvPVX(tmpglob),vmsspec)) != NULL);
                        if (ok) wilddsc.dsc$w_length = (unsigned short int) strlen(wilddsc.dsc$a_pointer);
                        while (ok && ((sts = lib$find_file(&wilddsc,&rsdsc,&cxt,
                                                    &dfltdsc,NULL,NULL,NULL))&1)) {
@@ -1143,9 +1131,14 @@ do_readline()
                sv_catsv(tmpcmd, tmpglob);
                sv_catpv(tmpcmd, "; do echo \"$a\\0\\c\"; done |");
 #else
+#ifdef DJGPP
+               sv_setpv(tmpcmd, "/dev/dosglob/"); /* File System Extension */
+               sv_catsv(tmpcmd, tmpglob);
+#else
                sv_setpv(tmpcmd, "perlglob ");
                sv_catsv(tmpcmd, tmpglob);
                sv_catpv(tmpcmd, " |");
+#endif /* !DJGPP */
 #endif /* !OS2 */
 #else /* !DOSISH */
 #if defined(CSH)
@@ -1241,7 +1234,7 @@ do_readline()
                if (!isALPHA(*tmps) && !isDIGIT(*tmps) &&
                    strchr("$&*(){}[]'\";\\|?<>~`", *tmps))
                        break;
-           if (*tmps && Stat(SvPVX(sv), &statbuf) < 0) {
+           if (*tmps && PerlLIO_stat(SvPVX(sv), &statbuf) < 0) {
                (void)POPs;             /* Unmatched wildcard?  Chuck it... */
                continue;
            }
@@ -1268,8 +1261,8 @@ do_readline()
 
 PP(pp_enter)
 {
-    dSP;
-    register CONTEXT *cx;
+    djSP;
+    register PERL_CONTEXT *cx;
     I32 gimme = OP_GIMME(op, -1);
 
     if (gimme == -1) {
@@ -1282,14 +1275,14 @@ PP(pp_enter)
     ENTER;
 
     SAVETMPS;
-    PUSHBLOCK(cx, CXt_BLOCK, sp);
+    PUSHBLOCK(cx, CXt_BLOCK, SP);
 
     RETURN;
 }
 
 PP(pp_helem)
 {
-    dSP;
+    djSP;
     HE* he;
     SV **svp;
     SV *keysv = POPs;
@@ -1327,7 +1320,7 @@ PP(pp_helem)
            if (HvNAME(hv) && isGV(*svp))
                save_gp((GV*)*svp, !(op->op_flags & OPf_SPECIAL));
            else
-               save_svref(svp);
+               save_helem(hv, keysv, svp);
        }
        else if (op->op_private & OPpDEREF)
            vivify_ref(*svp, op->op_private & OPpDEREF);
@@ -1338,8 +1331,8 @@ PP(pp_helem)
 
 PP(pp_leave)
 {
-    dSP;
-    register CONTEXT *cx;
+    djSP;
+    register PERL_CONTEXT *cx;
     register SV **mark;
     SV **newsp;
     PMOP *newpm;
@@ -1394,12 +1387,12 @@ PP(pp_leave)
 
 PP(pp_iter)
 {
-    dSP;
-    register CONTEXT *cx;
+    djSP;
+    register PERL_CONTEXT *cx;
     SV* sv;
     AV* av;
 
-    EXTEND(sp, 1);
+    EXTEND(SP, 1);
     cx = &cxstack[cxstack_ix];
     if (cx->cx_type != CXt_LOOP)
        DIE("panic: pp_iter");
@@ -1410,7 +1403,9 @@ PP(pp_iter)
 
     SvREFCNT_dec(*cx->blk_loop.itervar);
 
-    if (sv = AvARRAY(av)[++cx->blk_loop.iterix])
+    if (sv = (SvMAGICAL(av)) 
+           ? *av_fetch(av, ++cx->blk_loop.iterix, FALSE) 
+           : AvARRAY(av)[++cx->blk_loop.iterix])
        SvTEMP_off(sv);
     else
        sv = &sv_undef;
@@ -1430,7 +1425,7 @@ PP(pp_iter)
        }
        LvTARG(lv) = SvREFCNT_inc(av);
        LvTARGOFF(lv) = cx->blk_loop.iterix;
-       LvTARGLEN(lv) = -1;
+       LvTARGLEN(lv) = (UV) -1;
        sv = (SV*)lv;
     }
 
@@ -1440,7 +1435,7 @@ PP(pp_iter)
 
 PP(pp_subst)
 {
-    dSP; dTARG;
+    djSP; dTARG;
     register PMOP *pm = cPMOP;
     PMOP *rpm = pm;
     register SV *dstr;
@@ -1461,19 +1456,23 @@ PP(pp_subst)
     STRLEN len;
     int force_on_match = 0;
     I32 oldsave = savestack_ix;
+    I32 update_minmatch = 1;
+    SV *screamer;
 
     /* known replacement string? */
     dstr = (pm->op_pmflags & PMf_CONST) ? POPs : Nullsv;
     if (op->op_flags & OPf_STACKED)
        TARG = POPs;
     else {
-       TARG = GvSV(defgv);
+       TARG = DEFSV;
        EXTEND(SP,1);
-    }
+    }                  
     if (SvREADONLY(TARG)
        || (SvTYPE(TARG) > SVt_PVLV
            && !(SvTYPE(TARG) == SVt_PVGV && SvFAKE(TARG))))
        croak(no_modify);
+    PUTBACK;
+
     s = SvPV(TARG, len);
     if (!SvPOKp(TARG) || SvTYPE(TARG) == SVt_PVGV)
        force_on_match = 1;
@@ -1490,41 +1489,52 @@ PP(pp_subst)
        pm = curpm;
        rx = pm->op_pmregexp;
     }
-    safebase = (!rx->nparens && !sawampersand);
+    screamer = ( (SvSCREAM(TARG) && rx->check_substr
+                 && SvTYPE(rx->check_substr) == SVt_PVBM
+                 && SvVALID(rx->check_substr)) 
+               ? TARG : Nullsv);
+    safebase = (!rx->nparens && !sawampersand) ? 0 : REXEC_COPY_STR;
     if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
        SAVEINT(multiline);
        multiline = pm->op_pmflags & PMf_MULTILINE;
     }
     orig = m = s;
-    if (pm->op_pmshort) {
-       if (pm->op_pmflags & PMf_SCANFIRST) {
-           if (SvSCREAM(TARG)) {
-               if (screamfirst[BmRARE(pm->op_pmshort)] < 0)
+    if (rx->check_substr) {
+       if (!(rx->reganch & ROPT_NOSCAN)) { /* It floats. */
+           if (screamer) {
+               I32 p = -1;
+               
+               if (screamfirst[BmRARE(rx->check_substr)] < 0)
                    goto nope;
-               else if (!(s = screaminstr(TARG, pm->op_pmshort)))
+               else if (!(s = screaminstr(TARG, rx->check_substr, rx->check_offset_min, 0, &p, 0)))
                    goto nope;
            }
-           else if (!(s = fbm_instr((unsigned char*)s, (unsigned char*)strend,
-             pm->op_pmshort)))
+           else if (!(s = fbm_instr((unsigned char*)s + rx->check_offset_min, 
+                                    (unsigned char*)strend,
+                                    rx->check_substr)))
                goto nope;
-           if (s && rx->regback >= 0) {
-               ++BmUSEFUL(pm->op_pmshort);
-               s -= rx->regback;
-               if (s < m)
-                   s = m;
+           if (s && rx->check_offset_max < s - m) {
+               ++BmUSEFUL(rx->check_substr);
+               s -= rx->check_offset_max;
            }
            else
                s = m;
        }
-       else if (!multiline) {
-           if (*SvPVX(pm->op_pmshort) != *s
-               || (pm->op_pmslen > 1
-                   && memNE(SvPVX(pm->op_pmshort), s, pm->op_pmslen)))
+       /* Now checkstring is fixed, i.e. at fixed offset from the
+          beginning of match, and the match is anchored at s. */
+       else if (!multiline) { /* Anchored at beginning of string. */
+           I32 slen;
+           if (*SvPVX(rx->check_substr) != s[rx->check_offset_min]
+               || ((slen = SvCUR(rx->check_substr)) > 1
+                   && memNE(SvPVX(rx->check_substr), 
+                            s + rx->check_offset_min, slen)))
                goto nope;
        }
-       if (!rx->naughty && --BmUSEFUL(pm->op_pmshort) < 0) {
-           SvREFCNT_dec(pm->op_pmshort);
-           pm->op_pmshort = Nullsv;    /* opt is being useless */
+       if (!rx->naughty && --BmUSEFUL(rx->check_substr) < 0
+           && rx->check_substr == rx->float_substr) {
+           SvREFCNT_dec(rx->check_substr);
+           rx->check_substr = Nullsv;  /* opt is being useless */
+           rx->float_substr = Nullsv;
        }
     }
 
@@ -1535,9 +1545,10 @@ PP(pp_subst)
     c = dstr ? SvPV(dstr, clen) : Nullch;
 
     /* can do inplace substitution? */
-    if (c && clen <= rx->minlen && safebase) {
-       if (! pregexec(rx, s, strend, orig, 0,
-                      SvSCREAM(TARG) ? TARG : Nullsv, safebase)) {
+    if (c && clen <= rx->minlen && (once || !(safebase & REXEC_COPY_STR))
+       && !(rx->reganch & ROPT_LOOKBEHIND_SEEN)) {
+       if (!regexec_flags(rx, s, strend, orig, 0, screamer, NULL, safebase)) {
+           SPAGAIN;
            PUSHs(&sv_no);
            LEAVE_SCOPE(oldsave);
            RETURN;
@@ -1551,9 +1562,14 @@ PP(pp_subst)
        curpm = pm;
        SvSCREAM_off(TARG);     /* disable possible screamer */
        if (once) {
-           rxtainted = rx->exec_tainted;
-           m = rx->startp[0];
-           d = rx->endp[0];
+           rxtainted = RX_MATCH_TAINTED(rx);
+           if (rx->subbase) {
+               m = orig + (rx->startp[0] - rx->subbase);
+               d = orig + (rx->endp[0] - rx->subbase);
+           } else {
+               m = rx->startp[0];
+               d = rx->endp[0];
+           }
            s = orig;
            if (m - s > strend - d) {  /* faster to shorten from end */
                if (clen) {
@@ -1588,6 +1604,7 @@ PP(pp_subst)
                sv_chop(TARG, d);
            }
            TAINT_IF(rxtainted);
+           SPAGAIN;
            PUSHs(&sv_yes);
        }
        else {
@@ -1595,7 +1612,7 @@ PP(pp_subst)
            do {
                if (iters++ > maxiters)
                    DIE("Substitution loop");
-               rxtainted |= rx->exec_tainted;
+               rxtainted |= RX_MATCH_TAINTED(rx);
                m = rx->startp[0];
                /*SUPPRESS 560*/
                if (i = m - s) {
@@ -1608,43 +1625,48 @@ PP(pp_subst)
                    d += clen;
                }
                s = rx->endp[0];
-           } while (pregexec(rx, s, strend, orig, s == m,
-                             Nullsv, TRUE)); /* don't match same null twice */
+           } while (regexec_flags(rx, s, strend, orig, s == m,
+                             Nullsv, NULL, 0)); /* don't match same null twice */
            if (s != d) {
                i = strend - s;
                SvCUR_set(TARG, d - SvPVX(TARG) + i);
                Move(s, d, i+1, char);          /* include the NUL */
            }
            TAINT_IF(rxtainted);
+           SPAGAIN;
            PUSHs(sv_2mortal(newSViv((I32)iters)));
        }
        (void)SvPOK_only(TARG);
-       SvSETMAGIC(TARG);
+       if (SvSMAGICAL(TARG)) {
+           PUTBACK;
+           mg_set(TARG);
+           SPAGAIN;
+       }
        SvTAINT(TARG);
        LEAVE_SCOPE(oldsave);
        RETURN;
     }
 
-    if (pregexec(rx, s, strend, orig, 0,
-                SvSCREAM(TARG) ? TARG : Nullsv, safebase)) {
+    if (regexec_flags(rx, s, strend, orig, 0, screamer, NULL, safebase)) {
        if (force_on_match) {
            force_on_match = 0;
            s = SvPV_force(TARG, len);
            goto force_it;
        }
-       rxtainted = rx->exec_tainted;
-       dstr = NEWSV(25, sv_len(TARG));
+       rxtainted = RX_MATCH_TAINTED(rx);
+       dstr = NEWSV(25, len);
        sv_setpvn(dstr, m, s-m);
        curpm = pm;
        if (!c) {
-           register CONTEXT *cx;
+           register PERL_CONTEXT *cx;
+           SPAGAIN;
            PUSHSUBST(cx);
            RETURNOP(cPMOP->op_pmreplroot);
        }
        do {
            if (iters++ > maxiters)
                DIE("Substitution loop");
-           rxtainted |= rx->exec_tainted;
+           rxtainted |= RX_MATCH_TAINTED(rx);
            if (rx->subbase && rx->subbase != orig) {
                m = s;
                s = orig;
@@ -1659,7 +1681,7 @@ PP(pp_subst)
                sv_catpvn(dstr, c, clen);
            if (once)
                break;
-       } while (pregexec(rx, s, strend, orig, s == m, Nullsv, safebase));
+       } while (regexec_flags(rx, s, strend, orig, s == m, Nullsv, NULL, safebase));
        sv_catpvn(dstr, s, strend - s);
 
        TAINT_IF(rxtainted);
@@ -1675,6 +1697,7 @@ PP(pp_subst)
        (void)SvPOK_only(TARG);
        SvSETMAGIC(TARG);
        SvTAINT(TARG);
+       SPAGAIN;
        PUSHs(sv_2mortal(newSViv((I32)iters)));
        LEAVE_SCOPE(oldsave);
        RETURN;
@@ -1682,9 +1705,10 @@ PP(pp_subst)
     goto ret_no;
 
 nope:
-    ++BmUSEFUL(pm->op_pmshort);
+    ++BmUSEFUL(rx->check_substr);
 
-ret_no:
+ret_no:         
+    SPAGAIN;
     PUSHs(&sv_no);
     LEAVE_SCOPE(oldsave);
     RETURN;
@@ -1692,7 +1716,7 @@ ret_no:
 
 PP(pp_grepwhile)
 {
-    dSP;
+    djSP;
 
     if (SvTRUEx(POPs))
        stack_base[markstack_ptr[-1]++] = stack_base[*markstack_ptr];
@@ -1700,7 +1724,7 @@ PP(pp_grepwhile)
     LEAVE;                                     /* exit inner scope */
 
     /* All done yet? */
-    if (stack_base + *markstack_ptr > sp) {
+    if (stack_base + *markstack_ptr > SP) {
        I32 items;
        I32 gimme = GIMME_V;
 
@@ -1725,7 +1749,7 @@ PP(pp_grepwhile)
 
        src = stack_base[*markstack_ptr];
        SvTEMP_off(src);
-       GvSV(defgv) = src;
+       DEFSV = src;
 
        RETURNOP(cLOGOP->op_other);
     }
@@ -1733,12 +1757,12 @@ PP(pp_grepwhile)
 
 PP(pp_leavesub)
 {
-    dSP;
+    djSP;
     SV **mark;
     SV **newsp;
     PMOP *newpm;
     I32 gimme;
-    register CONTEXT *cx;
+    register PERL_CONTEXT *cx;
     struct block_sub cxsub;
 
     POPBLOCK(cx,newpm);
@@ -1772,13 +1796,41 @@ PP(pp_leavesub)
     return pop_return();
 }
 
+static CV *
+get_db_sub(SV **svp, CV *cv)
+{
+    dTHR;
+    SV *oldsv = *svp;
+    GV *gv;
+
+    *svp = GvSV(DBsub);
+    save_item(*svp);
+    gv = CvGV(cv);
+    if ( (CvFLAGS(cv) & (CVf_ANON | CVf_CLONED))
+        || strEQ(GvNAME(gv), "END") 
+        || ((GvCV(gv) != cv) && /* Could be imported, and old sub redefined. */
+            !( (SvTYPE(oldsv) == SVt_PVGV) && (GvCV((GV*)oldsv) == cv)
+               && (gv = (GV*)oldsv) ))) {
+       /* Use GV from the stack as a fallback. */
+       /* GV is potentially non-unique, or contain different CV. */
+       sv_setsv(*svp, newRV((SV*)cv));
+    }
+    else {
+       gv_efullname3(*svp, gv, Nullch);
+    }
+    cv = GvCV(DBsub);
+    if (CvXSUB(cv))
+       curcopdb = curcop;
+    return cv;
+}
+
 PP(pp_entersub)
 {
-    dSP; dPOPss;
+    djSP; dPOPss;
     GV *gv;
     HV *stash;
     register CV *cv;
-    register CONTEXT *cx;
+    register PERL_CONTEXT *cx;
     I32 gimme;
     bool hasargs = (op->op_flags & OPf_STACKED) != 0;
 
@@ -1789,8 +1841,11 @@ PP(pp_entersub)
        if (!SvROK(sv)) {
            char *sym;
 
-           if (sv == &sv_yes)          /* unfound import, ignore */
+           if (sv == &sv_yes) {                /* unfound import, ignore */
+               if (hasargs)
+                   SP = stack_base + POPMARK;
                RETURN;
+           }
            if (SvGMAGICAL(sv)) {
                mg_get(sv);
                sym = SvPOKp(sv) ? SvPVX(sv) : Nullch;
@@ -1829,7 +1884,7 @@ PP(pp_entersub)
 
     if (!CvROOT(cv) && !CvXSUB(cv)) {
        GV* autogv;
-       SV* subname;
+       SV* sub_name;
 
        /* anonymous or undef'd function leaves us no recourse */
        if (CvANON(cv) || !(gv = CvGV(cv)))
@@ -1847,39 +1902,32 @@ PP(pp_entersub)
            goto retry;
        }
        /* sorry */
-       subname = sv_newmortal();
-       gv_efullname3(subname, gv, Nullch);
-       DIE("Undefined subroutine &%s called", SvPVX(subname));
+       sub_name = sv_newmortal();
+       gv_efullname3(sub_name, gv, Nullch);
+       DIE("Undefined subroutine &%s called", SvPVX(sub_name));
     }
 
     gimme = GIMME_V;
-    if ((op->op_private & OPpENTERSUB_DB) && GvCV(DBsub) && !CvNODEBUG(cv)) {
-       SV *oldsv = sv;
-       sv = GvSV(DBsub);
-       save_item(sv);
-       gv = CvGV(cv);
-       if ( (CvFLAGS(cv) & (CVf_ANON | CVf_CLONED))
-            || strEQ(GvNAME(gv), "END") 
-            || ((GvCV(gv) != cv) && /* Could be imported, and old sub redefined. */
-                !( (SvTYPE(oldsv) == SVt_PVGV) && (GvCV((GV*)oldsv) == cv)
-                   && (gv = (GV*)oldsv) ))) { /* Use GV from the stack as a fallback. */
-           /* GV is potentially non-unique, or contain different CV. */
-           sv_setsv(sv, newRV((SV*)cv));
-       }
-       else {
-           gv_efullname3(sv, gv, Nullch);
-       }
-       cv = GvCV(DBsub);
-       if (CvXSUB(cv)) curcopdb = curcop;
-       if (!cv)
-           DIE("No DBsub routine");
-    }
+    if ((op->op_private & OPpENTERSUB_DB) && GvCV(DBsub) && !CvNODEBUG(cv))
+       cv = get_db_sub(&sv, cv);
+    if (!cv)
+       DIE("No DBsub routine");
 
 #ifdef USE_THREADS
+    /*
+     * First we need to check if the sub or method requires locking.
+     * If so, we gain a lock on the CV, the first argument or the
+     * stash (for static methods), as appropriate. This has to be
+     * inline because for FAKE_THREADS, COND_WAIT inlines code to
+     * reschedule by returning a new op.
+     */
     MUTEX_LOCK(CvMUTEXP(cv));
     if (CvFLAGS(cv) & CVf_LOCKED) {
-       MAGIC *mg;      
-       if (CvFLAGS(cv) & CVf_METHOD) {
+       MAGIC *mg;        
+       if (CvFLAGS(cv) & CVf_PACKAGE) {
+           sv = (SV *) CvGV(cv);
+       }
+       else if (CvFLAGS(cv) & CVf_METHOD) {
            if (SP > stack_base + TOPMARK)
                sv = *(stack_base + TOPMARK + 1);
            else {
@@ -1888,6 +1936,11 @@ PP(pp_entersub)
            }
            if (SvROK(sv))
                sv = SvRV(sv);
+           else {              
+               STRLEN len;
+               char *stashname = SvPV(sv, len);
+               sv = (SV*)gv_stashpvn(stashname, len, TRUE);
+           }
        }
        else {
            sv = (SV*)cv;
@@ -1901,117 +1954,106 @@ PP(pp_entersub)
            while (MgOWNER(mg))
                COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg));
            MgOWNER(mg) = thr;
-           DEBUG_L(PerlIO_printf(PerlIO_stderr(),
-                                 "0x%lx: pp_entersub lock 0x%lx\n",
-                                 (unsigned long)thr, (unsigned long)sv);)
+           DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: pp_entersub lock %p\n",
+                                 thr, sv);)
            MUTEX_UNLOCK(MgMUTEXP(mg));
+           SvREFCNT_inc(sv);   /* Keep alive until magic_mutexfree */
            save_destructor(unlock_condpair, sv);
        }
        MUTEX_LOCK(CvMUTEXP(cv));
-       assert(CvOWNER(cv) == 0);
-       CvOWNER(cv) = thr;      /* Assert ownership */
-       SvREFCNT_inc(cv);
-       MUTEX_UNLOCK(CvMUTEXP(cv));
-       if (CvDEPTH(cv) == 0)
-           SAVEDESTRUCTOR(unset_cvowner, (void*) cv);
     }
+    /*
+     * Now we have permission to enter the sub, we must distinguish
+     * four cases. (0) It's an XSUB (in which case we don't care
+     * about ownership); (1) it's ours already (and we're recursing);
+     * (2) it's free (but we may already be using a cached clone);
+     * (3) another thread owns it. Case (1) is easy: we just use it.
+     * Case (2) means we look for a clone--if we have one, use it
+     * otherwise grab ownership of cv. Case (3) means we look for a
+     * clone (for non-XSUBs) and have to create one if we don't
+     * already have one.
+     * Why look for a clone in case (2) when we could just grab
+     * ownership of cv straight away? Well, we could be recursing,
+     * i.e. we originally tried to enter cv while another thread
+     * owned it (hence we used a clone) but it has been freed up
+     * and we're now recursing into it. It may or may not be "better"
+     * to use the clone but at least CvDEPTH can be trusted.
+     */
+    if (CvOWNER(cv) == thr || CvXSUB(cv))
+       MUTEX_UNLOCK(CvMUTEXP(cv));
     else {
+       /* Case (2) or (3) */
+       SV **svp;
+       
        /*
-        * It's an ordinary unsynchronised CV so we must distinguish
-        * three cases. (1) It's ours already (and we're recursing);
-        * (2) it's free (but we may already be using a cached clone);
-        * (3) another thread owns it. Case (1) is easy: we just use it.
-        * Case (2) means we look for a clone--if we have one, use it
-        * otherwise grab ownership of cv. Case (3) means look we for a
-        * clone and have to create one if we don't already have one.
-        * Why look for a clone in case (2) when we could just grab
-        * ownership of cv straight away? Well, we could be recursing,
-        * i.e. we originally tried to enter cv while another thread
-        * owned it (hence we used a clone) but it has been freed up
-        * and we're now recursing into it. It may or may not be "better"
-        * to use the clone but at least CvDEPTH can be trusted.
-        */
-       if (CvOWNER(cv) == thr)
+        * XXX Might it be better to release CvMUTEXP(cv) while we
+        * do the hv_fetch? We might find someone has pinched it
+        * when we look again, in which case we would be in case
+        * (3) instead of (2) so we'd have to clone. Would the fact
+        * that we released the mutex more quickly make up for this?
+        */
+       svp = hv_fetch(thr->cvcache, (char *)cv, sizeof(cv), FALSE);
+       if (svp) {
+           /* We already have a clone to use */
            MUTEX_UNLOCK(CvMUTEXP(cv));
+           cv = *(CV**)svp;
+           DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+                                 "entersub: %p already has clone %p:%s\n",
+                                 thr, cv, SvPEEK((SV*)cv)));
+           CvOWNER(cv) = thr;
+           SvREFCNT_inc(cv);
+           if (CvDEPTH(cv) == 0)
+               SAVEDESTRUCTOR(unset_cvowner, (void*) cv);
+       }
        else {
-           /* Case (2) or (3) */
-           SV **svp;
-           
-           /*
-            * XXX Might it be better to release CvMUTEXP(cv) while we
-            * do the hv_fetch? We might find someone has pinched it
-            * when we look again, in which case we would be in case
-            * (3) instead of (2) so we'd have to clone. Would the fact
-            * that we released the mutex more quickly make up for this?
-            */
-           svp = hv_fetch(cvcache, (char *)cv, sizeof(cv), FALSE);
-           if (svp) {
-               /* We already have a clone to use */
+           /* (2) => grab ownership of cv. (3) => make clone */
+           if (!CvOWNER(cv)) {
+               CvOWNER(cv) = thr;
+               SvREFCNT_inc(cv);
                MUTEX_UNLOCK(CvMUTEXP(cv));
-               cv = *(CV**)svp;
                DEBUG_L(PerlIO_printf(PerlIO_stderr(),
-                               "entersub: 0x%lx already has clone 0x%lx:%s\n",
-                               (unsigned long) thr, (unsigned long) cv,
-                               SvPEEK((SV*)cv)));
-               CvOWNER(cv) = thr;
+                           "entersub: %p grabbing %p:%s in stash %s\n",
+                           thr, cv, SvPEEK((SV*)cv), CvSTASH(cv) ?
+                               HvNAME(CvSTASH(cv)) : "(none)"));
+           } else {
+               /* Make a new clone. */
+               CV *clonecv;
+               SvREFCNT_inc(cv); /* don't let it vanish from under us */
+               MUTEX_UNLOCK(CvMUTEXP(cv));
+               DEBUG_L((PerlIO_printf(PerlIO_stderr(),
+                                      "entersub: %p cloning %p:%s\n",
+                                      thr, cv, SvPEEK((SV*)cv))));
+               /*
+                * We're creating a new clone so there's no race
+                * between the original MUTEX_UNLOCK and the
+                * SvREFCNT_inc since no one will be trying to undef
+                * it out from underneath us. At least, I don't think
+                * there's a race...
+                */
+               clonecv = cv_clone(cv);
+               SvREFCNT_dec(cv); /* finished with this */
+               hv_store(thr->cvcache, (char*)cv, sizeof(cv), (SV*)clonecv,0);
+               CvOWNER(clonecv) = thr;
+               cv = clonecv;
                SvREFCNT_inc(cv);
-               if (CvDEPTH(cv) == 0)
-                   SAVEDESTRUCTOR(unset_cvowner, (void*) cv);
-           }
-           else {
-               /* (2) => grab ownership of cv. (3) => make clone */
-               if (!CvOWNER(cv)) {
-                   CvOWNER(cv) = thr;
-                   SvREFCNT_inc(cv);
-                   MUTEX_UNLOCK(CvMUTEXP(cv));
-                   DEBUG_L(PerlIO_printf(PerlIO_stderr(),
-                                   "entersub: 0x%lx grabbing 0x%lx:%s in stash %s\n",
-                                   (unsigned long) thr, (unsigned long) cv,
-                                   SvPEEK((SV*)cv), CvSTASH(cv) ?
-                                       HvNAME(CvSTASH(cv)) : "(none)"));
-               } else {
-                   /* Make a new clone. */
-                   CV *clonecv;
-                   SvREFCNT_inc(cv); /* don't let it vanish from under us */
-                   MUTEX_UNLOCK(CvMUTEXP(cv));
-                   DEBUG_L((PerlIO_printf(PerlIO_stderr(),
-                                    "entersub: 0x%lx cloning 0x%lx:%s\n",
-                                    (unsigned long) thr, (unsigned long) cv,
-                                    SvPEEK((SV*)cv))));
-                   /*
-                    * We're creating a new clone so there's no race
-                    * between the original MUTEX_UNLOCK and the
-                    * SvREFCNT_inc since no one will be trying to undef
-                    * it out from underneath us. At least, I don't think
-                    * there's a race...
-                    */
-                   clonecv = cv_clone(cv);
-                   SvREFCNT_dec(cv); /* finished with this */
-                   hv_store(cvcache, (char*)cv, sizeof(cv), (SV*)clonecv,0);
-                   CvOWNER(clonecv) = thr;
-                   cv = clonecv;
-                   SvREFCNT_inc(cv);
-               }
-               DEBUG_L(if (CvDEPTH(cv) != 0)
-                           PerlIO_printf(PerlIO_stderr(), "depth %ld != 0\n",
-                                         CvDEPTH(cv)););
-               SAVEDESTRUCTOR(unset_cvowner, (void*) cv);
            }
+           DEBUG_L(if (CvDEPTH(cv) != 0)
+                       PerlIO_printf(PerlIO_stderr(), "depth %ld != 0\n",
+                                     CvDEPTH(cv)););
+           SAVEDESTRUCTOR(unset_cvowner, (void*) cv);
        }
-    }  
+    }
 #endif /* USE_THREADS */
 
-    gimme = GIMME;
-
     if (CvXSUB(cv)) {
        if (CvOLDSTYLE(cv)) {
            I32 (*fp3)_((int,int,int));
            dMARK;
            register I32 items = SP - MARK;
                                        /* We dont worry to copy from @_. */
-           while (sp > mark) {
-               sp[1] = sp[0];
-               sp--;
+           while (SP > mark) {
+               SP[1] = SP[0];
+               SP--;
            }
            stack_sp = mark + 1;
            fp3 = (I32(*)_((int,int,int)))CvXSUB(cv);
@@ -2036,13 +2078,13 @@ PP(pp_entersub)
 #else
                av = GvAV(defgv);
 #endif /* USE_THREADS */               
-               items = AvFILL(av) + 1;
+               items = AvFILLp(av) + 1;   /* @_ is not tieable */
 
                if (items) {
                    /* Mark is at the end of the stack. */
-                   EXTEND(sp, items);
-                   Copy(AvARRAY(av), sp + 1, items, SV*);
-                   sp += items;
+                   EXTEND(SP, items);
+                   Copy(AvARRAY(av), SP + 1, items, SV*);
+                   SP += items;
                    PUTBACK ;               
                }
            }
@@ -2083,11 +2125,11 @@ PP(pp_entersub)
            if (CvDEPTH(cv) == 100 && dowarn 
                  && !(PERLDB_SUB && cv == GvCV(DBsub)))
                sub_crush_depth(cv);
-           if (CvDEPTH(cv) > AvFILL(padlist)) {
+           if (CvDEPTH(cv) > AvFILLp(padlist)) {
                AV *av;
                AV *newpad = newAV();
                SV **oldpad = AvARRAY(svp[CvDEPTH(cv)-1]);
-               I32 ix = AvFILL((AV*)svp[1]);
+               I32 ix = AvFILLp((AV*)svp[1]);
                svp = AvARRAY(svp[0]);
                for ( ;ix > 0; ix--) {
                    if (svp[ix] != &sv_undef) {
@@ -2117,7 +2159,7 @@ PP(pp_entersub)
                av_store(newpad, 0, (SV*)av);
                AvFLAGS(av) = AVf_REIFY;
                av_store(padlist, CvDEPTH(cv), (SV*)newpad);
-               AvFILL(padlist) = CvDEPTH(cv);
+               AvFILLp(padlist) = CvDEPTH(cv);
                svp = AvARRAY(padlist);
            }
        }
@@ -2125,12 +2167,12 @@ PP(pp_entersub)
        if (!hasargs) {
            AV* av = (AV*)curpad[0];
 
-           items = AvFILL(av) + 1;
+           items = AvFILLp(av) + 1;
            if (items) {
                /* Mark is at the end of the stack. */
-               EXTEND(sp, items);
-               Copy(AvARRAY(av), sp + 1, items, SV*);
-               sp += items;
+               EXTEND(SP, items);
+               Copy(AvARRAY(av), SP + 1, items, SV*);
+               SP += items;
                PUTBACK ;                   
            }
        }
@@ -2174,7 +2216,7 @@ PP(pp_entersub)
                }
            }
            Copy(MARK,AvARRAY(av),items,SV*);
-           AvFILL(av) = items - 1;
+           AvFILLp(av) = items - 1;
            
            while (items--) {
                if (*MARK)
@@ -2191,8 +2233,7 @@ PP(pp_entersub)
 }
 
 void
-sub_crush_depth(cv)
-CV* cv;
+sub_crush_depth(CV *cv)
 {
     if (CvANON(cv))
        warn("Deep recursion on anonymous subroutine");
@@ -2205,7 +2246,7 @@ CV* cv;
 
 PP(pp_aelem)
 {
-    dSP;
+    djSP;
     SV** svp;
     I32 elem = POPi;
     AV* av = (AV*)POPs;
@@ -2233,7 +2274,7 @@ PP(pp_aelem)
            RETURN;
        }
        if (op->op_private & OPpLVAL_INTRO)
-           save_svref(svp);
+           save_aelem(av, elem, svp);
        else if (op->op_private & OPpDEREF)
            vivify_ref(*svp, op->op_private & OPpDEREF);
     }
@@ -2242,9 +2283,7 @@ PP(pp_aelem)
 }
 
 void
-vivify_ref(sv, to_what)
-SV* sv;
-U32 to_what;
+vivify_ref(SV *sv, U32 to_what)
 {
     if (SvGMAGICAL(sv))
        mg_get(sv);
@@ -2260,7 +2299,7 @@ U32 to_what;
        }
        switch (to_what) {
        case OPpDEREF_SV:
-           SvRV(sv) = newSV(0);
+           SvRV(sv) = NEWSV(355,0);
            break;
        case OPpDEREF_AV:
            SvRV(sv) = (SV*)newAV();
@@ -2276,7 +2315,7 @@ U32 to_what;
 
 PP(pp_method)
 {
-    dSP;
+    djSP;
     SV* sv;
     SV* ob;
     GV* gv;
@@ -2285,6 +2324,14 @@ PP(pp_method)
     char* packname;
     STRLEN packlen;
 
+    if (SvROK(TOPs)) {
+       sv = SvRV(TOPs);
+       if (SvTYPE(sv) == SVt_PVCV) {
+           SETs(sv);
+           RETURN;
+       }
+    }
+
     name = SvPV(TOPs, na);
     sv = *(stack_base + TOPMARK + 1);
     
@@ -2341,3 +2388,4 @@ PP(pp_method)
     SETs(isGV(gv) ? (SV*)GvCV(gv) : (SV*)gv);
     RETURN;
 }
+