This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
make die/warn and other diagnostics go to wherever STDERR happens
[perl5.git] / pp_hot.c
index 5fa2bef..a25f000 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -16,6 +16,7 @@
  */
 
 #include "EXTERN.h"
+#define PERL_IN_PP_HOT_C
 #include "perl.h"
 
 #ifdef I_UNISTD
 /* Hot code. */
 
 #ifdef USE_THREADS
-static void
-unset_cvowner(void *cvarg)
-{
-    register CV* cv = (CV *) cvarg;
-#ifdef DEBUGGING
-    dTHR;
-#endif /* DEBUGGING */
-
-    DEBUG_S((PerlIO_printf(PerlIO_stderr(), "%p unsetting CvOWNER of %p:%s\n",
-                          thr, cv, SvPEEK((SV*)cv))));
-    MUTEX_LOCK(CvMUTEXP(cv));
-    DEBUG_S(if (CvDEPTH(cv) != 0)
-               PerlIO_printf(PerlIO_stderr(), "depth %ld != 0\n",
-                             CvDEPTH(cv)););
-    assert(thr == CvOWNER(cv));
-    CvOWNER(cv) = 0;
-    MUTEX_UNLOCK(CvMUTEXP(cv));
-    SvREFCNT_dec(cv);
-}
+static void unset_cvowner(pTHXo_ void *cvarg);
 #endif /* USE_THREADS */
 
 PP(pp_const)
@@ -86,6 +69,12 @@ PP(pp_null)
     return NORMAL;
 }
 
+PP(pp_setstate)
+{
+    PL_curcop = (COP*)PL_op;
+    return NORMAL;
+}
+
 PP(pp_pushmark)
 {
     PUSHMARK(PL_stack_sp);
@@ -141,9 +130,9 @@ PP(pp_cond_expr)
 {
     djSP;
     if (SvTRUEx(POPs))
-       RETURNOP(cCONDOP->op_true);
+       RETURNOP(cLOGOP->op_other);
     else
-       RETURNOP(cCONDOP->op_false);
+       RETURNOP(cLOGOP->op_next);
 }
 
 PP(pp_unstack)
@@ -175,8 +164,21 @@ PP(pp_concat)
        s = SvPV_force(TARG, len);
     }
     s = SvPV(right,len);
-    if (SvOK(TARG))
+    if (SvOK(TARG)) {
+#if defined(PERL_Y2KWARN)
+       if ((SvIOK(right) || SvNOK(right)) && ckWARN(WARN_MISC)) {
+           STRLEN n;
+           char *s = SvPV(TARG,n);
+           if (n >= 2 && s[n-2] == '1' && s[n-1] == '9'
+               && (n == 2 || !isDIGIT(s[n-3])))
+           {
+               Perl_warner(aTHX_ WARN_MISC, "Possible Y2K bug: %s",
+                           "about to append an integer to '19'");
+           }
+       }
+#endif
        sv_catpvn(TARG,s,len);
+    }
     else
        sv_setpvn(TARG,s,len);  /* suppress warning */
     SETTARG;
@@ -211,7 +213,7 @@ PP(pp_readline)
            dSP;
            XPUSHs((SV*)PL_last_in_gv);
            PUTBACK;
-           pp_rv2gv(ARGS);
+           pp_rv2gv();
            PL_last_in_gv = (GV*)(*PL_stack_sp--);
        }
     }
@@ -232,7 +234,7 @@ PP(pp_preinc)
 {
     djSP;
     if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
-       croak(PL_no_modify);
+       DIE(aTHX_ PL_no_modify);
     if (SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
        SvIVX(TOPs) != IV_MAX)
     {
@@ -338,7 +340,7 @@ PP(pp_print)
        *MARK = SvTIED_obj((SV*)gv, mg);
        PUTBACK;
        ENTER;
-       perl_call_method("PRINT", G_SCALAR);
+       call_method("PRINT", G_SCALAR);
        LEAVE;
        SPAGAIN;
        MARK = ORIGMARK + 1;
@@ -349,23 +351,24 @@ PP(pp_print)
     if (!(io = GvIO(gv))) {
        if (ckWARN(WARN_UNOPENED)) {
            SV* sv = sv_newmortal();
-            gv_fullname3(sv, gv, Nullch);
-            warner(WARN_UNOPENED, "Filehandle %s never opened", SvPV(sv,n_a));
+           gv_efullname3(sv, gv, Nullch);
+            Perl_warner(aTHX_ WARN_UNOPENED, "Filehandle %s never opened",
+                       SvPV(sv,n_a));
         }
-
        SETERRNO(EBADF,RMS$_IFI);
        goto just_say_no;
     }
     else if (!(fp = IoOFP(io))) {
        if (ckWARN2(WARN_CLOSED, WARN_IO))  {
            SV* sv = sv_newmortal();
-            gv_fullname3(sv, gv, Nullch);
+           gv_efullname3(sv, gv, Nullch);
            if (IoIFP(io))
-               warner(WARN_IO, "Filehandle %s opened only for input", 
-                               SvPV(sv,n_a));
+               Perl_warner(aTHX_ WARN_IO,
+                           "Filehandle %s opened only for input",
+                           SvPV(sv,n_a));
            else if (ckWARN(WARN_CLOSED))
-               warner(WARN_CLOSED, "print on closed filehandle %s", 
-                               SvPV(sv,n_a));
+               Perl_warner(aTHX_ WARN_CLOSED,
+                           "print on closed filehandle %s", SvPV(sv,n_a));
        }
        SETERRNO(EBADF,IoIFP(io)?RMS$_FAC:RMS$_IFI);
        goto just_say_no;
@@ -425,7 +428,7 @@ PP(pp_rv2av)
 
        av = (AV*)SvRV(sv);
        if (SvTYPE(av) != SVt_PVAV)
-           DIE("Not an ARRAY reference");
+           DIE(aTHX_ "Not an ARRAY reference");
        if (PL_op->op_flags & OPf_REF) {
            SETs((SV*)av);
            RETURN;
@@ -454,9 +457,9 @@ PP(pp_rv2av)
                if (!SvOK(sv)) {
                    if (PL_op->op_flags & OPf_REF ||
                      PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(PL_no_usym, "an ARRAY");
+                       DIE(aTHX_ PL_no_usym, "an ARRAY");
                    if (ckWARN(WARN_UNINITIALIZED))
-                       warner(WARN_UNINITIALIZED, PL_warn_uninit);
+                       Perl_warner(aTHX_ WARN_UNINITIALIZED, PL_warn_uninit);
                    if (GIMME == G_ARRAY) {
                        (void)POPs;
                        RETURN;
@@ -473,7 +476,7 @@ PP(pp_rv2av)
                }
                else {
                    if (PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(PL_no_symref, sym, "an ARRAY");
+                       DIE(aTHX_ PL_no_symref, sym, "an ARRAY");
                    gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PVAV);
                }
            }
@@ -525,7 +528,7 @@ PP(pp_rv2hv)
 
        hv = (HV*)SvRV(sv);
        if (SvTYPE(hv) != SVt_PVHV && SvTYPE(hv) != SVt_PVAV)
-           DIE("Not a HASH reference");
+           DIE(aTHX_ "Not a HASH reference");
        if (PL_op->op_flags & OPf_REF) {
            SETs((SV*)hv);
            RETURN;
@@ -554,9 +557,9 @@ PP(pp_rv2hv)
                if (!SvOK(sv)) {
                    if (PL_op->op_flags & OPf_REF ||
                      PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(PL_no_usym, "a HASH");
+                       DIE(aTHX_ PL_no_usym, "a HASH");
                    if (ckWARN(WARN_UNINITIALIZED))
-                       warner(WARN_UNINITIALIZED, PL_warn_uninit);
+                       Perl_warner(aTHX_ WARN_UNINITIALIZED, PL_warn_uninit);
                    if (GIMME == G_ARRAY) {
                        SP--;
                        RETURN;
@@ -573,7 +576,7 @@ PP(pp_rv2hv)
                }
                else {
                    if (PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(PL_no_symref, sym, "a HASH");
+                       DIE(aTHX_ PL_no_symref, sym, "a HASH");
                    gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PVHV);
                }
            }
@@ -592,15 +595,21 @@ PP(pp_rv2hv)
 
     if (GIMME == G_ARRAY) { /* array wanted */
        *PL_stack_sp = (SV*)hv;
-       return do_kv(ARGS);
+       return do_kv();
     }
     else {
        dTARGET;
        if (SvTYPE(hv) == SVt_PVAV)
            hv = avhv_keys((AV*)hv);
+#ifdef IV_IS_QUAD
        if (HvFILL(hv))
-           sv_setpvf(TARG, "%ld/%ld",
-                     (long)HvFILL(hv), (long)HvMAX(hv) + 1);
+            Perl_sv_setpvf(aTHX_ TARG, "%" PERL_PRId64 "/%" PERL_PRId64,
+                      (Quad_t)HvFILL(hv), (Quad_t)HvMAX(hv) + 1);
+#else
+       if (HvFILL(hv))
+            Perl_sv_setpvf(aTHX_ TARG, "%ld/%ld",
+                      (long)HvFILL(hv), (long)HvMAX(hv) + 1);
+#endif
        else
            sv_setiv(TARG, 0);
        
@@ -710,9 +719,9 @@ PP(pp_aassign)
                                SvROK(*relem) &&
                                ( SvTYPE(SvRV(*relem)) == SVt_PVAV ||
                                  SvTYPE(SvRV(*relem)) == SVt_PVHV ) )
-                               warner(WARN_UNSAFE, "Reference found where even-sized list expected");
+                               Perl_warner(aTHX_ WARN_UNSAFE, "Reference found where even-sized list expected");
                            else
-                               warner(WARN_UNSAFE, "Odd number of elements in hash assignment");
+                               Perl_warner(aTHX_ WARN_UNSAFE, "Odd number of elements in hash assignment");
                        }
                        tmpstr = NEWSV(29,0);
                        didstore = hv_store_ent(hash,*relem,tmpstr,0);
@@ -766,13 +775,13 @@ PP(pp_aassign)
 #    endif /* HAS_SETEUID */
            if (PL_delaymagic & DM_UID) {
                if (PL_uid != PL_euid)
-                   DIE("No setreuid available");
+                   DIE(aTHX_ "No setreuid available");
                (void)PerlProc_setuid(PL_uid);
            }
 #  endif /* HAS_SETREUID */
 #endif /* HAS_SETRESUID */
-           PL_uid = (int)PerlProc_getuid();
-           PL_euid = (int)PerlProc_geteuid();
+           PL_uid = PerlProc_getuid();
+           PL_euid = PerlProc_geteuid();
        }
        if (PL_delaymagic & DM_GID) {
 #ifdef HAS_SETRESGID
@@ -795,13 +804,13 @@ PP(pp_aassign)
 #    endif /* HAS_SETEGID */
            if (PL_delaymagic & DM_GID) {
                if (PL_gid != PL_egid)
-                   DIE("No setregid available");
+                   DIE(aTHX_ "No setregid available");
                (void)PerlProc_setgid(PL_gid);
            }
 #  endif /* HAS_SETREGID */
 #endif /* HAS_SETRESGID */
-           PL_gid = (int)PerlProc_getgid();
-           PL_egid = (int)PerlProc_getegid();
+           PL_gid = PerlProc_getgid();
+           PL_egid = PerlProc_getegid();
        }
        PL_tainting |= (PL_uid && (PL_euid != PL_uid || PL_egid != PL_gid));
     }
@@ -845,8 +854,8 @@ PP(pp_match)
     register char *s;
     char *strend;
     I32 global;
-    I32 r_flags = 0;
-    char *truebase;
+    I32 r_flags = REXEC_CHECKED;
+    char *truebase;                    /* Start of string  */
     register REGEXP *rx = pm->op_pmregexp;
     bool rxtainted;
     I32 gimme = GIMME;
@@ -866,7 +875,7 @@ PP(pp_match)
     s = SvPV(TARG, len);
     strend = s + len;
     if (!s)
-       DIE("panic: do_match");
+       DIE(aTHX_ "panic: do_match");
     rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
                 (PL_tainted && (pm->op_pmflags & PMf_RETAINT)));
     TAINT_NOT;
@@ -888,15 +897,15 @@ PP(pp_match)
 
     /* XXXX What part of this is needed with true \G-support? */
     if (global = pm->op_pmflags & PMf_GLOBAL) {
-       rx->startp[0] = 0;
+       rx->startp[0] = -1;
        if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
            MAGIC* mg = mg_find(TARG, 'g');
            if (mg && mg->mg_len >= 0) {
                if (!(rx->reganch & ROPT_GPOS_SEEN))
-                   rx->endp[0] = rx->startp[0] = s + mg->mg_len; 
+                   rx->endp[0] = rx->startp[0] = mg->mg_len; 
                else if (rx->reganch & ROPT_ANCH_GPOS) {
                    r_flags |= REXEC_IGNOREPOS;
-                   rx->endp[0] = rx->startp[0] = s + mg->mg_len; 
+                   rx->endp[0] = rx->startp[0] = mg->mg_len; 
                }
                minmatch = (mg->mg_flags & MGf_MINMATCH);
                update_minmatch = 0;
@@ -906,9 +915,7 @@ PP(pp_match)
     if ((gimme != G_ARRAY && !global && rx->nparens)
            || SvTEMP(TARG) || PL_sawampersand)
        r_flags |= REXEC_COPY_STR;
-    if (SvSCREAM(TARG) && rx->check_substr
-       && SvTYPE(rx->check_substr) == SVt_PVBM
-       && SvVALID(rx->check_substr)) 
+    if (SvSCREAM(TARG)) 
        r_flags |= REXEC_SCREAM;
 
     if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
@@ -917,61 +924,26 @@ PP(pp_match)
     }
 
 play_it_again:
-    if (global && rx->startp[0]) {
-       t = s = rx->endp[0];
+    if (global && rx->startp[0] != -1) {
+       t = s = rx->endp[0] + truebase;
        if ((s + rx->minlen) > strend)
            goto nope;
        if (update_minmatch++)
            minmatch = had_zerolen;
     }
-    if (rx->check_substr) {
-       if (!(rx->reganch & ROPT_NOSCAN)) { /* Floating checkstring. */
-           if (r_flags & REXEC_SCREAM) {
-               I32 p = -1;
-               char *b;
-               
-               if (PL_screamfirst[BmRARE(rx->check_substr)] < 0)
-                   goto nope;
-
-               b = (char*)HOP((U8*)s, rx->check_offset_min);
-               if (!(s = screaminstr(TARG, rx->check_substr, b - s, 0, &p, 0)))
-                   goto nope;
-
-               if ((rx->reganch & ROPT_CHECK_ALL)
-                        && !PL_sawampersand && !SvTAIL(rx->check_substr))
-                   goto yup;
-           }
-           else if (!(s = fbm_instr((unsigned char*)HOP((U8*)s, rx->check_offset_min),
-                                    (unsigned char*)strend, 
-                                    rx->check_substr, 0)))
-               goto nope;
-           else if ((rx->reganch & ROPT_CHECK_ALL) && !PL_sawampersand)
-               goto yup;
-           if (s && rx->check_offset_max < s - t) {
-               ++BmUSEFUL(rx->check_substr);
-               s = (char*)HOP((U8*)s, -rx->check_offset_max);
-           }
-           else
-               s = t;
-       }
-       /* Now checkstring is fixed, i.e. at fixed offset from the
-          beginning of match, and the match is anchored at s. */
-       else if (!PL_multiline) {       /* Anchored near beginning of string. */
-           I32 slen;
-           char *b = (char*)HOP((U8*)s, rx->check_offset_min);
-           if (*SvPVX(rx->check_substr) != *b
-               || ((slen = SvCUR(rx->check_substr)) > 1
-                   && memNE(SvPVX(rx->check_substr), b, slen)))
-               goto nope;
-       }
-       if (!(rx->reganch & ROPT_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 (CALLREGEXEC(rx, s, strend, truebase, minmatch, TARG, NULL, r_flags))
+    if (rx->reganch & RE_USE_INTUIT) {
+       s = CALLREG_INTUIT_START(aTHX_ rx, TARG, s, strend, r_flags, NULL);
+
+       if (!s)
+           goto nope;
+       if ( (rx->reganch & ROPT_CHECK_ALL)
+            && !PL_sawampersand 
+            && ((rx->reganch & ROPT_NOSCAN)
+                || !((rx->reganch & RE_INTUIT_TAIL)
+                     && (r_flags & REXEC_SCREAM))))
+           goto yup;
+    }
+    if (CALLREGEXEC(aTHX_ rx, s, strend, truebase, minmatch, TARG, NULL, r_flags))
     {
        PL_curpm = pm;
        if (pm->op_pmflags & PMf_ONCE)
@@ -1000,17 +972,17 @@ play_it_again:
        for (i = !i; i <= iters; i++) {
            PUSHs(sv_newmortal());
            /*SUPPRESS 560*/
-           if ((s = rx->startp[i]) && rx->endp[i] ) {
-               len = rx->endp[i] - s;
+           if ((rx->startp[i] != -1) && rx->endp[i] != -1 ) {
+               len = rx->endp[i] - rx->startp[i];
+               s = rx->startp[i] + truebase;
                sv_setpvn(*SP, s, len);
            }
        }
        if (global) {
-           truebase = rx->subbeg;
-           strend = rx->subend;
-           had_zerolen = (rx->startp[0] && rx->startp[0] == rx->endp[0]);
+           had_zerolen = (rx->startp[0] != -1
+                          && rx->startp[0] == rx->endp[0]);
            PUTBACK;                    /* EVAL blocks may use stack */
-           r_flags |= REXEC_IGNOREPOS;
+           r_flags |= REXEC_IGNOREPOS | REXEC_NOT_FIRST;
            goto play_it_again;
        }
        else if (!iters)
@@ -1027,8 +999,8 @@ play_it_again:
                sv_magic(TARG, (SV*)0, 'g', Nullch, 0);
                mg = mg_find(TARG, 'g');
            }
-           if (rx->startp[0]) {
-               mg->mg_len = rx->endp[0] - rx->subbeg;
+           if (rx->startp[0] != -1) {
+               mg->mg_len = rx->endp[0];
                if (rx->startp[0] == rx->endp[0])
                    mg->mg_flags |= MGf_MINMATCH;
                else
@@ -1039,39 +1011,41 @@ play_it_again:
        RETPUSHYES;
     }
 
-yup:                                   /* Confirmed by check_substr */
+yup:                                   /* Confirmed by INTUIT */
     if (rxtainted)
        RX_MATCH_TAINTED_on(rx);
     TAINT_IF(RX_MATCH_TAINTED(rx));
-    ++BmUSEFUL(rx->check_substr);
     PL_curpm = pm;
     if (pm->op_pmflags & PMf_ONCE)
        pm->op_pmdynflags |= PMdf_USED;
-    Safefree(rx->subbase);
-    rx->subbase = Nullch;
+    if (RX_MATCH_COPIED(rx))
+       Safefree(rx->subbeg);
+    RX_MATCH_COPIED_off(rx);
+    rx->subbeg = Nullch;
     if (global) {
        rx->subbeg = truebase;
-       rx->subend = strend;
-       rx->startp[0] = s;
-       rx->endp[0] = s + SvCUR(rx->check_substr);
+       rx->startp[0] = s - truebase;
+       rx->endp[0] = s - truebase + rx->minlen;
+       rx->sublen = strend - truebase;
        goto gotcha;
-    }
+    } 
     if (PL_sawampersand) {
-       char *tmps;
+       I32 off;
 
-       tmps = rx->subbase = savepvn(t, strend-t);
-       rx->subbeg = tmps;
-       rx->subend = tmps + (strend-t);
-       tmps = rx->startp[0] = tmps + (s - t);
-       rx->endp[0] = tmps + SvCUR(rx->check_substr);
+       rx->subbeg = savepvn(t, strend - t);
+       rx->sublen = strend - t;
+       RX_MATCH_COPIED_on(rx);
+       off = rx->startp[0] = s - t;
+       rx->endp[0] = off + rx->minlen;
+    }
+    else {                     /* startp/endp are used by @- @+. */
+       rx->startp[0] = s - truebase;
+       rx->endp[0] = s - truebase + rx->minlen;
     }
     LEAVE_SCOPE(oldsave);
     RETPUSHYES;
 
 nope:
-    if (rx->check_substr)
-       ++BmUSEFUL(rx->check_substr);
-
 ret_no:
     if (global && !(pm->op_pmflags & PMf_CONTINUE)) {
        if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
@@ -1087,7 +1061,7 @@ ret_no:
 }
 
 OP *
-do_readline(void)
+Perl_do_readline(pTHX)
 {
     dSP; dTARGETSTACKED;
     register SV *sv;
@@ -1104,7 +1078,7 @@ do_readline(void)
        XPUSHs(SvTIED_obj((SV*)PL_last_in_gv, mg));
        PUTBACK;
        ENTER;
-       perl_call_method("READLINE", gimme);
+       call_method("READLINE", gimme);
        LEAVE;
        SPAGAIN;
        if (gimme == G_SCALAR)
@@ -1232,15 +1206,9 @@ do_readline(void)
                sv_setpv(tmpcmd, "/dev/dosglob/"); /* File System Extension */
                sv_catsv(tmpcmd, tmpglob);
 #else
-#ifdef CYGWIN32
-               sv_setpv(tmpcmd, "for a in ");
-               sv_catsv(tmpcmd, tmpglob);
-               sv_catpv(tmpcmd, "; do echo -e \"$a\\0\\c\"; done |");
-#else
                sv_setpv(tmpcmd, "perlglob ");
                sv_catsv(tmpcmd, tmpglob);
                sv_catpv(tmpcmd, " |");
-#endif /* !CYGWIN */
 #endif /* !DJGPP */
 #endif /* !OS2 */
 #else /* !DOSISH */
@@ -1268,11 +1236,30 @@ do_readline(void)
        }
        else if (type == OP_GLOB)
            SP--;
+       else if (ckWARN(WARN_IO)        /* stdout/stderr or other write fh */
+                && (IoTYPE(io) == '>' || fp == PerlIO_stdout()
+                    || fp == PerlIO_stderr()))
+       {
+           SV* sv = sv_newmortal();
+           gv_efullname3(sv, PL_last_in_gv, Nullch);
+           Perl_warner(aTHX_ WARN_IO, "Filehandle %s opened only for output",
+                       SvPV_nolen(sv));
+       }
     }
     if (!fp) {
-       if (ckWARN(WARN_CLOSED) && io && !(IoFLAGS(io) & IOf_START))
-           warner(WARN_CLOSED,
-                  "Read on closed filehandle <%s>", GvENAME(PL_last_in_gv));
+       if (ckWARN(WARN_CLOSED) && io && !(IoFLAGS(io) & IOf_START)) {
+           if (type == OP_GLOB)
+               Perl_warner(aTHX_ WARN_CLOSED,
+                           "glob failed (can't start child: %s)",
+                           Strerror(errno));
+           else {
+               SV* sv = sv_newmortal();
+               gv_efullname3(sv, PL_last_in_gv, Nullch);
+               Perl_warner(aTHX_ WARN_CLOSED,
+                           "Read on closed filehandle %s",
+                           SvPV_nolen(sv));
+           }
+       }
        if (gimme == G_SCALAR) {
            (void)SvOK_off(TARG);
            PUSHTARG;
@@ -1319,7 +1306,7 @@ do_readline(void)
            }
            else if (type == OP_GLOB) {
                if (!do_close(PL_last_in_gv, FALSE) && ckWARN(WARN_CLOSED)) {
-                   warner(WARN_CLOSED,
+                   Perl_warner(aTHX_ WARN_CLOSED,
                           "glob failed (child exited with status %d%s)",
                           STATUS_CURRENT >> 8,
                           (STATUS_CURRENT & 0x80) ? ", core dumped" : "");
@@ -1353,7 +1340,7 @@ do_readline(void)
                if (!isALPHA(*tmps) && !isDIGIT(*tmps) &&
                    strchr("$&*(){}[]'\";\\|?<>~`", *tmps))
                        break;
-           if (*tmps && PerlLIO_stat(SvPVX(sv), &PL_statbuf) < 0) {
+           if (*tmps && PerlLIO_lstat(SvPVX(sv), &PL_statbuf) < 0) {
                (void)POPs;             /* Unmatched wildcard?  Chuck it... */
                continue;
            }
@@ -1416,7 +1403,7 @@ PP(pp_helem)
     }
     else if (SvTYPE(hv) == SVt_PVAV) {
        if (PL_op->op_private & OPpLVAL_INTRO)
-           DIE("Can't localize pseudo-hash element");
+           DIE(aTHX_ "Can't localize pseudo-hash element");
        svp = avhv_fetch_ent((AV*)hv, keysv, lval && !defer, 0);
     }
     else {
@@ -1428,7 +1415,7 @@ PP(pp_helem)
            SV* key2;
            if (!defer) {
                STRLEN n_a;
-               DIE(PL_no_helem, SvPV(keysv, n_a));
+               DIE(aTHX_ PL_no_helem, SvPV(keysv, n_a));
            }
            lv = sv_newmortal();
            sv_upgrade(lv, SVt_PVLV);
@@ -1528,7 +1515,7 @@ PP(pp_iter)
     EXTEND(SP, 1);
     cx = &cxstack[cxstack_ix];
     if (CxTYPE(cx) != CXt_LOOP)
-       DIE("panic: pp_iter");
+       DIE(aTHX_ "panic: pp_iter");
 
     av = cx->blk_loop.iterary;
     if (SvTYPE(av) != SVt_PVAV) {
@@ -1614,7 +1601,7 @@ PP(pp_iter)
        }
        LvTARG(lv) = SvREFCNT_inc(av);
        LvTARGOFF(lv) = cx->blk_loop.iterix;
-       LvTARGLEN(lv) = (UV) -1;
+       LvTARGLEN(lv) = (STRLEN)UV_MAX;
        sv = (SV*)lv;
     }
 
@@ -1658,7 +1645,7 @@ PP(pp_subst)
     if (SvREADONLY(TARG)
        || (SvTYPE(TARG) > SVt_PVLV
            && !(SvTYPE(TARG) == SVt_PVGV && SvFAKE(TARG))))
-       croak(PL_no_modify);
+       DIE(aTHX_ PL_no_modify);
     PUTBACK;
 
     s = SvPV(TARG, len);
@@ -1672,7 +1659,7 @@ PP(pp_subst)
 
   force_it:
     if (!pm || !s)
-       DIE("panic: do_subst");
+       DIE(aTHX_ "panic: do_subst");
 
     strend = s + len;
     maxiters = 2*(strend - s) + 10;    /* We can match twice at each 
@@ -1685,55 +1672,26 @@ PP(pp_subst)
     }
     r_flags = (rx->nparens || SvTEMP(TARG) || PL_sawampersand)
                ? REXEC_COPY_STR : 0;
-    if (SvSCREAM(TARG) && rx->check_substr
-                 && SvTYPE(rx->check_substr) == SVt_PVBM
-                 && SvVALID(rx->check_substr))
+    if (SvSCREAM(TARG))
        r_flags |= REXEC_SCREAM;
     if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
        SAVEINT(PL_multiline);
        PL_multiline = pm->op_pmflags & PMf_MULTILINE;
     }
     orig = m = s;
-    if (rx->check_substr) {
-       if (!(rx->reganch & ROPT_NOSCAN)) { /* It floats. */
-           if (r_flags & REXEC_SCREAM) {
-               I32 p = -1;
-               char *b;
-               
-               if (PL_screamfirst[BmRARE(rx->check_substr)] < 0)
-                   goto nope;
-
-               b = (char*)HOP((U8*)s, rx->check_offset_min);
-               if (!(s = screaminstr(TARG, rx->check_substr, b - s, 0, &p, 0)))
-                   goto nope;
-           }
-           else if (!(s = fbm_instr((unsigned char*)HOP((U8*)s, rx->check_offset_min), 
-                                    (unsigned char*)strend,
-                                    rx->check_substr, 0)))
-               goto nope;
-           if (s && rx->check_offset_max < s - m) {
-               ++BmUSEFUL(rx->check_substr);
-               s = (char*)HOP((U8*)s, -rx->check_offset_max);
-           }
-           else
-               s = m;
-       }
-       /* Now checkstring is fixed, i.e. at fixed offset from the
-          beginning of match, and the match is anchored at s. */
-       else if (!PL_multiline) { /* Anchored at beginning of string. */
-           I32 slen;
-           char *b = (char*)HOP((U8*)s, rx->check_offset_min);
-           if (*SvPVX(rx->check_substr) != *b
-               || ((slen = SvCUR(rx->check_substr)) > 1
-                   && memNE(SvPVX(rx->check_substr), b, slen)))
-               goto nope;
-       }
-       if (!(rx->reganch & ROPT_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 (rx->reganch & RE_USE_INTUIT) {
+       s = CALLREG_INTUIT_START(aTHX_ rx, TARG, s, strend, r_flags, NULL);
+
+       if (!s)
+           goto nope;
+       /* How to do it in subst? */
+/*     if ( (rx->reganch & ROPT_CHECK_ALL)
+            && !PL_sawampersand 
+            && ((rx->reganch & ROPT_NOSCAN)
+                || !((rx->reganch & RE_INTUIT_TAIL)
+                     && (r_flags & REXEC_SCREAM))))
+           goto yup;
+*/
     }
 
     /* only replace once? */
@@ -1745,7 +1703,9 @@ PP(pp_subst)
     /* can do inplace substitution? */
     if (c && clen <= rx->minlen && (once || !(r_flags & REXEC_COPY_STR))
        && !(rx->reganch & ROPT_LOOKBEHIND_SEEN)) {
-       if (!CALLREGEXEC(rx, s, strend, orig, 0, TARG, NULL, r_flags)) {
+       if (!CALLREGEXEC(aTHX_ rx, s, strend, orig, 0, TARG, NULL,
+                        r_flags | REXEC_CHECKED))
+       {
            SPAGAIN;
            PUSHs(&PL_sv_no);
            LEAVE_SCOPE(oldsave);
@@ -1761,13 +1721,8 @@ PP(pp_subst)
        SvSCREAM_off(TARG);     /* disable possible screamer */
        if (once) {
            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];
-           }
+           m = orig + rx->startp[0];
+           d = orig + rx->endp[0];
            s = orig;
            if (m - s > strend - d) {  /* faster to shorten from end */
                if (clen) {
@@ -1808,9 +1763,9 @@ PP(pp_subst)
        else {
            do {
                if (iters++ > maxiters)
-                   DIE("Substitution loop");
+                   DIE(aTHX_ "Substitution loop");
                rxtainted |= RX_MATCH_TAINTED(rx);
-               m = rx->startp[0];
+               m = rx->startp[0] + orig;
                /*SUPPRESS 560*/
                if (i = m - s) {
                    if (s != d)
@@ -1821,9 +1776,11 @@ PP(pp_subst)
                    Copy(c, d, clen, char);
                    d += clen;
                }
-               s = rx->endp[0];
-           } while (CALLREGEXEC(rx, s, strend, orig, s == m,
-                             Nullsv, NULL, 0)); /* don't match same null twice */
+               s = rx->endp[0] + orig;
+           } while (CALLREGEXEC(aTHX_ rx, s, strend, orig, s == m,
+                                TARG, NULL,
+                                /* don't match same null twice */
+                                REXEC_NOT_FIRST|REXEC_IGNOREPOS));
            if (s != d) {
                i = strend - s;
                SvCUR_set(TARG, d - SvPVX(TARG) + i);
@@ -1845,7 +1802,9 @@ PP(pp_subst)
        RETURN;
     }
 
-    if (CALLREGEXEC(rx, s, strend, orig, 0, TARG, NULL, r_flags)) {
+    if (CALLREGEXEC(aTHX_ rx, s, strend, orig, 0, TARG, NULL,
+                   r_flags | REXEC_CHECKED))
+    {
        if (force_on_match) {
            force_on_match = 0;
            s = SvPV_force(TARG, len);
@@ -1861,26 +1820,26 @@ PP(pp_subst)
            PUSHSUBST(cx);
            RETURNOP(cPMOP->op_pmreplroot);
        }
-       r_flags |= REXEC_IGNOREPOS;
+       r_flags |= REXEC_IGNOREPOS | REXEC_NOT_FIRST;
        do {
            if (iters++ > maxiters)
-               DIE("Substitution loop");
+               DIE(aTHX_ "Substitution loop");
            rxtainted |= RX_MATCH_TAINTED(rx);
-           if (rx->subbase && rx->subbase != orig) {
+           if (RX_MATCH_COPIED(rx) && rx->subbeg != orig) {
                m = s;
                s = orig;
-               orig = rx->subbase;
+               orig = rx->subbeg;
                s = orig + (m - s);
                strend = s + (strend - m);
            }
-           m = rx->startp[0];
+           m = rx->startp[0] + orig;
            sv_catpvn(dstr, s, m-s);
-           s = rx->endp[0];
+           s = rx->endp[0] + orig;
            if (clen)
                sv_catpvn(dstr, c, clen);
            if (once)
                break;
-       } while (CALLREGEXEC(rx, s, strend, orig, s == m, TARG, NULL, r_flags));
+       } while (CALLREGEXEC(aTHX_ rx, s, strend, orig, s == m, TARG, NULL, r_flags));
        sv_catpvn(dstr, s, strend - s);
 
        (void)SvOOK_off(TARG);
@@ -1905,8 +1864,6 @@ PP(pp_subst)
     goto ret_no;
 
 nope:
-    ++BmUSEFUL(rx->check_substr);
-
 ret_no:         
     SPAGAIN;
     PUSHs(&PL_sv_no);
@@ -1977,13 +1934,16 @@ PP(pp_leavesub)
                    *MARK = SvREFCNT_inc(TOPs);
                    FREETMPS;
                    sv_2mortal(*MARK);
-               } else {
+               }
+               else {
                    FREETMPS;
                    *MARK = sv_mortalcopy(TOPs);
                }
-           } else
+           }
+           else
                *MARK = SvTEMP(TOPs) ? TOPs : sv_mortalcopy(TOPs);
-       } else {
+       }
+       else {
            MEXTEND(MARK, 0);
            *MARK = &PL_sv_undef;
        }
@@ -2006,8 +1966,153 @@ PP(pp_leavesub)
     return pop_return();
 }
 
+/* This duplicates the above code because the above code must not
+ * get any slower by more conditions */
+PP(pp_leavesublv)
+{
+    djSP;
+    SV **mark;
+    SV **newsp;
+    PMOP *newpm;
+    I32 gimme;
+    register PERL_CONTEXT *cx;
+    struct block_sub cxsub;
+
+    POPBLOCK(cx,newpm);
+    POPSUB1(cx);       /* Delay POPSUB2 until stack values are safe */
+    TAINT_NOT;
+
+    if (cx->blk_sub.lval & OPpENTERSUB_INARGS) {
+       /* We are an argument to a function or grep().
+        * This kind of lvalueness was legal before lvalue
+        * subroutines too, so be backward compatible:
+        * cannot report errors.  */
+
+       /* Scalar context *is* possible, on the LHS of -> only,
+        * as in f()->meth().  But this is not an lvalue. */
+       if (gimme == G_SCALAR)
+           goto temporise;
+       if (gimme == G_ARRAY) {
+           if (!CvLVALUE(cxsub.cv))
+               goto temporise_array;
+           EXTEND_MORTAL(SP - newsp);
+           for (mark = newsp + 1; mark <= SP; mark++) {
+               if (SvTEMP(*mark))
+                   /* empty */ ;
+               else if (SvFLAGS(*mark) & (SVs_PADTMP | SVf_READONLY))
+                   *mark = sv_mortalcopy(*mark);
+               else {
+                   /* Can be a localized value subject to deletion. */
+                   PL_tmps_stack[++PL_tmps_ix] = *mark;
+                   SvREFCNT_inc(*mark);
+               }
+           }
+       }
+    }
+    else if (cx->blk_sub.lval) {     /* Leave it as it is if we can. */
+       /* Here we go for robustness, not for speed, so we change all
+        * the refcounts so the caller gets a live guy. Cannot set
+        * TEMP, so sv_2mortal is out of question. */
+       if (!CvLVALUE(cxsub.cv)) {
+           POPSUB2();
+           PL_curpm = newpm;
+           DIE(aTHX_ "Can't modify non-lvalue subroutine call");
+       }
+       if (gimme == G_SCALAR) {
+           MARK = newsp + 1;
+           EXTEND_MORTAL(1);
+           if (MARK == SP) {
+               if (SvFLAGS(TOPs) & (SVs_TEMP | SVs_PADTMP | SVf_READONLY)) {
+                   POPSUB2();
+                   PL_curpm = newpm;
+                   DIE(aTHX_ "Can't return a %s from lvalue subroutine",
+                       SvREADONLY(TOPs) ? "readonly value" : "temporary");
+               }
+               else {                  /* Can be a localized value
+                                        * subject to deletion. */
+                   PL_tmps_stack[++PL_tmps_ix] = *mark;
+                   SvREFCNT_inc(*mark);
+               }
+           }
+           else {                      /* Should not happen? */
+               POPSUB2();
+               PL_curpm = newpm;
+               DIE(aTHX_ "%s returned from lvalue subroutine in scalar context",
+                   (MARK > SP ? "Empty array" : "Array"));
+           }
+           SP = MARK;
+       }
+       else if (gimme == G_ARRAY) {
+           EXTEND_MORTAL(SP - newsp);
+           for (mark = newsp + 1; mark <= SP; mark++) {
+               if (SvFLAGS(*mark) & (SVs_TEMP | SVs_PADTMP | SVf_READONLY)) {
+                   /* Might be flattened array after $#array =  */
+                   PUTBACK;
+                   POPSUB2();
+                   PL_curpm = newpm;
+                   DIE(aTHX_ "Can't return %s from lvalue subroutine",
+                       (*mark != &PL_sv_undef)
+                       ? (SvREADONLY(TOPs)
+                           ? "a readonly value" : "a temporary")
+                       : "an uninitialized value");
+               }
+               else {
+                   mortalize:
+                   /* Can be a localized value subject to deletion. */
+                   PL_tmps_stack[++PL_tmps_ix] = *mark;
+                   SvREFCNT_inc(*mark);
+               }
+           }
+       }
+    }
+    else {
+       if (gimme == G_SCALAR) {
+         temporise:
+           MARK = newsp + 1;
+           if (MARK <= SP) {
+               if (cxsub.cv && CvDEPTH(cxsub.cv) > 1) {
+                   if (SvTEMP(TOPs)) {
+                       *MARK = SvREFCNT_inc(TOPs);
+                       FREETMPS;
+                       sv_2mortal(*MARK);
+                   }
+                   else {
+                       FREETMPS;
+                       *MARK = sv_mortalcopy(TOPs);
+                   }
+               }
+               else
+                   *MARK = SvTEMP(TOPs) ? TOPs : sv_mortalcopy(TOPs);
+           }
+           else {
+               MEXTEND(MARK, 0);
+               *MARK = &PL_sv_undef;
+           }
+           SP = MARK;
+       }
+       else if (gimme == G_ARRAY) {
+         temporise_array:
+           for (MARK = newsp + 1; MARK <= SP; MARK++) {
+               if (!SvTEMP(*MARK)) {
+                   *MARK = sv_mortalcopy(*MARK);
+                   TAINT_NOT;  /* Each item is independent */
+               }
+           }
+       }
+    }
+    PUTBACK;
+    
+    POPSUB2();         /* Stack values are safe: release CV and @_ ... */
+    PL_curpm = newpm;  /* ... and pop $1 et al */
+
+    LEAVE;
+    return pop_return();
+}
+
+
 STATIC CV *
-get_db_sub(SV **svp, CV *cv)
+S_get_db_sub(pTHX_ SV **svp, CV *cv)
 {
     dTHR;
     SV *dbsv = GvSV(PL_DBsub);
@@ -2033,7 +2138,7 @@ get_db_sub(SV **svp, CV *cv)
        SvUPGRADE(dbsv, SVt_PVIV);
        SvIOK_on(dbsv);
        SAVEIV(SvIVX(dbsv));
-       SvIVX(dbsv) = (IV)cv;           /* Do it the quickest way  */
+       SvIVX(dbsv) = PTR2IV(cv);       /* Do it the quickest way  */
     }
 
     if (CvXSUB(cv))
@@ -2053,7 +2158,7 @@ PP(pp_entersub)
     bool hasargs = (PL_op->op_flags & OPf_STACKED) != 0;
 
     if (!sv)
-       DIE("Not a CODE reference");
+       DIE(aTHX_ "Not a CODE reference");
     switch (SvTYPE(sv)) {
     default:
        if (!SvROK(sv)) {
@@ -2072,10 +2177,10 @@ PP(pp_entersub)
            else
                sym = SvPV(sv, n_a);
            if (!sym)
-               DIE(PL_no_usym, "a subroutine");
+               DIE(aTHX_ PL_no_usym, "a subroutine");
            if (PL_op->op_private & HINT_STRICT_REFS)
-               DIE(PL_no_symref, sym, "a subroutine");
-           cv = perl_get_cv(sym, TRUE);
+               DIE(aTHX_ PL_no_symref, sym, "a subroutine");
+           cv = get_cv(sym, TRUE);
            break;
        }
        {
@@ -2088,7 +2193,7 @@ PP(pp_entersub)
        /* FALL THROUGH */
     case SVt_PVHV:
     case SVt_PVAV:
-       DIE("Not a CODE reference");
+       DIE(aTHX_ "Not a CODE reference");
     case SVt_PVCV:
        cv = (CV*)sv;
        break;
@@ -2113,7 +2218,7 @@ PP(pp_entersub)
 
        /* anonymous or undef'd function leaves us no recourse */
        if (CvANON(cv) || !(gv = CvGV(cv)))
-           DIE("Undefined subroutine called");
+           DIE(aTHX_ "Undefined subroutine called");
 
        /* autoloaded stub? */
        if (cv != GvCV(gv)) {
@@ -2131,11 +2236,11 @@ try_autoload:
            else {
                sub_name = sv_newmortal();
                gv_efullname3(sub_name, gv, Nullch);
-               DIE("Undefined subroutine &%s called", SvPVX(sub_name));
+               DIE(aTHX_ "Undefined subroutine &%s called", SvPVX(sub_name));
            }
        }
        if (!cv)
-           DIE("Not a CODE reference");
+           DIE(aTHX_ "Not a CODE reference");
        goto retry;
     }
 
@@ -2143,7 +2248,7 @@ try_autoload:
     if ((PL_op->op_private & OPpENTERSUB_DB) && GvCV(PL_DBsub) && !CvNODEBUG(cv)) {
        cv = get_db_sub(&sv, cv);
        if (!cv)
-           DIE("No DBsub routine");
+           DIE(aTHX_ "No DBsub routine");
     }
 
 #ifdef USE_THREADS
@@ -2166,7 +2271,7 @@ try_autoload:
                    || !(sv = AvARRAY(av)[0]))
                {
                    MUTEX_UNLOCK(CvMUTEXP(cv));
-                   croak("no argument for locked method call");
+                   DIE(aTHX_ "no argument for locked method call");
                }
            }
            if (SvROK(sv))
@@ -2189,10 +2294,10 @@ try_autoload:
            while (MgOWNER(mg))
                COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg));
            MgOWNER(mg) = thr;
-           DEBUG_S(PerlIO_printf(PerlIO_stderr(), "%p: pp_entersub lock %p\n",
+           DEBUG_S(PerlIO_printf(Perl_debug_log, "%p: pp_entersub lock %p\n",
                                  thr, sv);)
            MUTEX_UNLOCK(MgMUTEXP(mg));
-           save_destructor(unlock_condpair, sv);
+           SAVEDESTRUCTOR(Perl_unlock_condpair, sv);
        }
        MUTEX_LOCK(CvMUTEXP(cv));
     }
@@ -2231,7 +2336,7 @@ try_autoload:
            /* We already have a clone to use */
            MUTEX_UNLOCK(CvMUTEXP(cv));
            cv = *(CV**)svp;
-           DEBUG_S(PerlIO_printf(PerlIO_stderr(),
+           DEBUG_S(PerlIO_printf(Perl_debug_log,
                                  "entersub: %p already has clone %p:%s\n",
                                  thr, cv, SvPEEK((SV*)cv)));
            CvOWNER(cv) = thr;
@@ -2245,16 +2350,17 @@ try_autoload:
                CvOWNER(cv) = thr;
                SvREFCNT_inc(cv);
                MUTEX_UNLOCK(CvMUTEXP(cv));
-               DEBUG_S(PerlIO_printf(PerlIO_stderr(),
+               DEBUG_S(PerlIO_printf(Perl_debug_log,
                            "entersub: %p grabbing %p:%s in stash %s\n",
                            thr, cv, SvPEEK((SV*)cv), CvSTASH(cv) ?
                                HvNAME(CvSTASH(cv)) : "(none)"));
-           } else {
+           }
+           else {
                /* Make a new clone. */
                CV *clonecv;
                SvREFCNT_inc(cv); /* don't let it vanish from under us */
                MUTEX_UNLOCK(CvMUTEXP(cv));
-               DEBUG_S((PerlIO_printf(PerlIO_stderr(),
+               DEBUG_S((PerlIO_printf(Perl_debug_log,
                                       "entersub: %p cloning %p:%s\n",
                                       thr, cv, SvPEEK((SV*)cv))));
                /*
@@ -2272,7 +2378,7 @@ try_autoload:
                SvREFCNT_inc(cv);
            }
            DEBUG_S(if (CvDEPTH(cv) != 0)
-                       PerlIO_printf(PerlIO_stderr(), "depth %ld != 0\n",
+                       PerlIO_printf(Perl_debug_log, "depth %ld != 0\n",
                                      CvDEPTH(cv)););
            SAVEDESTRUCTOR(unset_cvowner, (void*) cv);
        }
@@ -2282,7 +2388,7 @@ try_autoload:
     if (CvXSUB(cv)) {
 #ifdef PERL_XSUB_OLDSTYLE
        if (CvOLDSTYLE(cv)) {
-           I32 (*fp3)_((int,int,int));
+           I32 (*fp3)(int,int,int);
            dMARK;
            register I32 items = SP - MARK;
                                        /* We dont worry to copy from @_. */
@@ -2291,7 +2397,7 @@ try_autoload:
                SP--;
            }
            PL_stack_sp = mark + 1;
-           fp3 = (I32(*)_((int,int,int)))CvXSUB(cv);
+           fp3 = (I32(*)(int,int,int)))CvXSUB(cv;
            items = (*fp3)(CvXSUBANY(cv).any_i32, 
                           MARK - PL_stack_base + 1,
                           items);
@@ -2332,7 +2438,7 @@ try_autoload:
                PL_curcopdb = NULL;
            }
            /* Do we need to open block here? XXXX */
-           (void)(*CvXSUB(cv))(cv _PERL_OBJECT_THIS);
+           (void)(*CvXSUB(cv))(aTHXo_ cv);
 
            /* Enforce some sanity in scalar context. */
            if (gimme == G_SCALAR && ++markix != PL_stack_sp - PL_stack_base ) {
@@ -2425,14 +2531,11 @@ try_autoload:
            SV** ary;
 
 #if 0
-           DEBUG_S(PerlIO_printf(PerlIO_stderr(),
+           DEBUG_S(PerlIO_printf(Perl_debug_log,
                                  "%p entersub preparing @_\n", thr));
 #endif
            av = (AV*)PL_curpad[0];
-           if (AvREAL(av)) {
-               av_clear(av);
-               AvREAL_off(av);
-           }
+           assert(!AvREAL(av));
 #ifndef USE_THREADS
            cx->blk_sub.savearray = GvAV(PL_defgv);
            GvAV(PL_defgv) = (AV*)SvREFCNT_inc(av);
@@ -2470,7 +2573,7 @@ try_autoload:
            && !(PERLDB_SUB && cv == GvCV(PL_DBsub)))
            sub_crush_depth(cv);
 #if 0
-       DEBUG_S(PerlIO_printf(PerlIO_stderr(),
+       DEBUG_S(PerlIO_printf(Perl_debug_log,
                              "%p entersub returning %p\n", thr, CvSTART(cv)));
 #endif
        RETURNOP(CvSTART(cv));
@@ -2478,14 +2581,14 @@ try_autoload:
 }
 
 void
-sub_crush_depth(CV *cv)
+Perl_sub_crush_depth(pTHX_ CV *cv)
 {
     if (CvANON(cv))
-       warner(WARN_RECURSION, "Deep recursion on anonymous subroutine");
+       Perl_warner(aTHX_ WARN_RECURSION, "Deep recursion on anonymous subroutine");
     else {
        SV* tmpstr = sv_newmortal();
        gv_efullname3(tmpstr, CvGV(cv), Nullch);
-       warner(WARN_RECURSION, "Deep recursion on subroutine \"%s\"", 
+       Perl_warner(aTHX_ WARN_RECURSION, "Deep recursion on subroutine \"%s\"", 
                SvPVX(tmpstr));
     }
 }
@@ -2509,7 +2612,7 @@ PP(pp_aelem)
        if (!svp || *svp == &PL_sv_undef) {
            SV* lv;
            if (!defer)
-               DIE(PL_no_aelem, elem);
+               DIE(aTHX_ PL_no_aelem, elem);
            lv = sv_newmortal();
            sv_upgrade(lv, SVt_PVLV);
            LvTYPE(lv) = 'y';
@@ -2533,13 +2636,13 @@ PP(pp_aelem)
 }
 
 void
-vivify_ref(SV *sv, U32 to_what)
+Perl_vivify_ref(pTHX_ SV *sv, U32 to_what)
 {
     if (SvGMAGICAL(sv))
        mg_get(sv);
     if (!SvOK(sv)) {
        if (SvREADONLY(sv))
-           croak(PL_no_modify);
+           Perl_croak(aTHX_ PL_no_modify);
        if (SvTYPE(sv) < SVt_RV)
            sv_upgrade(sv, SVt_RV);
        else if (SvTYPE(sv) >= SVt_PV) {
@@ -2566,25 +2669,46 @@ vivify_ref(SV *sv, U32 to_what)
 PP(pp_method)
 {
     djSP;
+    SV* sv = TOPs;
+
+    if (SvROK(sv)) {
+       SV* rsv = SvRV(sv);
+       if (SvTYPE(rsv) == SVt_PVCV) {
+           SETs(rsv);
+           RETURN;
+       }
+    }
+
+    SETs(method_common(sv, Null(U32*)));
+    RETURN;
+}
+
+PP(pp_method_named)
+{
+    djSP;
+    SV* sv = cSVOP->op_sv;
+    U32 hash = SvUVX(sv);
+
+    XPUSHs(method_common(sv, &hash));
+    RETURN;
+}
+
+STATIC SV *
+S_method_common(pTHX_ SV* meth, U32* hashp)
+{
+    djSP;
     SV* sv;
     SV* ob;
     GV* gv;
     HV* stash;
     char* name;
+    STRLEN namelen;
     char* packname;
     STRLEN packlen;
 
-    if (SvROK(TOPs)) {
-       sv = SvRV(TOPs);
-       if (SvTYPE(sv) == SVt_PVCV) {
-           SETs(sv);
-           RETURN;
-       }
-    }
-
-    name = SvPV(TOPs, packlen);
+    name = SvPV(meth, namelen);
     sv = *(PL_stack_base + TOPMARK + 1);
-    
+
     if (SvGMAGICAL(sv))
         mg_get(sv);
     if (SvROK(sv))
@@ -2604,9 +2728,9 @@ PP(pp_method)
                    : !isIDFIRST(*packname)
                ))
            {
-               DIE("Can't call method \"%s\" %s", name,
-                   SvOK(sv)? "without a package or object reference"
-                           : "on an undefined value");
+               Perl_croak(aTHX_ "Can't call method \"%s\" %s", name,
+                          SvOK(sv) ? "without a package or object reference"
+                                   : "on an undefined value");
            }
            stash = gv_stashpvn(packname, packlen, TRUE);
            goto fetch;
@@ -2615,11 +2739,23 @@ PP(pp_method)
     }
 
     if (!ob || !SvOBJECT(ob))
-       DIE("Can't call method \"%s\" on unblessed reference", name);
+       Perl_croak(aTHX_ "Can't call method \"%s\" on unblessed reference",
+                  name);
 
     stash = SvSTASH(ob);
 
   fetch:
+    /* shortcut for simple names */
+    if (hashp) {
+       HE* he = hv_fetch_ent(stash, meth, 0, *hashp);
+       if (he) {
+           gv = (GV*)HeVAL(he);
+           if (isGV(gv) && GvCV(gv) &&
+               (!GvCVGEN(gv) || GvCVGEN(gv) == PL_sub_generation))
+               return (SV*)GvCV(gv);
+       }
+    }
+
     gv = gv_fetchmethod(stash, name);
     if (!gv) {
        char* leaf = name;
@@ -2640,10 +2776,31 @@ PP(pp_method)
            packname = name;
            packlen = sep - name;
        }
-       DIE("Can't locate object method \"%s\" via package \"%.*s\"",
-           leaf, (int)packlen, packname);
+       Perl_croak(aTHX_
+                  "Can't locate object method \"%s\" via package \"%s\"",
+                  leaf, packname);
     }
-    SETs(isGV(gv) ? (SV*)GvCV(gv) : (SV*)gv);
-    RETURN;
+    return isGV(gv) ? (SV*)GvCV(gv) : (SV*)gv;
 }
 
+#ifdef USE_THREADS
+static void
+unset_cvowner(pTHXo_ void *cvarg)
+{
+    register CV* cv = (CV *) cvarg;
+#ifdef DEBUGGING
+    dTHR;
+#endif /* DEBUGGING */
+
+    DEBUG_S((PerlIO_printf(Perl_debug_log, "%p unsetting CvOWNER of %p:%s\n",
+                          thr, cv, SvPEEK((SV*)cv))));
+    MUTEX_LOCK(CvMUTEXP(cv));
+    DEBUG_S(if (CvDEPTH(cv) != 0)
+               PerlIO_printf(Perl_debug_log, "depth %ld != 0\n",
+                             CvDEPTH(cv)););
+    assert(thr == CvOWNER(cv));
+    CvOWNER(cv) = 0;
+    MUTEX_UNLOCK(CvMUTEXP(cv));
+    SvREFCNT_dec(cv);
+}
+#endif /* USE_THREADS */