This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
flock() should return EWOULDBLOCK instead of EAGAIN.
[perl5.git] / pp_ctl.c
index 5da6993..921363f 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -1,7 +1,7 @@
 /*    pp_ctl.c
  *
- *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by Larry Wall and others
+ *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ *    2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -9,12 +9,14 @@
  */
 
 /*
- * Now far ahead the Road has gone,
- * And I must follow, if I can,
- * Pursuing it with eager feet,
- * Until it joins some larger way
- * Where many paths and errands meet.
- * And whither then?  I cannot say.
+ *      Now far ahead the Road has gone,
+ *          And I must follow, if I can,
+ *      Pursuing it with eager feet,
+ *          Until it joins some larger way
+ *      Where many paths and errands meet.
+ *          And whither then?  I cannot say.
+ *
+ *     [Bilbo on p.35 of _The Lord of the Rings_, I/i: "A Long-Expected Party"]
  */
 
 /* This file contains control-oriented pp ("push/pop") functions that
@@ -91,36 +93,63 @@ PP(pp_regcomp)
        RETURN;
     }
 #endif
+
+#define tryAMAGICregexp(rx)                    \
+    STMT_START {                               \
+       if (SvROK(rx) && SvAMAGIC(rx)) {        \
+           SV *sv = AMG_CALLun(rx, regexp);    \
+           if (sv) {                           \
+               if (SvROK(sv))                  \
+                   sv = SvRV(sv);              \
+               if (SvTYPE(sv) != SVt_REGEXP)   \
+                   Perl_croak(aTHX_ "Overloaded qr did not return a REGEXP"); \
+               rx = sv;                        \
+           }                                   \
+       }                                       \
+    } STMT_END
+           
+
     if (PL_op->op_flags & OPf_STACKED) {
        /* multiple args; concatentate them */
        dMARK; dORIGMARK;
        tmpstr = PAD_SV(ARGTARG);
-       sv_setpvn(tmpstr, "", 0);
+       sv_setpvs(tmpstr, "");
        while (++MARK <= SP) {
+           SV *msv = *MARK;
            if (PL_amagic_generation) {
                SV *sv;
-               if ((SvAMAGIC(tmpstr) || SvAMAGIC(*MARK)) &&
-                   (sv = amagic_call(tmpstr, *MARK, concat_amg, AMGf_assign)))
+
+               tryAMAGICregexp(msv);
+
+               if ((SvAMAGIC(tmpstr) || SvAMAGIC(msv)) &&
+                   (sv = amagic_call(tmpstr, msv, concat_amg, AMGf_assign)))
                {
                   sv_setsv(tmpstr, sv);
                   continue;
                }
            }
-           sv_catsv(tmpstr, *MARK);
+           sv_catsv(tmpstr, msv);
        }
        SvSETMAGIC(tmpstr);
        SP = ORIGMARK;
     }
-    else
+    else {
        tmpstr = POPs;
+       tryAMAGICregexp(tmpstr);
+    }
+
+#undef tryAMAGICregexp
 
     if (SvROK(tmpstr)) {
        SV * const sv = SvRV(tmpstr);
        if (SvTYPE(sv) == SVt_REGEXP)
            re = (REGEXP*) sv;
     }
+    else if (SvTYPE(tmpstr) == SVt_REGEXP)
+       re = (REGEXP*) tmpstr;
+
     if (re) {
-       re = reg_temp_copy(re);
+       re = reg_temp_copy(NULL, re);
        ReREFCNT_dec(PM_GETRE(pm));
        PM_SETRE(pm, re);
     }
@@ -231,14 +260,16 @@ PP(pp_substcont)
        if (!(cx->sb_rxtainted & 2) && SvTAINTED(TOPs))
            cx->sb_rxtainted |= 2;
        sv_catsv(dstr, POPs);
-       FREETMPS; /* Prevent excess tmp stack */
+       /* XXX: adjust for positive offsets of \G for instance s/(.)\G//g with positive pos() */
+       s -= RX_GOFS(rx);
 
        /* Are we done */
-       if (CxONCE(cx) || !CALLREGEXEC(rx, s, cx->sb_strend, orig,
-                                    s == m, cx->sb_targ, NULL,
-                                    ((cx->sb_rflags & REXEC_COPY_STR)
-                                     ? (REXEC_IGNOREPOS|REXEC_NOT_FIRST)
-                                     : (REXEC_COPY_STR|REXEC_IGNOREPOS|REXEC_NOT_FIRST))))
+       if (CxONCE(cx) || s < orig ||
+               !CALLREGEXEC(rx, s, cx->sb_strend, orig,
+                            (s == m) + RX_GOFS(rx), cx->sb_targ, NULL,
+                            ((cx->sb_rflags & REXEC_COPY_STR)
+                             ? (REXEC_IGNOREPOS|REXEC_NOT_FIRST)
+                             : (REXEC_COPY_STR|REXEC_IGNOREPOS|REXEC_NOT_FIRST))))
        {
            SV * const targ = cx->sb_targ;
 
@@ -298,7 +329,6 @@ PP(pp_substcont)
     { /* Update the pos() information. */
        SV * const sv = cx->sb_targ;
        MAGIC *mg;
-       I32 i;
        SvUPGRADE(sv, SVt_PVMG);
        if (!(mg = mg_find(sv, PERL_MAGIC_regex_global))) {
 #ifdef PERL_OLD_COPY_ON_WRITE
@@ -308,10 +338,7 @@ PP(pp_substcont)
            mg = sv_magicext(sv, NULL, PERL_MAGIC_regex_global, &PL_vtbl_mglob,
                             NULL, 0);
        }
-       i = m - orig;
-       if (DO_UTF8(sv))
-           sv_pos_b2u(sv, &i);
-       mg->mg_len = i;
+       mg->mg_len = m - orig;
     }
     if (old != rx)
        (void)ReREFCNT_inc(rx);
@@ -325,6 +352,8 @@ Perl_rxres_save(pTHX_ void **rsp, REGEXP *rx)
 {
     UV *p = (UV*)*rsp;
     U32 i;
+
+    PERL_ARGS_ASSERT_RXRES_SAVE;
     PERL_UNUSED_CONTEXT;
 
     if (!p || p[1] < RX_NPARENS(rx)) {
@@ -358,11 +387,13 @@ Perl_rxres_save(pTHX_ void **rsp, REGEXP *rx)
     }
 }
 
-void
-Perl_rxres_restore(pTHX_ void **rsp, REGEXP *rx)
+static void
+S_rxres_restore(pTHX_ void **rsp, REGEXP *rx)
 {
     UV *p = (UV*)*rsp;
     U32 i;
+
+    PERL_ARGS_ASSERT_RXRES_RESTORE;
     PERL_UNUSED_CONTEXT;
 
     RX_MATCH_COPY_FREE(rx);
@@ -386,10 +417,12 @@ Perl_rxres_restore(pTHX_ void **rsp, REGEXP *rx)
     }
 }
 
-void
-Perl_rxres_free(pTHX_ void **rsp)
+static void
+S_rxres_free(pTHX_ void **rsp)
 {
     UV * const p = (UV*)*rsp;
+
+    PERL_ARGS_ASSERT_RXRES_FREE;
     PERL_UNUSED_CONTEXT;
 
     if (p) {
@@ -437,7 +470,6 @@ PP(pp_formline)
     SV * nsv = NULL;
     OP * parseres = NULL;
     const char *fmt;
-    bool oneline;
 
     if (!SvMAGICAL(tmpForm) || !SvCOMPILED(tmpForm)) {
        if (SvREADONLY(tmpForm)) {
@@ -503,13 +535,13 @@ PP(pp_formline)
                *t = '\0';
                sv_catpvn_utf8_upgrade(PL_formtarget, f, arg, nsv);
                t = SvEND(PL_formtarget);
+               f += arg;
                break;
            }
            if (!targ_is_utf8 && DO_UTF8(tmpForm)) {
                SvCUR_set(PL_formtarget, t - SvPVX_const(PL_formtarget));
                *t = '\0';
-               sv_utf8_upgrade(PL_formtarget);
-               SvGROW(PL_formtarget, SvCUR(PL_formtarget) + fudge + 1);
+               sv_utf8_upgrade_flags_grow(PL_formtarget, SV_GMAGIC, fudge + 1);
                t = SvEND(PL_formtarget);
                targ_is_utf8 = TRUE;
            }
@@ -530,8 +562,7 @@ PP(pp_formline)
                sv = *++MARK;
            else {
                sv = &PL_sv_no;
-               if (ckWARN(WARN_SYNTAX))
-                   Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Not enough format arguments");
+               Perl_ck_warner(aTHX_ packWARN(WARN_SYNTAX), "Not enough format arguments");
            }
            break;
 
@@ -692,8 +723,8 @@ PP(pp_formline)
                    if (!targ_is_utf8) {
                        SvCUR_set(PL_formtarget, t - SvPVX_const(PL_formtarget));
                        *t = '\0';
-                       sv_utf8_upgrade(PL_formtarget);
-                       SvGROW(PL_formtarget, SvCUR(PL_formtarget) + fudge + 1);
+                       sv_utf8_upgrade_flags_grow(PL_formtarget, SV_GMAGIC,
+                                                                   fudge + 1);
                        t = SvEND(PL_formtarget);
                        targ_is_utf8 = TRUE;
                    }
@@ -763,51 +794,76 @@ PP(pp_formline)
 
        case FF_LINESNGL:
            chopspace = 0;
-           oneline = TRUE;
-           goto ff_line;
        case FF_LINEGLOB:
-           oneline = FALSE;
-       ff_line:
            {
+               const bool oneline = fpc[-1] == FF_LINESNGL;
                const char *s = item = SvPV_const(sv, len);
+               item_is_utf8 = DO_UTF8(sv);
                itemsize = len;
-               if ((item_is_utf8 = DO_UTF8(sv)))
-                   itemsize = sv_len_utf8(sv);
                if (itemsize) {
-                   bool chopped = FALSE;
+                   STRLEN to_copy = itemsize;
                    const char *const send = s + len;
+                   const U8 *source = (const U8 *) s;
+                   U8 *tmp = NULL;
+
                    gotsome = TRUE;
                    chophere = s + itemsize;
                    while (s < send) {
                        if (*s++ == '\n') {
                            if (oneline) {
-                               chopped = TRUE;
+                               to_copy = s - SvPVX_const(sv) - 1;
                                chophere = s;
                                break;
                            } else {
                                if (s == send) {
                                    itemsize--;
-                                   chopped = TRUE;
+                                   to_copy--;
                                } else
                                    lines++;
                            }
                        }
                    }
-                   SvCUR_set(PL_formtarget, t - SvPVX_const(PL_formtarget));
-                   if (targ_is_utf8)
-                       SvUTF8_on(PL_formtarget);
-                   if (oneline) {
-                       SvCUR_set(sv, chophere - item);
-                       sv_catsv(PL_formtarget, sv);
-                       SvCUR_set(sv, itemsize);
-                   } else
-                       sv_catsv(PL_formtarget, sv);
-                   if (chopped)
-                       SvCUR_set(PL_formtarget, SvCUR(PL_formtarget) - 1);
-                   SvGROW(PL_formtarget, SvCUR(PL_formtarget) + fudge + 1);
+                   if (targ_is_utf8 && !item_is_utf8) {
+                       source = tmp = bytes_to_utf8(source, &to_copy);
+                       SvCUR_set(PL_formtarget,
+                                 t - SvPVX_const(PL_formtarget));
+                   } else {
+                       if (item_is_utf8 && !targ_is_utf8) {
+                           /* Upgrade targ to UTF8, and then we reduce it to
+                              a problem we have a simple solution for.  */
+                           SvCUR_set(PL_formtarget,
+                                     t - SvPVX_const(PL_formtarget));
+                           targ_is_utf8 = TRUE;
+                           /* Don't need get magic.  */
+                           sv_utf8_upgrade_nomg(PL_formtarget);
+                       } else {
+                           SvCUR_set(PL_formtarget,
+                                     t - SvPVX_const(PL_formtarget));
+                       }
+
+                       /* Easy. They agree.  */
+                       assert (item_is_utf8 == targ_is_utf8);
+                   }
+                   SvGROW(PL_formtarget,
+                          SvCUR(PL_formtarget) + to_copy + fudge + 1);
                    t = SvPVX(PL_formtarget) + SvCUR(PL_formtarget);
-                   if (item_is_utf8)
-                       targ_is_utf8 = TRUE;
+
+                   Copy(source, t, to_copy, char);
+                   t += to_copy;
+                   SvCUR_set(PL_formtarget, SvCUR(PL_formtarget) + to_copy);
+                   if (item_is_utf8) {
+                       if (SvGMAGICAL(sv)) {
+                           /* Mustn't call sv_pos_b2u() as it does a second
+                              mg_get(). Is this a bug? Do we need a _flags()
+                              variant? */
+                           itemsize = utf8_length(source, source + itemsize);
+                       } else {
+                           sv_pos_b2u(sv, &itemsize);
+                       }
+                       assert(!tmp);
+                   } else if (tmp) {
+                       Safefree(tmp);
+                   }
                }
                break;
            }
@@ -874,11 +930,6 @@ PP(pp_formline)
                    *t = '\0';
                    SvCUR_set(PL_formtarget, t - SvPVX_const(PL_formtarget));
                    lines += FmLINES(PL_formtarget);
-                   if (lines == 200) {
-                       arg = t - linemark;
-                       if (strnEQ(linemark, linemark - arg, arg))
-                           DIE(aTHX_ "Runaway format");
-                   }
                    if (targ_is_utf8)
                        SvUTF8_on(PL_formtarget);
                    FmLINES(PL_formtarget) = lines;
@@ -945,14 +996,14 @@ PP(pp_grepstart)
     PL_stack_sp = PL_stack_base + *PL_markstack_ptr + 1;
     pp_pushmark();                             /* push dst */
     pp_pushmark();                             /* push src */
-    ENTER;                                     /* enter outer scope */
+    ENTER_with_name("grep");                                   /* enter outer scope */
 
     SAVETMPS;
     if (PL_op->op_private & OPpGREP_LEX)
        SAVESPTR(PAD_SVl(PL_op->op_targ));
     else
        SAVE_DEFSV;
-    ENTER;                                     /* enter inner scope */
+    ENTER_with_name("grep_item");                                      /* enter inner scope */
     SAVEVPTR(PL_curpm);
 
     src = PL_stack_base[*PL_markstack_ptr];
@@ -960,7 +1011,7 @@ PP(pp_grepstart)
     if (PL_op->op_private & OPpGREP_LEX)
        PAD_SVl(PL_op->op_targ) = src;
     else
-       DEFSV = src;
+       DEFSV_set(src);
 
     PUTBACK;
     if (PL_op->op_type == OP_MAPSTART)
@@ -1033,13 +1084,13 @@ PP(pp_mapwhile)
            }
        }
     }
-    LEAVE;                                     /* exit inner scope */
+    LEAVE_with_name("grep_item");                                      /* exit inner scope */
 
     /* All done yet? */
     if (PL_markstack_ptr[-1] > *PL_markstack_ptr) {
 
        (void)POPMARK;                          /* pop top */
-       LEAVE;                                  /* exit outer scope */
+       LEAVE_with_name("grep");                                        /* exit outer scope */
        (void)POPMARK;                          /* pop src */
        items = --*PL_markstack_ptr - PL_markstack_ptr[-1];
        (void)POPMARK;                          /* pop dst */
@@ -1062,7 +1113,7 @@ PP(pp_mapwhile)
     else {
        SV *src;
 
-       ENTER;                                  /* enter inner scope */
+       ENTER_with_name("grep_item");                                   /* enter inner scope */
        SAVEVPTR(PL_curpm);
 
        /* set $_ to the new source item */
@@ -1071,7 +1122,7 @@ PP(pp_mapwhile)
        if (PL_op->op_private & OPpGREP_LEX)
            PAD_SVl(PL_op->op_targ) = src;
        else
-           DEFSV = src;
+           DEFSV_set(src);
 
        RETURNOP(cLOGOP->op_other);
     }
@@ -1128,7 +1179,7 @@ PP(pp_flip)
                RETURNOP(((LOGOP*)cUNOP->op_first)->op_other);
            }
        }
-       sv_setpvn(TARG, "", 0);
+       sv_setpvs(TARG, "");
        SETs(targ);
        RETURN;
     }
@@ -1224,14 +1275,17 @@ PP(pp_flop)
 
 static const char * const context_name[] = {
     "pseudo-block",
+    NULL, /* CXt_WHEN never actually needs "block" */
+    NULL, /* CXt_BLOCK never actually needs "block" */
+    NULL, /* CXt_GIVEN never actually needs "block" */
+    NULL, /* CXt_LOOP_FOR never actually needs "loop" */
+    NULL, /* CXt_LOOP_PLAIN never actually needs "loop" */
+    NULL, /* CXt_LOOP_LAZYSV never actually needs "loop" */
+    NULL, /* CXt_LOOP_LAZYIV never actually needs "loop" */
     "subroutine",
+    "format",
     "eval",
-    "loop",
     "substitution",
-    "block",
-    "format",
-    "given",
-    "when"
 };
 
 STATIC I32
@@ -1240,6 +1294,8 @@ S_dopoptolabel(pTHX_ const char *label)
     dVAR;
     register I32 i;
 
+    PERL_ARGS_ASSERT_DOPOPTOLABEL;
+
     for (i = cxstack_ix; i >= 0; i--) {
        register const PERL_CONTEXT * const cx = &cxstack[i];
        switch (CxTYPE(cx)) {
@@ -1248,11 +1304,8 @@ S_dopoptolabel(pTHX_ const char *label)
        case CXt_FORMAT:
        case CXt_EVAL:
        case CXt_NULL:
-       case CXt_GIVEN:
-       case CXt_WHEN:
-           if (ckWARN(WARN_EXITING))
-               Perl_warner(aTHX_ packWARN(WARN_EXITING), "Exiting %s via %s",
-                       context_name[CxTYPE(cx)], OP_NAME(PL_op));
+           Perl_ck_warner(aTHX_ packWARN(WARN_EXITING), "Exiting %s via %s",
+                          context_name[CxTYPE(cx)], OP_NAME(PL_op));
            if (CxTYPE(cx) == CXt_NULL)
                return -1;
            break;
@@ -1322,6 +1375,9 @@ S_dopoptosub_at(pTHX_ const PERL_CONTEXT *cxstk, I32 startingblock)
 {
     dVAR;
     I32 i;
+
+    PERL_ARGS_ASSERT_DOPOPTOSUB_AT;
+
     for (i = startingblock; i >= 0; i--) {
        register const PERL_CONTEXT * const cx = &cxstk[i];
        switch (CxTYPE(cx)) {
@@ -1368,9 +1424,8 @@ S_dopoptoloop(pTHX_ I32 startingblock)
        case CXt_FORMAT:
        case CXt_EVAL:
        case CXt_NULL:
-           if (ckWARN(WARN_EXITING))
-               Perl_warner(aTHX_ packWARN(WARN_EXITING), "Exiting %s via %s",
-                       context_name[CxTYPE(cx)], OP_NAME(PL_op));
+           Perl_ck_warner(aTHX_ packWARN(WARN_EXITING), "Exiting %s via %s",
+                          context_name[CxTYPE(cx)], OP_NAME(PL_op));
            if ((CxTYPE(cx)) == CXt_NULL)
                return -1;
            break;
@@ -1475,6 +1530,9 @@ void
 Perl_qerror(pTHX_ SV *err)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_QERROR;
+
     if (PL_in_eval)
        sv_catsv(ERRSV, err);
     else if (PL_errors)
@@ -1485,8 +1543,8 @@ Perl_qerror(pTHX_ SV *err)
        ++PL_parser->error_count;
 }
 
-OP *
-Perl_die_where(pTHX_ const char *message, STRLEN msglen)
+void
+Perl_die_where(pTHX_ SV *msv)
 {
     dVAR;
 
@@ -1494,32 +1552,37 @@ Perl_die_where(pTHX_ const char *message, STRLEN msglen)
        I32 cxix;
        I32 gimme;
 
-       if (message) {
+       if (msv) {
            if (PL_in_eval & EVAL_KEEPERR) {
                 static const char prefix[] = "\t(in cleanup) ";
                SV * const err = ERRSV;
                const char *e = NULL;
                if (!SvPOK(err))
-                   sv_setpvn(err,"",0);
-               else if (SvCUR(err) >= sizeof(prefix)+msglen-1) {
+                   sv_setpvs(err,"");
+               else if (SvCUR(err) >= sizeof(prefix)+SvCUR(msv)-1) {
                    STRLEN len;
+                   STRLEN msglen;
+                   const char* message = SvPV_const(msv, msglen);
                    e = SvPV_const(err, len);
                    e += len - msglen;
                    if (*e != *message || strNE(e,message))
                        e = NULL;
                }
                if (!e) {
-                   SvGROW(err, SvCUR(err)+sizeof(prefix)+msglen);
+                   STRLEN start;
+                   SvGROW(err, SvCUR(err)+sizeof(prefix)+SvCUR(msv));
                    sv_catpvn(err, prefix, sizeof(prefix)-1);
-                   sv_catpvn(err, message, msglen);
-                   if (ckWARN(WARN_MISC)) {
-                       const STRLEN start = SvCUR(err)-msglen-sizeof(prefix)+1;
-                       Perl_warner(aTHX_ packWARN(WARN_MISC), SvPVX_const(err)+start);
-                   }
+                   sv_catsv(err, msv);
+                   start = SvCUR(err)-SvCUR(msv)-sizeof(prefix)+1;
+                   Perl_ck_warner(aTHX_ packWARN(WARN_MISC), "%s",
+                                  SvPVX_const(err)+start);
                }
            }
            else {
+               STRLEN msglen;
+               const char* message = SvPV_const(msv, msglen);
                sv_setpvn(ERRSV, message, msglen);
+               SvFLAGS(ERRSV) |= SvFLAGS(msv) & SVf_UTF8;
            }
        }
 
@@ -1540,8 +1603,8 @@ Perl_die_where(pTHX_ const char *message, STRLEN msglen)
 
            POPBLOCK(cx,PL_curpm);
            if (CxTYPE(cx) != CXt_EVAL) {
-               if (!message)
-                   message = SvPVx_const(ERRSV, msglen);
+               STRLEN msglen;
+               const char* message = SvPVx_const( msv ? msv : ERRSV, msglen);
                PerlIO_write(Perl_error_log, (const char *)"panic: die ", 11);
                PerlIO_write(Perl_error_log, message, msglen);
                my_exit(1);
@@ -1569,16 +1632,15 @@ Perl_die_where(pTHX_ const char *message, STRLEN msglen)
                    *msg ? msg : "Unknown error\n");
            }
            assert(CxTYPE(cx) == CXt_EVAL);
-           return cx->blk_eval.retop;
+           PL_restartop = cx->blk_eval.retop;
+           JMPENV_JUMP(3);
+           /* NOTREACHED */
        }
     }
-    if (!message)
-       message = SvPVx_const(ERRSV, msglen);
 
-    write_to_stderr(message, msglen);
+    write_to_stderr( msv ? msv : ERRSV );
     my_failure_exit();
     /* NOTREACHED */
-    return 0;
 }
 
 PP(pp_xor)
@@ -1712,9 +1774,8 @@ PP(pp_caller)
        const int off = AvARRAY(ary) - AvALLOC(ary);
 
        if (!PL_dbargs) {
-           GV* const tmpgv = gv_fetchpvs("DB::args", GV_ADD, SVt_PVAV);
-           PL_dbargs = GvAV(gv_AVadd(tmpgv));
-           GvMULTI_on(tmpgv);
+           PL_dbargs = GvAV(gv_AVadd(gv_fetchpvs("DB::args", GV_ADDMULTI,
+                                                 SVt_PVAV)));
            AvREAL_off(PL_dbargs);      /* XXX should be REIFY (see av.h) */
        }
 
@@ -1739,7 +1800,7 @@ PP(pp_caller)
            /* Get the bit mask for $warnings::Bits{all}, because
             * it could have been extended by warnings::register */
            SV **bits_all;
-           HV * const bits = get_hv("warnings::Bits", FALSE);
+           HV * const bits = get_hv("warnings::Bits", 0);
            if (bits && (bits_all=hv_fetchs(bits, "all", FALSE))) {
                mask = newSVsv(*bits_all);
            }
@@ -1754,8 +1815,8 @@ PP(pp_caller)
 
     PUSHs(cx->blk_oldcop->cop_hints_hash ?
          sv_2mortal(newRV_noinc(
-           (SV*)Perl_refcounted_he_chain_2hv(aTHX_
-                                             cx->blk_oldcop->cop_hints_hash)))
+                                MUTABLE_SV(Perl_refcounted_he_chain_2hv(aTHX_
+                                             cx->blk_oldcop->cop_hints_hash))))
          : &PL_sv_undef);
     RETURN;
 }
@@ -1797,7 +1858,7 @@ PP(pp_dbstate)
            /* don't do recursive DB::DB call */
            return NORMAL;
 
-       ENTER;
+       ENTER_with_name("sub");
        SAVETMPS;
 
        SAVEI32(PL_debug);
@@ -1812,7 +1873,7 @@ PP(pp_dbstate)
            (void)(*CvXSUB(cv))(aTHX_ cv);
            CvDEPTH(cv)--;
            FREETMPS;
-           LEAVE;
+           LEAVE_with_name("sub");
            return NORMAL;
        }
        else {
@@ -1837,10 +1898,10 @@ PP(pp_enteriter)
     SV **svp;
     U8 cxtype = CXt_LOOP_FOR;
 #ifdef USE_ITHREADS
-    void *iterdata;
+    PAD *iterdata;
 #endif
 
-    ENTER;
+    ENTER_with_name("loop1");
     SAVETMPS;
 
     if (PL_op->op_targ) {
@@ -1849,35 +1910,33 @@ PP(pp_enteriter)
            SAVESETSVFLAGS(PAD_SVl(PL_op->op_targ),
                    SVs_PADSTALE, SVs_PADSTALE);
        }
+       SAVEPADSVANDMORTALIZE(PL_op->op_targ);
 #ifndef USE_ITHREADS
        svp = &PAD_SVl(PL_op->op_targ);         /* "my" variable */
-       SAVESPTR(*svp);
 #else
-       SAVEPADSV(PL_op->op_targ);
-       iterdata = INT2PTR(void*, PL_op->op_targ);
-       cxtype |= CXp_PADVAR;
+       iterdata = NULL;
 #endif
     }
     else {
-       GV * const gv = (GV*)POPs;
+       GV * const gv = MUTABLE_GV(POPs);
        svp = &GvSV(gv);                        /* symbol table variable */
        SAVEGENERICSV(*svp);
        *svp = newSV(0);
 #ifdef USE_ITHREADS
-       iterdata = (void*)gv;
+       iterdata = (PAD*)gv;
 #endif
     }
 
     if (PL_op->op_private & OPpITER_DEF)
        cxtype |= CXp_FOR_DEF;
 
-    ENTER;
+    ENTER_with_name("loop2");
 
     PUSHBLOCK(cx, cxtype, SP);
 #ifdef USE_ITHREADS
-    PUSHLOOP_FOR(cx, iterdata, MARK);
+    PUSHLOOP_FOR(cx, iterdata, MARK, PL_op->op_targ);
 #else
-    PUSHLOOP_FOR(cx, svp, MARK);
+    PUSHLOOP_FOR(cx, svp, MARK, 0);
 #endif
     if (PL_op->op_flags & OPf_STACKED) {
        SV *maybe_ary = POPs;
@@ -1941,7 +2000,7 @@ PP(pp_enteriter)
            }
        }
        else /* SvTYPE(maybe_ary) == SVt_PVAV */ {
-           cx->blk_loop.state_u.ary.ary = (AV*)maybe_ary;
+           cx->blk_loop.state_u.ary.ary = MUTABLE_AV(maybe_ary);
            SvREFCNT_inc(maybe_ary);
            cx->blk_loop.state_u.ary.ix =
                (PL_op->op_private & OPpITER_REVERSED) ?
@@ -1968,9 +2027,9 @@ PP(pp_enterloop)
     register PERL_CONTEXT *cx;
     const I32 gimme = GIMME_V;
 
-    ENTER;
+    ENTER_with_name("loop1");
     SAVETMPS;
-    ENTER;
+    ENTER_with_name("loop2");
 
     PUSHBLOCK(cx, CXt_LOOP_PLAIN, SP);
     PUSHLOOP_PLAIN(cx, SP);
@@ -2013,8 +2072,8 @@ PP(pp_leaveloop)
     POPLOOP(cx);       /* Stack values are safe: release loop vars ... */
     PL_curpm = newpm;  /* ... and pop $1 et al */
 
-    LEAVE;
-    LEAVE;
+    LEAVE_with_name("loop2");
+    LEAVE_with_name("loop1");
 
     return NORMAL;
 }
@@ -2138,8 +2197,9 @@ PP(pp_return)
     PL_curpm = newpm;  /* ... and pop $1 et al */
 
     LEAVESUB(sv);
-    if (clear_errsv)
-       sv_setpvn(ERRSV,"",0);
+    if (clear_errsv) {
+       CLEAR_ERRSV();
+    }
     return retop;
 }
 
@@ -2314,6 +2374,8 @@ S_dofindlabel(pTHX_ OP *o, const char *label, OP **opstack, OP **oplimit)
     OP **ops = opstack;
     static const char too_deep[] = "Target of goto is too deeply nested";
 
+    PERL_ARGS_ASSERT_DOFINDLABEL;
+
     if (ops >= oplimit)
        Perl_croak(aTHX_ too_deep);
     if (o->op_type == OP_LEAVE ||
@@ -2332,7 +2394,7 @@ S_dofindlabel(pTHX_ OP *o, const char *label, OP **opstack, OP **oplimit)
        /* First try all the kids at this level, since that's likeliest. */
        for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) {
            if ((kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) &&
-                   kCOP->cop_label && strEQ(kCOP->cop_label, label))
+                   CopLABEL(kCOP) && strEQ(CopLABEL(kCOP), label))
                return kid;
        }
        for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) {
@@ -2374,7 +2436,7 @@ PP(pp_goto)
        if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV) {
            I32 cxix;
            register PERL_CONTEXT *cx;
-           CV* cv = (CV*)SvRV(sv);
+           CV *cv = MUTABLE_CV(SvRV(sv));
            SV** mark;
            I32 items = 0;
            I32 oldsave;
@@ -2436,7 +2498,7 @@ PP(pp_goto)
                    av = newAV();
                    av_extend(av, items-1);
                    AvREIFY_only(av);
-                   PAD_SVl(0) = (SV*)(cx->blk_sub.argarray = av);
+                   PAD_SVl(0) = MUTABLE_SV(cx->blk_sub.argarray = av);
                }
            }
            else if (CvISXSUB(cv)) {    /* put GvAV(defgv) back onto stack */
@@ -2472,7 +2534,7 @@ PP(pp_goto)
                PUSHMARK(mark);
                PUTBACK;
                (void)(*CvXSUB(cv))(aTHX_ cv);
-               LEAVE;
+               LEAVE_with_name("sub");
                return retop;
            }
            else {
@@ -2497,10 +2559,10 @@ PP(pp_goto)
                PAD_SET_CUR_NOSAVE(padlist, CvDEPTH(cv));
                if (CxHASARGS(cx))
                {
-                   AV* const av = (AV*)PAD_SVl(0);
+                   AV *const av = MUTABLE_AV(PAD_SVl(0));
 
                    cx->blk_sub.savearray = GvAV(PL_defgv);
-                   GvAV(PL_defgv) = (AV*)SvREFCNT_inc_simple(av);
+                   GvAV(PL_defgv) = MUTABLE_AV(SvREFCNT_inc_simple(av));
                    CX_CURPAD_SAVE(cx->blk_sub);
                    cx->blk_sub.argarray = av;
 
@@ -2535,10 +2597,10 @@ PP(pp_goto)
                if (PERLDB_SUB) {       /* Checking curstash breaks DProf. */
                    Perl_get_db_sub(aTHX_ NULL, cv);
                    if (PERLDB_GOTO) {
-                       CV * const gotocv = get_cv("DB::goto", FALSE);
+                       CV * const gotocv = get_cvs("DB::goto", 0);
                        if (gotocv) {
                            PUSHMARK( PL_stack_sp );
-                           call_sv((SV*)gotocv, G_SCALAR | G_NODEBUG);
+                           call_sv(MUTABLE_SV(gotocv), G_SCALAR | G_NODEBUG);
                            PL_stack_sp--;
                        }
                    }
@@ -2586,6 +2648,8 @@ PP(pp_goto)
            case CXt_LOOP_LAZYSV:
            case CXt_LOOP_FOR:
            case CXt_LOOP_PLAIN:
+           case CXt_GIVEN:
+           case CXt_WHEN:
                gotoprobe = cx->blk_oldcop->op_sibling;
                break;
            case CXt_SUBST:
@@ -2717,11 +2781,13 @@ S_save_lines(pTHX_ AV *array, SV *sv)
     const char * const send = SvPVX_const(sv) + SvCUR(sv);
     I32 line = 1;
 
+    PERL_ARGS_ASSERT_SAVE_LINES;
+
     while (s && s < send) {
        const char *t;
        SV * const tmpstr = newSV_type(SVt_PVMG);
 
-       t = strchr(s, '\n');
+       t = (const char *)memchr(s, '\n', send - s);
        if (t)
            t++;
        else
@@ -2804,7 +2870,9 @@ Perl_sv_compile_2op(pTHX_ SV *sv, OP** startop, const char *code, PAD** padp)
     CV* runcv = NULL;  /* initialise to avoid compiler warnings */
     STRLEN len;
 
-    ENTER;
+    PERL_ARGS_ASSERT_SV_COMPILE_2OP;
+
+    ENTER_with_name("eval");
     lex_start(sv, NULL, FALSE);
     SAVETMPS;
     /* switch to eval mode */
@@ -2851,7 +2919,7 @@ Perl_sv_compile_2op(pTHX_ SV *sv, OP** startop, const char *code, PAD** padp)
     PL_op->op_type = OP_ENTEREVAL;
     PL_op->op_flags = 0;                       /* Avoid uninit warning. */
     PUSHBLOCK(cx, CXt_EVAL|(IN_PERL_COMPILETIME ? 0 : CXp_REAL), SP);
-    PUSHEVAL(cx, 0, NULL);
+    PUSHEVAL(cx, 0);
 
     if (runtime)
        (void) doeval(G_SCALAR, startop, runcv, PL_curcop->cop_seq);
@@ -2864,8 +2932,8 @@ Perl_sv_compile_2op(pTHX_ SV *sv, OP** startop, const char *code, PAD** padp)
     (*startop)->op_ppaddr = PL_ppaddr[OP_NULL];
     lex_end();
     /* XXX DAPM do this properly one year */
-    *padp = (AV*)SvREFCNT_inc_simple(PL_comppad);
-    LEAVE;
+    *padp = MUTABLE_AV(SvREFCNT_inc_simple(PL_comppad));
+    LEAVE_with_name("eval");
     if (IN_PERL_COMPILETIME)
        CopHINTS_set(&PL_compiling, PL_hints);
 #ifdef OP_IN_REGISTER
@@ -2941,13 +3009,13 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 seq)
     PUSHMARK(SP);
 
     SAVESPTR(PL_compcv);
-    PL_compcv = (CV*)newSV_type(SVt_PVCV);
+    PL_compcv = MUTABLE_CV(newSV_type(SVt_PVCV));
     CvEVAL_on(PL_compcv);
     assert(CxTYPE(&cxstack[cxstack_ix]) == CXt_EVAL);
     cxstack[cxstack_ix].blk_eval.cv = PL_compcv;
 
     CvOUTSIDE_SEQ(PL_compcv) = seq;
-    CvOUTSIDE(PL_compcv) = (CV*)SvREFCNT_inc_simple(outside);
+    CvOUTSIDE(PL_compcv) = MUTABLE_CV(SvREFCNT_inc_simple(outside));
 
     /* set up a scratch pad */
 
@@ -2985,7 +3053,7 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 seq)
     if (saveop && (saveop->op_type != OP_REQUIRE) && (saveop->op_flags & OPf_SPECIAL))
        PL_in_eval |= EVAL_KEEPERR;
     else
-       sv_setpvn(ERRSV,"",0);
+       CLEAR_ERRSV();
     if (yyparse() || PL_parser->error_count || !PL_eval_root) {
        SV **newsp;                     /* Used by POPBLOCK. */
        PERL_CONTEXT *cx = &cxstack[cxstack_ix];
@@ -3003,7 +3071,7 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 seq)
            POPEVAL(cx);
        }
        lex_end();
-       LEAVE;
+       LEAVE_with_name("eval"); /* pp_entereval knows about this LEAVE.  */
 
        msg = SvPVx_nolen_const(ERRSV);
        if (optype == OP_REQUIRE) {
@@ -3054,13 +3122,13 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 seq)
 
     /* Register with debugger: */
     if (PERLDB_INTER && saveop && saveop->op_type == OP_REQUIRE) {
-       CV * const cv = get_cv("DB::postponed", FALSE);
+       CV * const cv = get_cvs("DB::postponed", 0);
        if (cv) {
            dSP;
            PUSHMARK(SP);
-           XPUSHs((SV*)CopFILEGV(&PL_compiling));
+           XPUSHs(MUTABLE_SV(CopFILEGV(&PL_compiling)));
            PUTBACK;
-           call_sv((SV*)cv, G_DISCARD);
+           call_sv(MUTABLE_SV(cv), G_DISCARD);
        }
     }
 
@@ -3084,6 +3152,8 @@ S_check_type_and_open(pTHX_ const char *name)
     Stat_t st;
     const int st_rc = PerlLIO_stat(name, &st);
 
+    PERL_ARGS_ASSERT_CHECK_TYPE_AND_OPEN;
+
     if (st_rc < 0 || S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode)) {
        return NULL;
     }
@@ -3097,6 +3167,8 @@ S_doopen_pm(pTHX_ const char *name, const STRLEN namelen)
 {
     PerlIO *fp;
 
+    PERL_ARGS_ASSERT_DOOPEN_PM;
+
     if (namelen > 3 && memEQs(name + namelen - 3, 3, ".pm")) {
        SV *const pmcsv = newSV(namelen + 2);
        char *const pmc = SvPVX(pmcsv);
@@ -3162,14 +3234,14 @@ PP(pp_require)
                I32 first = 0;
                AV *lav;
                SV * const req = SvRV(sv);
-               SV * const pv = *hv_fetchs((HV*)req, "original", FALSE);
+               SV * const pv = *hv_fetchs(MUTABLE_HV(req), "original", FALSE);
 
                /* get the left hand term */
-               lav = (AV *)SvRV(*hv_fetchs((HV*)req, "version", FALSE));
+               lav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(req), "version", FALSE)));
 
                first  = SvIV(*av_fetch(lav,0,0));
                if (   first > (int)PERL_REVISION    /* probably 'use 6.0' */
-                   || hv_exists((HV*)req, "qv", 2 ) /* qv style */
+                   || hv_exists(MUTABLE_HV(req), "qv", 2 ) /* qv style */
                    || av_len(lav) > 1               /* FP with > 3 digits */
                    || strstr(SvPVX(pv),".0")        /* FP with leading 0 */
                   ) {
@@ -3205,9 +3277,14 @@ PP(pp_require)
                vcmp(sv, sv_2mortal(upg_version(newSVnv(5.009005), FALSE))) >= 0) {
            SV *const importsv = vnormal(sv);
            *SvPVX_mutable(importsv) = ':';
-           ENTER;
+           ENTER_with_name("load_feature");
            Perl_load_module(aTHX_ 0, newSVpvs("feature"), NULL, importsv, NULL);
-           LEAVE;
+           LEAVE_with_name("load_feature");
+       }
+       /* If a version >= 5.11.0 is requested, strictures are on by default! */
+       if (PL_compcv &&
+               vcmp(sv, sv_2mortal(upg_version(newSVnv(5.011000), FALSE))) >= 0) {
+           PL_hints |= (HINT_STRICT_REFS | HINT_STRICT_SUBS | HINT_STRICT_VARS);
        }
 
        RETPUSHYES;
@@ -3256,17 +3333,6 @@ PP(pp_require)
        tryname = name;
        tryrsfp = doopen_pm(name, len);
     }
-#ifdef MACOS_TRADITIONAL
-    if (!tryrsfp) {
-       char newname[256];
-
-       MacPerl_CanonDir(name, newname, 1);
-       if (path_is_absolute(newname)) {
-           tryname = newname;
-           tryrsfp = doopen_pm(newname, strlen(newname));
-       }
-    }
-#endif
     if (!tryrsfp) {
        AV * const ar = GvAVn(PL_incgv);
        I32 i;
@@ -3278,7 +3344,7 @@ PP(pp_require)
            for (i = 0; i <= AvFILL(ar); i++) {
                SV * const dirsv = *av_fetch(ar, i, TRUE);
 
-               if (SvTIED_mg((SV*)ar, PERL_MAGIC_tied))
+               if (SvTIED_mg((const SV *)ar, PERL_MAGIC_tied))
                    mg_get(dirsv);
                if (SvROK(dirsv)) {
                    int count;
@@ -3288,7 +3354,7 @@ PP(pp_require)
                    if (SvTYPE(SvRV(loader)) == SVt_PVAV
                        && !sv_isobject(loader))
                    {
-                       loader = *av_fetch((AV *)SvRV(loader), 0, TRUE);
+                       loader = *av_fetch(MUTABLE_AV(SvRV(loader)), 0, TRUE);
                    }
 
                    Perl_sv_setpvf(aTHX_ namesv, "/loader/0x%"UVxf"/%s",
@@ -3296,7 +3362,7 @@ PP(pp_require)
                    tryname = SvPVX_const(namesv);
                    tryrsfp = NULL;
 
-                   ENTER;
+                   ENTER_with_name("call_INC");
                    SAVETMPS;
                    EXTEND(SP, 2);
 
@@ -3313,7 +3379,7 @@ PP(pp_require)
                    /* Adjust file name if the hook has set an %INC entry */
                    svp = hv_fetch(GvHVn(PL_incgv), name, len, 0);
                    if (svp)
-                       tryname = SvPVX_const(*svp);
+                       tryname = SvPV_nolen_const(*svp);
 
                    if (count > 0) {
                        int i = 0;
@@ -3332,12 +3398,12 @@ PP(pp_require)
                            }
                        }
 
-                       if (SvROK(arg) && SvTYPE(SvRV(arg)) == SVt_PVGV) {
+                       if (SvROK(arg) && isGV_with_GP(SvRV(arg))) {
                            arg = SvRV(arg);
                        }
 
-                       if (SvTYPE(arg) == SVt_PVGV) {
-                           IO * const io = GvIO((GV *)arg);
+                       if (isGV_with_GP(arg)) {
+                           IO * const io = GvIO((const GV *)arg);
 
                            ++filter_has_file;
 
@@ -3374,7 +3440,7 @@ PP(pp_require)
 
                    PUTBACK;
                    FREETMPS;
-                   LEAVE;
+                   LEAVE_with_name("call_INC");
 
                    if (tryrsfp) {
                        hook_sv = dirsv;
@@ -3397,12 +3463,6 @@ PP(pp_require)
                }
                else {
                  if (!path_is_absolute(name)
-#ifdef MACOS_TRADITIONAL
-                       /* We consider paths of the form :a:b ambiguous and interpret them first
-                          as global then as local
-                       */
-                       || (*name == ':' && name[1] != ':' && strchr(name+2, ':'))
-#endif
                  ) {
                    const char *dir;
                    STRLEN dirlen;
@@ -3414,21 +3474,14 @@ PP(pp_require)
                        dirlen = 0;
                    }
 
-#ifdef MACOS_TRADITIONAL
-                   char buf1[256];
-                   char buf2[256];
-
-                   MacPerl_CanonDir(name, buf2, 1);
-                   Perl_sv_setpvf(aTHX_ namesv, "%s%s", MacPerl_CanonDir(dir, buf1, 0), buf2+(buf2[0] == ':'));
-#else
-#  ifdef VMS
+#ifdef VMS
                    char *unixdir;
                    if ((unixdir = tounixpath(dir, NULL)) == NULL)
                        continue;
                    sv_setpv(namesv, unixdir);
                    sv_catpv(namesv, unixname);
-#  else
-#    ifdef __SYMBIAN32__
+#else
+#  ifdef __SYMBIAN32__
                    if (PL_origfilename[0] &&
                        PL_origfilename[1] == ':' &&
                        !(dir[0] && dir[1] == ':'))
@@ -3440,7 +3493,7 @@ PP(pp_require)
                        Perl_sv_setpvf(aTHX_ namesv,
                                       "%s\\%s",
                                       dir, name);
-#    else
+#  else
                    /* The equivalent of                    
                       Perl_sv_setpvf(aTHX_ namesv, "%s/%s", dir, name);
                       but without the need to parse the format string, or
@@ -3461,15 +3514,16 @@ PP(pp_require)
                        /* Don't even actually have to turn SvPOK_on() as we
                           access it directly with SvPVX() below.  */
                    }
-#    endif
 #  endif
 #endif
                    TAINT_PROPER("require");
                    tryname = SvPVX_const(namesv);
                    tryrsfp = doopen_pm(tryname, SvCUR(namesv));
                    if (tryrsfp) {
-                       if (tryname[0] == '.' && tryname[1] == '/')
-                           tryname += 2;
+                       if (tryname[0] == '.' && tryname[1] == '/') {
+                           ++tryname;
+                           while (*++tryname == '/');
+                       }
                        break;
                    }
                    else if (errno == EMFILE)
@@ -3533,12 +3587,14 @@ PP(pp_require)
                           unixname, unixlen, SvREFCNT_inc_simple(hook_sv), 0 );
     }
 
-    ENTER;
+    ENTER_with_name("eval");
     SAVETMPS;
     lex_start(NULL, tryrsfp, TRUE);
 
     SAVEHINTS();
     PL_hints = 0;
+    hv_clear(GvHV(PL_hintgv));
+
     SAVECOMPILEWARNINGS();
     if (PL_dowarn & G_WARN_ALL_ON)
         PL_compiling.cop_warnings = pWARN_ALL ;
@@ -3548,16 +3604,19 @@ PP(pp_require)
         PL_compiling.cop_warnings = pWARN_STD ;
 
     if (filter_sub || filter_cache) {
-       SV * const datasv = filter_add(S_run_user_filter, NULL);
+       /* We can use the SvPV of the filter PVIO itself as our cache, rather
+          than hanging another SV from it. In turn, filter_add() optionally
+          takes the SV to use as the filter (or creates a new SV if passed
+          NULL), so simply pass in whatever value filter_cache has.  */
+       SV * const datasv = filter_add(S_run_user_filter, filter_cache);
        IoLINES(datasv) = filter_has_file;
-       IoTOP_GV(datasv) = (GV *)filter_state;
-       IoBOTTOM_GV(datasv) = (GV *)filter_sub;
-       IoFMT_GV(datasv) = (GV *)filter_cache;
+       IoTOP_GV(datasv) = MUTABLE_GV(filter_state);
+       IoBOTTOM_GV(datasv) = MUTABLE_GV(filter_sub);
     }
 
     /* switch to eval mode */
     PUSHBLOCK(cx, CXt_EVAL, SP);
-    PUSHEVAL(cx, name, NULL);
+    PUSHEVAL(cx, name);
     cx->blk_eval.retop = PL_op->op_next;
 
     SAVECOPLINE(&PL_compiling);
@@ -3580,33 +3639,42 @@ PP(pp_require)
     return op;
 }
 
+/* This is a op added to hold the hints hash for
+   pp_entereval. The hash can be modified by the code
+   being eval'ed, so we return a copy instead. */
+
+PP(pp_hintseval)
+{
+    dVAR;
+    dSP;
+    mXPUSHs(MUTABLE_SV(Perl_hv_copy_hints_hv(aTHX_ MUTABLE_HV(cSVOP_sv))));
+    RETURN;
+}
+
+
 PP(pp_entereval)
 {
     dVAR; dSP;
     register PERL_CONTEXT *cx;
     SV *sv;
     const I32 gimme = GIMME_V;
-    const I32 was = PL_sub_generation;
+    const U32 was = PL_breakable_sub_gen;
     char tbuf[TYPE_DIGITS(long) + 12];
     char *tmpbuf = tbuf;
-    char *safestr;
     STRLEN len;
-    bool ok;
     CV* runcv;
     U32 seq;
     HV *saved_hh = NULL;
-    const char * const fakestr = "_<(eval )";
-    const int fakelen = 9 + 1;
-    
+
     if (PL_op->op_private & OPpEVAL_HAS_HH) {
-       saved_hh = (HV*) SvREFCNT_inc(POPs);
+       saved_hh = MUTABLE_HV(SvREFCNT_inc(POPs));
     }
     sv = POPs;
 
     TAINT_IF(SvTAINTED(sv));
     TAINT_PROPER("eval");
 
-    ENTER;
+    ENTER_with_name("eval");
     lex_start(sv, NULL, FALSE);
     SAVETMPS;
 
@@ -3631,12 +3699,13 @@ PP(pp_entereval)
        (i.e. before run-time proper). To work around the coredump that
        ensues, we always turn GvMULTI_on for any globals that were
        introduced within evals. See force_ident(). GSAR 96-10-12 */
-    safestr = savepvn(tmpbuf, len);
-    SAVEDELETE(PL_defstash, safestr, len);
     SAVEHINTS();
     PL_hints = PL_op->op_targ;
-    if (saved_hh)
+    if (saved_hh) {
+       /* SAVEHINTS created a new HV in PL_hintgv, which we need to GC */
+       SvREFCNT_dec(GvHV(PL_hintgv));
        GvHV(PL_hintgv) = saved_hh;
+    }
     SAVECOMPILEWARNINGS();
     PL_compiling.cop_warnings = DUP_WARNINGS(PL_curcop->cop_warnings);
     if (PL_compiling.cop_hints_hash) {
@@ -3656,21 +3725,37 @@ PP(pp_entereval)
     runcv = find_runcv(&seq);
 
     PUSHBLOCK(cx, (CXt_EVAL|CXp_REAL), SP);
-    PUSHEVAL(cx, 0, NULL);
+    PUSHEVAL(cx, 0);
     cx->blk_eval.retop = PL_op->op_next;
 
     /* prepare to compile string */
 
-    if (PERLDB_LINE && PL_curstash != PL_debstash)
+    if ((PERLDB_LINE || PERLDB_SAVESRC) && PL_curstash != PL_debstash)
        save_lines(CopFILEAV(&PL_compiling), PL_parser->linestr);
     PUTBACK;
-    ok = doeval(gimme, NULL, runcv, seq);
-    if (PERLDB_INTER && was != (I32)PL_sub_generation /* Some subs defined here. */
-       && ok) {
-       /* Copy in anything fake and short. */
-       my_strlcpy(safestr, fakestr, fakelen);
+
+    if (doeval(gimme, NULL, runcv, seq)) {
+       if (was != PL_breakable_sub_gen /* Some subs defined here. */
+           ? (PERLDB_LINE || PERLDB_SAVESRC)
+           :  PERLDB_SAVESRC_NOSUBS) {
+           /* Retain the filegv we created.  */
+       } else {
+           char *const safestr = savepvn(tmpbuf, len);
+           SAVEDELETE(PL_defstash, safestr, len);
+       }
+       return DOCATCH(PL_eval_start);
+    } else {
+       /* We have already left the scope set up earler thanks to the LEAVE
+          in doeval().  */
+       if (was != PL_breakable_sub_gen /* Some subs defined here. */
+           ? (PERLDB_LINE || PERLDB_SAVESRC)
+           :  PERLDB_SAVESRC_INVALID) {
+           /* Retain the filegv we created.  */
+       } else {
+           (void)hv_delete(PL_defstash, tmpbuf, len, G_DISCARD);
+       }
+       return PL_op->op_next;
     }
-    return ok ? DOCATCH(PL_eval_start) : PL_op->op_next;
 }
 
 PP(pp_leaveeval)
@@ -3733,9 +3818,10 @@ PP(pp_leaveeval)
        /* die_where() did LEAVE, or we won't be here */
     }
     else {
-       LEAVE;
-       if (!(save_flags & OPf_SPECIAL))
-           sv_setpvn(ERRSV,"",0);
+       LEAVE_with_name("eval");
+       if (!(save_flags & OPf_SPECIAL)) {
+           CLEAR_ERRSV();
+       }
     }
 
     RETURNOP(retop);
@@ -3755,7 +3841,7 @@ Perl_delete_eval_scope(pTHX)
     POPBLOCK(cx,newpm);
     POPEVAL(cx);
     PL_curpm = newpm;
-    LEAVE;
+    LEAVE_with_name("eval_scope");
     PERL_UNUSED_VAR(newsp);
     PERL_UNUSED_VAR(gimme);
     PERL_UNUSED_VAR(optype);
@@ -3769,17 +3855,17 @@ Perl_create_eval_scope(pTHX_ U32 flags)
     PERL_CONTEXT *cx;
     const I32 gimme = GIMME_V;
        
-    ENTER;
+    ENTER_with_name("eval_scope");
     SAVETMPS;
 
     PUSHBLOCK(cx, (CXt_EVAL|CXp_TRYBLOCK), PL_stack_sp);
-    PUSHEVAL(cx, 0, 0);
+    PUSHEVAL(cx, 0);
 
     PL_in_eval = EVAL_INEVAL;
     if (flags & G_KEEPERR)
        PL_in_eval |= EVAL_KEEPERR;
     else
-       sv_setpvn(ERRSV,"",0);
+       CLEAR_ERRSV();
     if (flags & G_FAKINGEVAL) {
        PL_eval_root = PL_op; /* Only needed so that goto works right. */
     }
@@ -3837,8 +3923,8 @@ PP(pp_leavetry)
     }
     PL_curpm = newpm;  /* Don't pop $1 et al till now */
 
-    LEAVE;
-    sv_setpvn(ERRSV,"",0);
+    LEAVE_with_name("eval_scope");
+    CLEAR_ERRSV();
     RETURN;
 }
 
@@ -3848,16 +3934,10 @@ PP(pp_entergiven)
     register PERL_CONTEXT *cx;
     const I32 gimme = GIMME_V;
     
-    ENTER;
+    ENTER_with_name("given");
     SAVETMPS;
 
-    if (PL_op->op_targ == 0) {
-       SV ** const defsv_p = &GvSV(PL_defgv);
-       *defsv_p = newSVsv(POPs);
-       SAVECLEARSV(*defsv_p);
-    }
-    else
-       sv_setsv(PAD_SV(PL_op->op_targ), POPs);
+    sv_setsv(PAD_SV(PL_op->op_targ), POPs);
 
     PUSHBLOCK(cx, CXt_GIVEN, SP);
     PUSHGIVEN(cx);
@@ -3882,7 +3962,7 @@ PP(pp_leavegiven)
 
     PL_curpm = newpm;   /* pop $1 et al */
 
-    LEAVE;
+    LEAVE_with_name("given");
 
     return NORMAL;
 }
@@ -3893,10 +3973,13 @@ S_make_matcher(pTHX_ REGEXP *re)
 {
     dVAR;
     PMOP *matcher = (PMOP *) newPMOP(OP_MATCH, OPf_WANT_SCALAR | OPf_STACKED);
+
+    PERL_ARGS_ASSERT_MAKE_MATCHER;
+
     PM_SETRE(matcher, ReREFCNT_inc(re));
-    
+
     SAVEFREEOP((OP *) matcher);
-    ENTER; SAVETMPS;
+    ENTER_with_name("matcher"); SAVETMPS;
     SAVEOP();
     return matcher;
 }
@@ -3906,6 +3989,8 @@ S_matcher_matches_sv(pTHX_ PMOP *matcher, SV *sv)
 {
     dVAR;
     dSP;
+
+    PERL_ARGS_ASSERT_MATCHER_MATCHES_SV;
     
     PL_op = (OP *) matcher;
     XPUSHs(sv);
@@ -3919,14 +4004,18 @@ STATIC void
 S_destroy_matcher(pTHX_ PMOP *matcher)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_DESTROY_MATCHER;
     PERL_UNUSED_ARG(matcher);
+
     FREETMPS;
-    LEAVE;
+    LEAVE_with_name("matcher");
 }
 
 /* Do a smart match */
 PP(pp_smartmatch)
 {
+    DEBUG_M(Perl_deb(aTHX_ "Starting smart match resolution\n"));
     return do_smartmatch(NULL, NULL);
 }
 
@@ -3939,49 +4028,26 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
     dVAR;
     dSP;
     
+    bool object_on_left = FALSE;
     SV *e = TOPs;      /* e is for 'expression' */
     SV *d = TOPm1s;    /* d is for 'default', as in PL_defgv */
-    SV *This, *Other;  /* 'This' (and Other to match) to play with C++ */
-    REGEXP *this_regex, *other_regex;
-
-#   define NOT_EMPTY_PROTO(cv) (!SvPOK(cv) || SvCUR(cv) == 0)
-
-#   define SM_REF(type) ( \
-          (SvROK(d) && (SvTYPE(This = SvRV(d)) == SVt_##type) && (Other = e)) \
-       || (SvROK(e) && (SvTYPE(This = SvRV(e)) == SVt_##type) && (Other = d)))
-
-#   define SM_CV_NEP   /* Find a code ref without an empty prototype */ \
-       ((SvROK(d) && (SvTYPE(This = SvRV(d)) == SVt_PVCV)              \
-           && NOT_EMPTY_PROTO(This) && (Other = e))                    \
-       || (SvROK(e) && (SvTYPE(This = SvRV(e)) == SVt_PVCV)            \
-           && NOT_EMPTY_PROTO(This) && (Other = d)))
-
-#   define SM_REGEX ( \
-          (SvROK(d) && (SvTYPE(This = SvRV(d)) == SVt_REGEXP)          \
-       && (this_regex = (REGEXP*) This)                                \
-       && (Other = e))                                                 \
-    ||                                                                 \
-          (SvROK(e) && (SvTYPE(This = SvRV(e)) == SVt_REGEXP)          \
-       && (this_regex = (REGEXP*) This)                                \
-       && (Other = d)) )
-       
-
-#   define SM_OTHER_REF(type) \
-       (SvROK(Other) && SvTYPE(SvRV(Other)) == SVt_##type)
-
-#   define SM_OTHER_REGEX (SvROK(Other)                                        \
-       && (SvTYPE(SvRV(Other)) == SVt_REGEXP)                          \
-       && (other_regex = (REGEXP*) SvRV(Other)))
 
+    /* First of all, handle overload magic of the rightmost argument */
+    if (SvAMAGIC(e)) {
+       SV * tmpsv;
+       DEBUG_M(Perl_deb(aTHX_ "    applying rule Any-Object\n"));
+       DEBUG_M(Perl_deb(aTHX_ "        attempting overload\n"));
 
-#   define SM_SEEN_THIS(sv) hv_exists_ent(seen_this, \
-       sv_2mortal(newSViv(PTR2IV(sv))), 0)
-
-#   define SM_SEEN_OTHER(sv) hv_exists_ent(seen_other, \
-       sv_2mortal(newSViv(PTR2IV(sv))), 0)
+       tmpsv = amagic_call(d, e, smart_amg, 0);
+       if (tmpsv) {
+           SPAGAIN;
+           (void)POPs;
+           SETs(tmpsv);
+           RETURN;
+       }
+       DEBUG_M(Perl_deb(aTHX_ "        failed to run overload method; continuing...\n"));
+    }
 
-    tryAMAGICbinSET(smart, 0);
-    
     SP -= 2;   /* Pop the values */
 
     /* Take care only to invoke mg_get() once for each argument. 
@@ -3997,69 +4063,156 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
     if (SvGMAGICAL(e))
        e = sv_mortalcopy(e);
 
-    if (SM_CV_NEP) {
+    /* ~~ undef */
+    if (!SvOK(e)) {
+       DEBUG_M(Perl_deb(aTHX_ "    applying rule Any-undef\n"));
+       if (SvOK(d))
+           RETPUSHNO;
+       else
+           RETPUSHYES;
+    }
+
+    if (sv_isobject(e) && (SvTYPE(SvRV(e)) != SVt_REGEXP)) {
+       DEBUG_M(Perl_deb(aTHX_ "    applying rule Any-Object\n"));
+       Perl_croak(aTHX_ "Smart matching a non-overloaded object breaks encapsulation");
+    }
+    if (sv_isobject(d) && (SvTYPE(SvRV(d)) != SVt_REGEXP))
+       object_on_left = TRUE;
+
+    /* ~~ sub */
+    if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVCV) {
        I32 c;
-       
-       if ( SM_OTHER_REF(PVCV) && NOT_EMPTY_PROTO(SvRV(Other)) )
-       {
-           if (This == SvRV(Other))
+       if (object_on_left) {
+           goto sm_any_sub; /* Treat objects like scalars */
+       }
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
+           /* Test sub truth for each key */
+           HE *he;
+           bool andedresults = TRUE;
+           HV *hv = (HV*) SvRV(d);
+           I32 numkeys = hv_iterinit(hv);
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Hash-CodeRef\n"));
+           if (numkeys == 0)
+               RETPUSHYES;
+           while ( (he = hv_iternext(hv)) ) {
+               DEBUG_M(Perl_deb(aTHX_ "        testing hash key...\n"));
+               ENTER_with_name("smartmatch_hash_key_test");
+               SAVETMPS;
+               PUSHMARK(SP);
+               PUSHs(hv_iterkeysv(he));
+               PUTBACK;
+               c = call_sv(e, G_SCALAR);
+               SPAGAIN;
+               if (c == 0)
+                   andedresults = FALSE;
+               else
+                   andedresults = SvTRUEx(POPs) && andedresults;
+               FREETMPS;
+               LEAVE_with_name("smartmatch_hash_key_test");
+           }
+           if (andedresults)
                RETPUSHYES;
            else
                RETPUSHNO;
        }
-       
-       ENTER;
-       SAVETMPS;
-       PUSHMARK(SP);
-       PUSHs(Other);
-       PUTBACK;
-       c = call_sv(This, G_SCALAR);
-       SPAGAIN;
-       if (c == 0)
-           PUSHs(&PL_sv_no);
-       else if (SvTEMP(TOPs))
-           SvREFCNT_inc_void(TOPs);
-       FREETMPS;
-       LEAVE;
-       RETURN;
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
+           /* Test sub truth for each element */
+           I32 i;
+           bool andedresults = TRUE;
+           AV *av = (AV*) SvRV(d);
+           const I32 len = av_len(av);
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Array-CodeRef\n"));
+           if (len == -1)
+               RETPUSHYES;
+           for (i = 0; i <= len; ++i) {
+               SV * const * const svp = av_fetch(av, i, FALSE);
+               DEBUG_M(Perl_deb(aTHX_ "        testing array element...\n"));
+               ENTER_with_name("smartmatch_array_elem_test");
+               SAVETMPS;
+               PUSHMARK(SP);
+               if (svp)
+                   PUSHs(*svp);
+               PUTBACK;
+               c = call_sv(e, G_SCALAR);
+               SPAGAIN;
+               if (c == 0)
+                   andedresults = FALSE;
+               else
+                   andedresults = SvTRUEx(POPs) && andedresults;
+               FREETMPS;
+               LEAVE_with_name("smartmatch_array_elem_test");
+           }
+           if (andedresults)
+               RETPUSHYES;
+           else
+               RETPUSHNO;
+       }
+       else {
+         sm_any_sub:
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Any-CodeRef\n"));
+           ENTER_with_name("smartmatch_coderef");
+           SAVETMPS;
+           PUSHMARK(SP);
+           PUSHs(d);
+           PUTBACK;
+           c = call_sv(e, G_SCALAR);
+           SPAGAIN;
+           if (c == 0)
+               PUSHs(&PL_sv_no);
+           else if (SvTEMP(TOPs))
+               SvREFCNT_inc_void(TOPs);
+           FREETMPS;
+           LEAVE_with_name("smartmatch_coderef");
+           RETURN;
+       }
     }
-    else if (SM_REF(PVHV)) {
-       if (SM_OTHER_REF(PVHV)) {
+    /* ~~ %hash */
+    else if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVHV) {
+       if (object_on_left) {
+           goto sm_any_hash; /* Treat objects like scalars */
+       }
+       else if (!SvOK(d)) {
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Any-Hash ($a undef)\n"));
+           RETPUSHNO;
+       }
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
            /* Check that the key-sets are identical */
            HE *he;
-           HV *other_hv = (HV *) SvRV(Other);
+           HV *other_hv = MUTABLE_HV(SvRV(d));
            bool tied = FALSE;
            bool other_tied = FALSE;
            U32 this_key_count  = 0,
                other_key_count = 0;
-           
+           HV *hv = MUTABLE_HV(SvRV(e));
+
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Hash-Hash\n"));
            /* Tied hashes don't know how many keys they have. */
-           if (SvTIED_mg(This, PERL_MAGIC_tied)) {
+           if (SvTIED_mg((SV*)hv, PERL_MAGIC_tied)) {
                tied = TRUE;
            }
-           else if (SvTIED_mg((SV *) other_hv, PERL_MAGIC_tied)) {
+           else if (SvTIED_mg((const SV *)other_hv, PERL_MAGIC_tied)) {
                HV * const temp = other_hv;
-               other_hv = (HV *) This;
-               This  = (SV *) temp;
+               other_hv = hv;
+               hv = temp;
                tied = TRUE;
            }
-           if (SvTIED_mg((SV *) other_hv, PERL_MAGIC_tied))
+           if (SvTIED_mg((const SV *)other_hv, PERL_MAGIC_tied))
                other_tied = TRUE;
            
-           if (!tied && HvUSEDKEYS((HV *) This) != HvUSEDKEYS(other_hv))
+           if (!tied && HvUSEDKEYS((const HV *) hv) != HvUSEDKEYS(other_hv))
                RETPUSHNO;
 
            /* The hashes have the same number of keys, so it suffices
               to check that one is a subset of the other. */
-           (void) hv_iterinit((HV *) This);
-           while ( (he = hv_iternext((HV *) This)) ) {
-               I32 key_len;
-               char * const key = hv_iterkey(he, &key_len);
-               
+           (void) hv_iterinit(hv);
+           while ( (he = hv_iternext(hv)) ) {
+               SV *key = hv_iterkeysv(he);
+
+               DEBUG_M(Perl_deb(aTHX_ "        comparing hash key...\n"));
                ++ this_key_count;
                
-               if(!hv_exists(other_hv, key, key_len)) {
-                   (void) hv_iterinit((HV *) This);    /* reset iterator */
+               if(!hv_exists_ent(other_hv, key, 0)) {
+                   (void) hv_iterinit(hv);     /* reset iterator */
                    RETPUSHNO;
                }
            }
@@ -4077,50 +4230,79 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
            else
                RETPUSHYES;
        }
-       else if (SM_OTHER_REF(PVAV)) {
-           AV * const other_av = (AV *) SvRV(Other);
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
+           AV * const other_av = MUTABLE_AV(SvRV(d));
            const I32 other_len = av_len(other_av) + 1;
            I32 i;
+           HV *hv = MUTABLE_HV(SvRV(e));
 
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Array-Hash\n"));
            for (i = 0; i < other_len; ++i) {
                SV ** const svp = av_fetch(other_av, i, FALSE);
-               char *key;
-               STRLEN key_len;
-
+               DEBUG_M(Perl_deb(aTHX_ "        checking for key existence...\n"));
                if (svp) {      /* ??? When can this not happen? */
-                   key = SvPV(*svp, key_len);
-                   if (hv_exists((HV *) This, key, key_len))
+                   if (hv_exists_ent(hv, *svp, 0))
                        RETPUSHYES;
                }
            }
            RETPUSHNO;
        }
-       else if (SM_OTHER_REGEX) {
-           PMOP * const matcher = make_matcher(other_regex);
-           HE *he;
-
-           (void) hv_iterinit((HV *) This);
-           while ( (he = hv_iternext((HV *) This)) ) {
-               if (matcher_matches_sv(matcher, hv_iterkeysv(he))) {
-                   (void) hv_iterinit((HV *) This);
-                   destroy_matcher(matcher);
-                   RETPUSHYES;
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_REGEXP) {
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Regex-Hash\n"));
+         sm_regex_hash:
+           {
+               PMOP * const matcher = make_matcher((REGEXP*) SvRV(d));
+               HE *he;
+               HV *hv = MUTABLE_HV(SvRV(e));
+
+               (void) hv_iterinit(hv);
+               while ( (he = hv_iternext(hv)) ) {
+                   DEBUG_M(Perl_deb(aTHX_ "        testing key against pattern...\n"));
+                   if (matcher_matches_sv(matcher, hv_iterkeysv(he))) {
+                       (void) hv_iterinit(hv);
+                       destroy_matcher(matcher);
+                       RETPUSHYES;
+                   }
                }
+               destroy_matcher(matcher);
+               RETPUSHNO;
            }
-           destroy_matcher(matcher);
-           RETPUSHNO;
        }
        else {
-           if (hv_exists_ent((HV *) This, Other, 0))
+         sm_any_hash:
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Any-Hash\n"));
+           if (hv_exists_ent(MUTABLE_HV(SvRV(e)), d, 0))
                RETPUSHYES;
            else
                RETPUSHNO;
        }
     }
-    else if (SM_REF(PVAV)) {
-       if (SM_OTHER_REF(PVAV)) {
-           AV *other_av = (AV *) SvRV(Other);
-           if (av_len((AV *) This) != av_len(other_av))
+    /* ~~ @array */
+    else if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVAV) {
+       if (object_on_left) {
+           goto sm_any_array; /* Treat objects like scalars */
+       }
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
+           AV * const other_av = MUTABLE_AV(SvRV(e));
+           const I32 other_len = av_len(other_av) + 1;
+           I32 i;
+
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Hash-Array\n"));
+           for (i = 0; i < other_len; ++i) {
+               SV ** const svp = av_fetch(other_av, i, FALSE);
+
+               DEBUG_M(Perl_deb(aTHX_ "        testing for key existence...\n"));
+               if (svp) {      /* ??? When can this not happen? */
+                   if (hv_exists_ent(MUTABLE_HV(SvRV(d)), *svp, 0))
+                       RETPUSHYES;
+               }
+           }
+           RETPUSHNO;
+       }
+       if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
+           AV *other_av = MUTABLE_AV(SvRV(d));
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Array-Array\n"));
+           if (av_len(MUTABLE_AV(SvRV(e))) != av_len(other_av))
                RETPUSHNO;
            else {
                I32 i;
@@ -4128,22 +4310,24 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
 
                if (NULL == seen_this) {
                    seen_this = newHV();
-                   (void) sv_2mortal((SV *) seen_this);
+                   (void) sv_2mortal(MUTABLE_SV(seen_this));
                }
                if (NULL == seen_other) {
                    seen_this = newHV();
-                   (void) sv_2mortal((SV *) seen_other);
+                   (void) sv_2mortal(MUTABLE_SV(seen_other));
                }
                for(i = 0; i <= other_len; ++i) {
-                   SV * const * const this_elem = av_fetch((AV *)This, i, FALSE);
+                   SV * const * const this_elem = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
                    SV * const * const other_elem = av_fetch(other_av, i, FALSE);
 
                    if (!this_elem || !other_elem) {
                        if (this_elem || other_elem)
                            RETPUSHNO;
                    }
-                   else if (SM_SEEN_THIS(*this_elem)
-                        || SM_SEEN_OTHER(*other_elem))
+                   else if (hv_exists_ent(seen_this,
+                               sv_2mortal(newSViv(PTR2IV(*this_elem))), 0) ||
+                           hv_exists_ent(seen_other,
+                               sv_2mortal(newSViv(PTR2IV(*other_elem))), 0))
                    {
                        if (*this_elem != *other_elem)
                            RETPUSHNO;
@@ -4155,12 +4339,14 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
                        (void)hv_store_ent(seen_other,
                                sv_2mortal(newSViv(PTR2IV(*other_elem))),
                                &PL_sv_undef, 0);
-                       PUSHs(*this_elem);
                        PUSHs(*other_elem);
+                       PUSHs(*this_elem);
                        
                        PUTBACK;
+                       DEBUG_M(Perl_deb(aTHX_ "        recursively comparing array element...\n"));
                        (void) do_smartmatch(seen_this, seen_other);
                        SPAGAIN;
+                       DEBUG_M(Perl_deb(aTHX_ "        recursion finished\n"));
                        
                        if (!SvTRUEx(POPs))
                            RETPUSHNO;
@@ -4169,124 +4355,124 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
                RETPUSHYES;
            }
        }
-       else if (SM_OTHER_REGEX) {
-           PMOP * const matcher = make_matcher(other_regex);
-           const I32 this_len = av_len((AV *) This);
-           I32 i;
-
-           for(i = 0; i <= this_len; ++i) {
-               SV * const * const svp = av_fetch((AV *)This, i, FALSE);
-               if (svp && matcher_matches_sv(matcher, *svp)) {
-                   destroy_matcher(matcher);
-                   RETPUSHYES;
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_REGEXP) {
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Regex-Array\n"));
+         sm_regex_array:
+           {
+               PMOP * const matcher = make_matcher((REGEXP*) SvRV(d));
+               const I32 this_len = av_len(MUTABLE_AV(SvRV(e)));
+               I32 i;
+
+               for(i = 0; i <= this_len; ++i) {
+                   SV * const * const svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
+                   DEBUG_M(Perl_deb(aTHX_ "        testing element against pattern...\n"));
+                   if (svp && matcher_matches_sv(matcher, *svp)) {
+                       destroy_matcher(matcher);
+                       RETPUSHYES;
+                   }
                }
+               destroy_matcher(matcher);
+               RETPUSHNO;
            }
-           destroy_matcher(matcher);
-           RETPUSHNO;
        }
-       else if (SvIOK(Other) || SvNOK(Other)) {
+       else if (!SvOK(d)) {
+           /* undef ~~ array */
+           const I32 this_len = av_len(MUTABLE_AV(SvRV(e)));
            I32 i;
 
-           for(i = 0; i <= AvFILL((AV *) This); ++i) {
-               SV * const * const svp = av_fetch((AV *)This, i, FALSE);
-               if (!svp)
-                   continue;
-               
-               PUSHs(Other);
-               PUSHs(*svp);
-               PUTBACK;
-               if (CopHINTS_get(PL_curcop) & HINT_INTEGER)
-                   (void) pp_i_eq();
-               else
-                   (void) pp_eq();
-               SPAGAIN;
-               if (SvTRUEx(POPs))
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Undef-Array\n"));
+           for (i = 0; i <= this_len; ++i) {
+               SV * const * const svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
+               DEBUG_M(Perl_deb(aTHX_ "        testing for undef element...\n"));
+               if (!svp || !SvOK(*svp))
                    RETPUSHYES;
            }
            RETPUSHNO;
        }
-       else if (SvPOK(Other)) {
-           const I32 this_len = av_len((AV *) This);
-           I32 i;
+       else {
+         sm_any_array:
+           {
+               I32 i;
+               const I32 this_len = av_len(MUTABLE_AV(SvRV(e)));
 
-           for(i = 0; i <= this_len; ++i) {
-               SV * const * const svp = av_fetch((AV *)This, i, FALSE);
-               if (!svp)
-                   continue;
-               
-               PUSHs(Other);
-               PUSHs(*svp);
-               PUTBACK;
-               (void) pp_seq();
-               SPAGAIN;
-               if (SvTRUEx(POPs))
-                   RETPUSHYES;
+               DEBUG_M(Perl_deb(aTHX_ "    applying rule Any-Array\n"));
+               for (i = 0; i <= this_len; ++i) {
+                   SV * const * const svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
+                   if (!svp)
+                       continue;
+
+                   PUSHs(d);
+                   PUSHs(*svp);
+                   PUTBACK;
+                   /* infinite recursion isn't supposed to happen here */
+                   DEBUG_M(Perl_deb(aTHX_ "        recursively testing array element...\n"));
+                   (void) do_smartmatch(NULL, NULL);
+                   SPAGAIN;
+                   DEBUG_M(Perl_deb(aTHX_ "        recursion finished\n"));
+                   if (SvTRUEx(POPs))
+                       RETPUSHYES;
+               }
+               RETPUSHNO;
            }
-           RETPUSHNO;
        }
     }
-    else if (!SvOK(d) || !SvOK(e)) {
-       if (!SvOK(d) && !SvOK(e))
-           RETPUSHYES;
-       else
-           RETPUSHNO;
-    }
-    else if (SM_REGEX) {
-       PMOP * const matcher = make_matcher(this_regex);
+    /* ~~ qr// */
+    else if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_REGEXP) {
+       if (!object_on_left && SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
+           SV *t = d; d = e; e = t;
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Hash-Regex\n"));
+           goto sm_regex_hash;
+       }
+       else if (!object_on_left && SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
+           SV *t = d; d = e; e = t;
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Array-Regex\n"));
+           goto sm_regex_array;
+       }
+       else {
+           PMOP * const matcher = make_matcher((REGEXP*) SvRV(e));
 
-       PUTBACK;
-       PUSHs(matcher_matches_sv(matcher, Other)
-           ? &PL_sv_yes
-           : &PL_sv_no);
-       destroy_matcher(matcher);
-       RETURN;
+           DEBUG_M(Perl_deb(aTHX_ "    applying rule Any-Regex\n"));
+           PUTBACK;
+           PUSHs(matcher_matches_sv(matcher, d)
+                   ? &PL_sv_yes
+                   : &PL_sv_no);
+           destroy_matcher(matcher);
+           RETURN;
+       }
     }
-    else if (SM_REF(PVCV)) {
-       I32 c;
-       /* This must be a null-prototyped sub, because we
-          already checked for the other kind. */
-       
-       ENTER;
-       SAVETMPS;
-       PUSHMARK(SP);
+    /* ~~ scalar */
+    /* See if there is overload magic on left */
+    else if (object_on_left && SvAMAGIC(d)) {
+       SV *tmpsv;
+       DEBUG_M(Perl_deb(aTHX_ "    applying rule Object-Any\n"));
+       DEBUG_M(Perl_deb(aTHX_ "        attempting overload\n"));
+       PUSHs(d); PUSHs(e);
        PUTBACK;
-       c = call_sv(This, G_SCALAR);
-       SPAGAIN;
-       if (c == 0)
-           PUSHs(&PL_sv_undef);
-       else if (SvTEMP(TOPs))
-           SvREFCNT_inc_void(TOPs);
-
-       if (SM_OTHER_REF(PVCV)) {
-           /* This one has to be null-proto'd too.
-              Call both of 'em, and compare the results */
-           PUSHMARK(SP);
-           c = call_sv(SvRV(Other), G_SCALAR);
+       tmpsv = amagic_call(d, e, smart_amg, AMGf_noright);
+       if (tmpsv) {
            SPAGAIN;
-           if (c == 0)
-               PUSHs(&PL_sv_undef);
-           else if (SvTEMP(TOPs))
-               SvREFCNT_inc_void(TOPs);
-           FREETMPS;
-           LEAVE;
-           PUTBACK;
-           return pp_eq();
+           (void)POPs;
+           SETs(tmpsv);
+           RETURN;
        }
-       
-       FREETMPS;
-       LEAVE;
-       RETURN;
+       SP -= 2;
+       DEBUG_M(Perl_deb(aTHX_ "        failed to run overload method; falling back...\n"));
+       goto sm_any_scalar;
     }
-    else if ( ((SvIOK(d) || SvNOK(d)) && (This = d) && (Other = e))
-         ||   ((SvIOK(e) || SvNOK(e)) && (This = e) && (Other = d)) )
-    {
-       if (SvPOK(Other) && !looks_like_number(Other)) {
-           /* String comparison */
-           PUSHs(d); PUSHs(e);
-           PUTBACK;
-           return pp_seq();
-       }
-       /* Otherwise, numeric comparison */
+    else if (!SvOK(d)) {
+       /* undef ~~ scalar ; we already know that the scalar is SvOK */
+       DEBUG_M(Perl_deb(aTHX_ "    applying rule undef-Any\n"));
+       RETPUSHNO;
+    }
+    else
+  sm_any_scalar:
+    if (SvNIOK(e) || (SvPOK(e) && looks_like_number(e) && SvNIOK(d))) {
+       DEBUG_M(if (SvNIOK(e))
+                   Perl_deb(aTHX_ "    applying rule Any-Num\n");
+               else
+                   Perl_deb(aTHX_ "    applying rule Num-numish\n");
+       );
+       /* numeric comparison */
        PUSHs(d); PUSHs(e);
        PUTBACK;
        if (CopHINTS_get(PL_curcop) & HINT_INTEGER)
@@ -4301,6 +4487,7 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
     }
     
     /* As a last resort, use string comparison */
+    DEBUG_M(Perl_deb(aTHX_ "    applying rule Any-Any\n"));
     PUSHs(d); PUSHs(e);
     PUTBACK;
     return pp_seq();
@@ -4320,7 +4507,7 @@ PP(pp_enterwhen)
     if ((0 == (PL_op->op_flags & OPf_SPECIAL)) && !SvTRUEx(POPs))
        return cLOGOP->op_other->op_next;
 
-    ENTER;
+    ENTER_with_name("eval");
     SAVETMPS;
 
     PUSHBLOCK(cx, CXt_WHEN, SP);
@@ -4345,7 +4532,7 @@ PP(pp_leavewhen)
 
     PL_curpm = newpm;   /* pop $1 et al */
 
-    LEAVE;
+    LEAVE_with_name("eval");
     return NORMAL;
 }
 
@@ -4423,6 +4610,8 @@ S_doparseform(pTHX_ SV *sv)
     bool unchopnum = FALSE;
     int maxops = 12; /* FF_LINEMARK + FF_END + 10 (\0 without preceding \n) */
 
+    PERL_ARGS_ASSERT_DOPARSEFORM;
+
     if (len == 0)
        Perl_croak(aTHX_ "Null picture in formline");
 
@@ -4655,8 +4844,8 @@ S_run_user_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
     dVAR;
     SV * const datasv = FILTER_DATA(idx);
     const int filter_has_file = IoLINES(datasv);
-    SV * const filter_state = (SV *)IoTOP_GV(datasv);
-    SV * const filter_sub = (SV *)IoBOTTOM_GV(datasv);
+    SV * const filter_state = MUTABLE_SV(IoTOP_GV(datasv));
+    SV * const filter_sub = MUTABLE_SV(IoBOTTOM_GV(datasv));
     int status = 0;
     SV *upstream;
     STRLEN got_len;
@@ -4665,6 +4854,8 @@ S_run_user_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
     bool read_from_cache = FALSE;
     STRLEN umaxlen;
 
+    PERL_ARGS_ASSERT_RUN_USER_FILTER;
+
     assert(maxlen >= 0);
     umaxlen = maxlen;
 
@@ -4673,8 +4864,8 @@ S_run_user_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
        for PL_parser->error_count == 0.)  Solaris doesn't segfault --
        not sure where the trouble is yet.  XXX */
 
-    if (IoFMT_GV(datasv)) {
-       SV *const cache = (SV *)IoFMT_GV(datasv);
+    {
+       SV *const cache = datasv;
        if (SvOK(cache)) {
            STRLEN cache_len;
            const char *cache_p = SvPV(cache, cache_len);
@@ -4728,12 +4919,12 @@ S_run_user_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
        dSP;
        int count;
 
-       ENTER;
+       ENTER_with_name("call_filter_sub");
        SAVE_DEFSV;
        SAVETMPS;
        EXTEND(SP, 2);
 
-       DEFSV = upstream;
+       DEFSV_set(upstream);
        PUSHMARK(SP);
        mPUSHi(0);
        if (filter_state) {
@@ -4752,7 +4943,7 @@ S_run_user_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
 
        PUTBACK;
        FREETMPS;
-       LEAVE;
+       LEAVE_with_name("call_filter_sub");
     }
 
     if(SvOK(upstream)) {
@@ -4773,11 +4964,9 @@ S_run_user_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
     if (prune_from) {
        /* Oh. Too long. Stuff some in our cache.  */
        STRLEN cached_len = got_p + got_len - prune_from;
-       SV *cache = (SV *)IoFMT_GV(datasv);
+       SV *const cache = datasv;
 
-       if (!cache) {
-           IoFMT_GV(datasv) = (GV*) (cache = newSV(got_len - umaxlen));
-       } else if (SvOK(cache)) {
+       if (SvOK(cache)) {
            /* Cache should be empty.  */
            assert(!SvCUR(cache));
        }
@@ -4806,7 +4995,6 @@ S_run_user_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
 
     if (status <= 0) {
        IoLINES(datasv) = 0;
-       SvREFCNT_dec(IoFMT_GV(datasv));
        if (filter_state) {
            SvREFCNT_dec(filter_state);
            IoTOP_GV(datasv) = NULL;
@@ -4831,9 +5019,15 @@ S_run_user_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
 static bool
 S_path_is_absolute(const char *name)
 {
+    PERL_ARGS_ASSERT_PATH_IS_ABSOLUTE;
+
     if (PERL_FILE_IS_ABSOLUTE(name)
-#ifdef MACOS_TRADITIONAL
-       || (*name == ':')
+#ifdef WIN32
+       || (*name == '.' && ((name[1] == '/' ||
+                            (name[1] == '.' && name[2] == '/'))
+                        || (name[1] == '\\' ||
+                            ( name[1] == '.' && name[2] == '\\')))
+           )
 #else
        || (*name == '.' && (name[1] == '/' ||
                             (name[1] == '.' && name[2] == '/')))