This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
do FILE should not see outside lexicals (from Rick Delaney
[perl5.git] / pp_ctl.c
index 746f483..42811f5 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -1,6 +1,6 @@
 /*    pp_ctl.c
  *
- *    Copyright (c) 1991-1999, Larry Wall
+ *    Copyright (c) 1991-2000, Larry Wall
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -27,6 +27,8 @@
 #define DOCATCH(o) ((CATCH_GET == TRUE) ? docatch(o) : (o))
 
 static I32 sortcv(pTHXo_ SV *a, SV *b);
+static I32 sortcv_stacked(pTHXo_ SV *a, SV *b);
+static I32 sortcv_xsub(pTHXo_ SV *a, SV *b);
 static I32 sv_ncmp(pTHXo_ SV *a, SV *b);
 static I32 sv_i_ncmp(pTHXo_ SV *a, SV *b);
 static I32 amagic_ncmp(pTHXo_ SV *a, SV *b);
@@ -112,6 +114,8 @@ PP(pp_regcomp)
                PL_reginterp_cnt = I32_MAX; /* Mark as safe.  */
 
            pm->op_pmflags = pm->op_pmpermflags;        /* reset case sensitivity */
+           if (DO_UTF8(tmpstr))
+               pm->op_pmdynflags |= PMdf_UTF8;
            pm->op_pmregexp = CALLREGCOMP(aTHX_ t, t + len, pm);
            PL_reginterp_cnt = 0;               /* XXXX Be extra paranoid - needed
                                           inside tie/overload accessors.  */
@@ -132,9 +136,13 @@ PP(pp_regcomp)
     else if (strEQ("\\s+", pm->op_pmregexp->precomp))
        pm->op_pmflags |= PMf_WHITE;
 
+    /* XXX runtime compiled output needs to move to the pad */
     if (pm->op_pmflags & PMf_KEEP) {
        pm->op_private &= ~OPpRUNTIME;  /* no point compiling again */
+#if !defined(USE_ITHREADS) && !defined(USE_THREADS)
+       /* XXX can't change the optree at runtime either */
        cLOGOP->op_first->op_next = PL_op->op_next;
+#endif
     }
     RETURN;
 }
@@ -290,11 +298,17 @@ PP(pp_formline)
     NV value;
     bool gotsome;
     STRLEN len;
-    STRLEN fudge = SvCUR(tmpForm) * (IN_UTF8 ? 3 : 1) + 1;
+    STRLEN fudge = SvCUR(tmpForm) * (IN_BYTE ? 1 : 3) + 1;
+    bool item_is_utf = FALSE;
 
     if (!SvMAGICAL(tmpForm) || !SvCOMPILED(tmpForm)) {
-       SvREADONLY_off(tmpForm);
-       doparseform(tmpForm);
+       if (SvREADONLY(tmpForm)) {
+           SvREADONLY_off(tmpForm);
+           doparseform(tmpForm);
+           SvREADONLY_on(tmpForm);
+       }
+       else
+           doparseform(tmpForm);
     }
 
     SvPV_force(PL_formtarget, len);
@@ -368,7 +382,7 @@ PP(pp_formline)
        case FF_CHECKNL:
            item = s = SvPV(sv, len);
            itemsize = len;
-           if (IN_UTF8) {
+           if (DO_UTF8(sv)) {
                itemsize = sv_len_utf8(sv);
                if (itemsize != len) {
                    I32 itembytes;
@@ -387,11 +401,13 @@ PP(pp_formline)
                            break;
                        s++;
                    }
+                   item_is_utf = TRUE;
                    itemsize = s - item;
                    sv_pos_b2u(sv, &itemsize);
                    break;
                }
            }
+           item_is_utf = FALSE;
            if (itemsize > fieldsize)
                itemsize = fieldsize;
            send = chophere = s + itemsize;
@@ -408,7 +424,7 @@ PP(pp_formline)
        case FF_CHECKCHOP:
            item = s = SvPV(sv, len);
            itemsize = len;
-           if (IN_UTF8) {
+           if (DO_UTF8(sv)) {
                itemsize = sv_len_utf8(sv);
                if (itemsize != len) {
                    I32 itembytes;
@@ -446,9 +462,11 @@ PP(pp_formline)
                        itemsize = chophere - item;
                        sv_pos_b2u(sv, &itemsize);
                    }
+                   item_is_utf = TRUE;
                    break;
                }
            }
+           item_is_utf = FALSE;
            if (itemsize <= fieldsize) {
                send = chophere = s + itemsize;
                while (s < send) {
@@ -504,7 +522,7 @@ PP(pp_formline)
        case FF_ITEM:
            arg = itemsize;
            s = item;
-           if (IN_UTF8) {
+           if (item_is_utf) {
                while (arg--) {
                    if (*s & 0x80) {
                        switch (UTF8SKIP(s)) {
@@ -547,6 +565,7 @@ PP(pp_formline)
        case FF_LINEGLOB:
            item = s = SvPV(sv, len);
            itemsize = len;
+           item_is_utf = FALSE;                /* XXX is this correct? */
            if (itemsize) {
                gotsome = TRUE;
                send = s + itemsize;
@@ -686,7 +705,7 @@ PP(pp_grepstart)
     /* SAVE_DEFSV does *not* suffice here for USE_THREADS */
     SAVESPTR(DEFSV);
     ENTER;                                     /* enter inner scope */
-    SAVESPTR(PL_curpm);
+    SAVEVPTR(PL_curpm);
 
     src = PL_stack_base[*PL_markstack_ptr];
     SvTEMP_off(src);
@@ -756,7 +775,7 @@ PP(pp_mapwhile)
        SV *src;
 
        ENTER;                                  /* enter inner scope */
-       SAVESPTR(PL_curpm);
+       SAVEVPTR(PL_curpm);
 
        src = PL_stack_base[PL_markstack_ptr[-1]];
        SvTEMP_off(src);
@@ -778,6 +797,8 @@ PP(pp_sort)
     I32 gimme = GIMME;
     OP* nextop = PL_op->op_next;
     I32 overloading = 0;
+    bool hasargs = FALSE;
+    I32 is_xsub = 0;
 
     if (gimme != G_ARRAY) {
        SP = MARK;
@@ -785,50 +806,60 @@ PP(pp_sort)
     }
 
     ENTER;
-    SAVEPPTR(PL_sortcop);
+    SAVEVPTR(PL_sortcop);
     if (PL_op->op_flags & OPf_STACKED) {
        if (PL_op->op_flags & OPf_SPECIAL) {
            OP *kid = cLISTOP->op_first->op_sibling;    /* pass pushmark */
            kid = kUNOP->op_first;                      /* pass rv2gv */
            kid = kUNOP->op_first;                      /* pass leave */
            PL_sortcop = kid->op_next;
-           stash = PL_curcop->cop_stash;
+           stash = CopSTASH(PL_curcop);
        }
        else {
            cv = sv_2cv(*++MARK, &stash, &gv, 0);
+           if (cv && SvPOK(cv)) {
+               STRLEN n_a;
+               char *proto = SvPV((SV*)cv, n_a);
+               if (proto && strEQ(proto, "$$")) {
+                   hasargs = TRUE;
+               }
+           }
            if (!(cv && CvROOT(cv))) {
-               if (gv) {
+               if (cv && CvXSUB(cv)) {
+                   is_xsub = 1;
+               }
+               else if (gv) {
                    SV *tmpstr = sv_newmortal();
                    gv_efullname3(tmpstr, gv, Nullch);
-                   if (cv && CvXSUB(cv))
-                       DIE(aTHX_ "Xsub \"%s\" called in sort", SvPVX(tmpstr));
                    DIE(aTHX_ "Undefined sort subroutine \"%s\" called",
                        SvPVX(tmpstr));
                }
-               if (cv) {
-                   if (CvXSUB(cv))
-                       DIE(aTHX_ "Xsub called in sort");
+               else {
                    DIE(aTHX_ "Undefined subroutine in sort");
                }
-               DIE(aTHX_ "Not a CODE reference in sort");
            }
-           PL_sortcop = CvSTART(cv);
-           SAVESPTR(CvROOT(cv)->op_ppaddr);
-           CvROOT(cv)->op_ppaddr = PL_ppaddr[OP_NULL];
 
-           SAVESPTR(PL_curpad);
-           PL_curpad = AvARRAY((AV*)AvARRAY(CvPADLIST(cv))[1]);
+           if (is_xsub)
+               PL_sortcop = (OP*)cv;
+           else {
+               PL_sortcop = CvSTART(cv);
+               SAVEVPTR(CvROOT(cv)->op_ppaddr);
+               CvROOT(cv)->op_ppaddr = PL_ppaddr[OP_NULL];
+
+               SAVEVPTR(PL_curpad);
+               PL_curpad = AvARRAY((AV*)AvARRAY(CvPADLIST(cv))[1]);
+            }
        }
     }
     else {
        PL_sortcop = Nullop;
-       stash = PL_curcop->cop_stash;
+       stash = CopSTASH(PL_curcop);
     }
 
     up = myorigmark + 1;
     while (MARK < SP) {        /* This may or may not shift down one here. */
        /*SUPPRESS 560*/
-       if (*up = *++MARK) {                    /* Weed out nulls. */
+       if ((*up = *++MARK)) {                  /* Weed out nulls. */
            SvTEMP_off(*up);
            if (!PL_sortcop && !SvPOK(*up)) {
                STRLEN n_a;
@@ -863,7 +894,6 @@ PP(pp_sort)
 
            PUSHBLOCK(cx, CXt_NULL, PL_stack_base);
            if (!(PL_op->op_flags & OPf_SPECIAL)) {
-               bool hasargs = FALSE;
                cx->cx_type = CXt_SUB;
                cx->blk_gimme = G_SCALAR;
                PUSHSUB(cx);
@@ -871,7 +901,19 @@ PP(pp_sort)
                    (void)SvREFCNT_inc(cv); /* in preparation for POPSUB */
            }
            PL_sortcxix = cxstack_ix;
-           qsortsv((myorigmark+1), max, sortcv);
+
+           if (hasargs && !is_xsub) {
+               /* This is mostly copied from pp_entersub */
+               AV *av = (AV*)PL_curpad[0];
+
+#ifndef USE_THREADS
+               cx->blk_sub.savearray = GvAV(PL_defgv);
+               GvAV(PL_defgv) = (AV*)SvREFCNT_inc(av);
+#endif /* USE_THREADS */
+               cx->blk_sub.argarray = av;
+           }
+           qsortsv((myorigmark+1), max,
+                   is_xsub ? sortcv_xsub : hasargs ? sortcv_stacked : sortcv);
 
            POPBLOCK(cx,PL_curpm);
            PL_stack_sp = newsp;
@@ -968,7 +1010,9 @@ PP(pp_flop)
            mg_get(right);
 
        if (SvNIOKp(left) || !SvPOKp(left) ||
-         (looks_like_number(left) && *SvPVX(left) != '0') )
+           SvNIOKp(right) || !SvPOKp(right) ||
+           (looks_like_number(left) && *SvPVX(left) != '0' &&
+            looks_like_number(right) && *SvPVX(right) != '0'))
        {
            if (SvNV(left) < IV_MIN || SvNV(right) > IV_MAX)
                DIE(aTHX_ "Range iterator outside integer range");
@@ -1031,23 +1075,28 @@ S_dopoptolabel(pTHX_ char *label)
        cx = &cxstack[i];
        switch (CxTYPE(cx)) {
        case CXt_SUBST:
-           if (ckWARN(WARN_UNSAFE))
-               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting substitution via %s", 
+           if (ckWARN(WARN_EXITING))
+               Perl_warner(aTHX_ WARN_EXITING, "Exiting substitution via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_SUB:
-           if (ckWARN(WARN_UNSAFE))
-               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting subroutine via %s", 
+           if (ckWARN(WARN_EXITING))
+               Perl_warner(aTHX_ WARN_EXITING, "Exiting subroutine via %s", 
+                       PL_op_name[PL_op->op_type]);
+           break;
+       case CXt_FORMAT:
+           if (ckWARN(WARN_EXITING))
+               Perl_warner(aTHX_ WARN_EXITING, "Exiting format via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_EVAL:
-           if (ckWARN(WARN_UNSAFE))
-               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting eval via %s", 
+           if (ckWARN(WARN_EXITING))
+               Perl_warner(aTHX_ WARN_EXITING, "Exiting eval via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_NULL:
-           if (ckWARN(WARN_UNSAFE))
-               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting pseudo-block via %s", 
+           if (ckWARN(WARN_EXITING))
+               Perl_warner(aTHX_ WARN_EXITING, "Exiting pseudo-block via %s", 
                        PL_op_name[PL_op->op_type]);
            return -1;
        case CXt_LOOP:
@@ -1115,6 +1164,7 @@ S_dopoptosub_at(pTHX_ PERL_CONTEXT *cxstk, I32 startingblock)
            continue;
        case CXt_EVAL:
        case CXt_SUB:
+       case CXt_FORMAT:
            DEBUG_l( Perl_deb(aTHX_ "(Found sub #%ld)\n", (long)i));
            return i;
        }
@@ -1151,23 +1201,28 @@ S_dopoptoloop(pTHX_ I32 startingblock)
        cx = &cxstack[i];
        switch (CxTYPE(cx)) {
        case CXt_SUBST:
-           if (ckWARN(WARN_UNSAFE))
-               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting substitution via %s", 
+           if (ckWARN(WARN_EXITING))
+               Perl_warner(aTHX_ WARN_EXITING, "Exiting substitution via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_SUB:
-           if (ckWARN(WARN_UNSAFE))
-               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting subroutine via %s", 
+           if (ckWARN(WARN_EXITING))
+               Perl_warner(aTHX_ WARN_EXITING, "Exiting subroutine via %s", 
+                       PL_op_name[PL_op->op_type]);
+           break;
+       case CXt_FORMAT:
+           if (ckWARN(WARN_EXITING))
+               Perl_warner(aTHX_ WARN_EXITING, "Exiting format via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_EVAL:
-           if (ckWARN(WARN_UNSAFE))
-               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting eval via %s", 
+           if (ckWARN(WARN_EXITING))
+               Perl_warner(aTHX_ WARN_EXITING, "Exiting eval via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_NULL:
-           if (ckWARN(WARN_UNSAFE))
-               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting pseudo-block via %s", 
+           if (ckWARN(WARN_EXITING))
+               Perl_warner(aTHX_ WARN_EXITING, "Exiting pseudo-block via %s", 
                        PL_op_name[PL_op->op_type]);
            return -1;
        case CXt_LOOP:
@@ -1183,7 +1238,6 @@ Perl_dounwind(pTHX_ I32 cxix)
 {
     dTHR;
     register PERL_CONTEXT *cx;
-    SV **newsp;
     I32 optype;
 
     while (cxstack_ix > cxix) {
@@ -1208,6 +1262,9 @@ Perl_dounwind(pTHX_ I32 cxix)
            break;
        case CXt_NULL:
            break;
+       case CXt_FORMAT:
+           POPFORMAT(cx);
+           break;
        }
        cxstack_ix--;
     }
@@ -1257,14 +1314,13 @@ Perl_qerror(pTHX_ SV *err)
     else if (PL_errors)
        sv_catsv(PL_errors, err);
     else
-       Perl_warn(aTHX_ "%_", err);
+       Perl_warn(aTHX_ "%"SVf, err);
     ++PL_error_count;
 }
 
 OP *
 Perl_die_where(pTHX_ char *message, STRLEN msglen)
 {
-    dSP;
     STRLEN n_a;
     if (PL_in_eval) {
        I32 cxix;
@@ -1289,9 +1345,9 @@ Perl_die_where(pTHX_ char *message, STRLEN msglen)
                    SvGROW(err, SvCUR(err)+sizeof(prefix)+msglen);
                    sv_catpvn(err, prefix, sizeof(prefix)-1);
                    sv_catpvn(err, message, msglen);
-                   if (ckWARN(WARN_UNSAFE)) {
+                   if (ckWARN(WARN_MISC)) {
                        STRLEN start = SvCUR(err)-msglen-sizeof(prefix)+1;
-                       Perl_warner(aTHX_ WARN_UNSAFE, SvPVX(err)+start);
+                       Perl_warner(aTHX_ WARN_MISC, SvPVX(err)+start);
                    }
                }
            }
@@ -1392,13 +1448,13 @@ PP(pp_caller)
     PERL_SI *top_si = PL_curstackinfo;
     I32 dbcxix;
     I32 gimme;
-    HV *hv;
+    char *stashname;
     SV *sv;
     I32 count = 0;
 
     if (MAXARG)
        count = POPi;
-    EXTEND(SP, 7);
+    EXTEND(SP, 10);
     for (;;) {
        /* we may be in a higher stacklevel, so dig down deeper */
        while (cxix < 0 && top_si->si_type != PERLSI_MAIN) {
@@ -1420,7 +1476,7 @@ PP(pp_caller)
     }
 
     cx = &ccstack[cxix];
-    if (CxTYPE(cx) == CXt_SUB) {
+    if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT) {
         dbcxix = dopoptosub_at(ccstack, cxix - 1);
        /* We expect that ccstack[dbcxix] is CXt_SUB, anyway, the
           field below is defined for any cx. */
@@ -1428,28 +1484,28 @@ PP(pp_caller)
            cx = &ccstack[dbcxix];
     }
 
+    stashname = CopSTASHPV(cx->blk_oldcop);
     if (GIMME != G_ARRAY) {
-       hv = cx->blk_oldcop->cop_stash;
-       if (!hv)
+       if (!stashname)
            PUSHs(&PL_sv_undef);
        else {
            dTARGET;
-           sv_setpv(TARG, HvNAME(hv));
+           sv_setpv(TARG, stashname);
            PUSHs(TARG);
        }
        RETURN;
     }
 
-    hv = cx->blk_oldcop->cop_stash;
-    if (!hv)
+    if (!stashname)
        PUSHs(&PL_sv_undef);
     else
-       PUSHs(sv_2mortal(newSVpv(HvNAME(hv), 0)));
-    PUSHs(sv_2mortal(newSVsv(CopFILESV(cx->blk_oldcop))));
-    PUSHs(sv_2mortal(newSViv((I32)cx->blk_oldcop->cop_line)));
+       PUSHs(sv_2mortal(newSVpv(stashname, 0)));
+    PUSHs(sv_2mortal(newSVpv(CopFILE(cx->blk_oldcop), 0)));
+    PUSHs(sv_2mortal(newSViv((I32)CopLINE(cx->blk_oldcop))));
     if (!MAXARG)
        RETURN;
-    if (CxTYPE(cx) == CXt_SUB) { /* So is ccstack[dbcxix]. */
+    if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT) {
+       /* So is ccstack[dbcxix]. */
        sv = NEWSV(49, 0);
        gv_efullname3(sv, CvGV(ccstack[cxix].blk_sub.cv), Nullch);
        PUSHs(sv_2mortal(sv));
@@ -1468,10 +1524,10 @@ PP(pp_caller)
        if (cx->blk_eval.old_op_type == OP_ENTEREVAL) {
            PUSHs(cx->blk_eval.cur_text);
            PUSHs(&PL_sv_no);
-       } 
-       else if (cx->blk_eval.old_name) { /* Try blocks have old_name == 0. */
-           /* Require, put the name. */
-           PUSHs(sv_2mortal(newSVpv(cx->blk_eval.old_name, 0)));
+       }
+       /* try blocks have old_namesv == 0 */
+       else if (cx->blk_eval.old_namesv) {
+           PUSHs(sv_2mortal(newSVsv(cx->blk_eval.old_namesv)));
            PUSHs(&PL_sv_yes);
        }
     }
@@ -1480,7 +1536,7 @@ PP(pp_caller)
        PUSHs(&PL_sv_undef);
     }
     if (CxTYPE(cx) == CXt_SUB && cx->blk_sub.hasargs
-       && PL_curcop->cop_stash == PL_debstash)
+       && CopSTASH_eq(PL_curcop, PL_debstash))
     {
        AV *ary = cx->blk_sub.argarray;
        int off = AvARRAY(ary) - AvALLOC(ary);
@@ -1503,6 +1559,17 @@ PP(pp_caller)
      * use the global PL_hints) */
     PUSHs(sv_2mortal(newSViv((I32)cx->blk_oldcop->op_private &
                             HINT_PRIVATE_MASK)));
+    {
+       SV * mask ;
+       SV * old_warnings = cx->blk_oldcop->cop_warnings ;
+       if  (old_warnings == WARN_NONE || old_warnings == WARN_STD)
+            mask = newSVpvn(WARN_NONEstring, WARNsize) ;
+        else if (old_warnings == WARN_ALL)
+            mask = newSVpvn(WARN_ALLstring, WARNsize) ;
+        else
+            mask = newSVsv(old_warnings);
+        PUSHs(sv_2mortal(mask));
+    }
     RETURN;
 }
 
@@ -1516,7 +1583,7 @@ PP(pp_reset)
        tmps = "";
     else
        tmps = POPpx;
-    sv_reset(tmps, PL_curcop->cop_stash);
+    sv_reset(tmps, CopSTASH(PL_curcop));
     PUSHs(&PL_sv_yes);
     RETURN;
 }
@@ -1564,7 +1631,7 @@ PP(pp_dbstate)
        PUSHSUB(cx);
        CvDEPTH(cv)++;
        (void)SvREFCNT_inc(cv);
-       SAVESPTR(PL_curpad);
+       SAVEVPTR(PL_curpad);
        PL_curpad = AvARRAY((AV*)*av_fetch(CvPADLIST(cv),1,FALSE));
        RETURNOP(CvSTART(cv));
     }
@@ -1583,6 +1650,10 @@ PP(pp_enteriter)
     register PERL_CONTEXT *cx;
     I32 gimme = GIMME_V;
     SV **svp;
+    U32 cxtype = CXt_LOOP;
+#ifdef USE_ITHREADS
+    void *iterdata;
+#endif
 
     ENTER;
     SAVETMPS;
@@ -1599,23 +1670,39 @@ PP(pp_enteriter)
     if (PL_op->op_targ) {
        svp = &PL_curpad[PL_op->op_targ];               /* "my" variable */
        SAVESPTR(*svp);
+#ifdef USE_ITHREADS
+       iterdata = (void*)PL_op->op_targ;
+       cxtype |= CXp_PADVAR;
+#endif
     }
     else {
-       svp = &GvSV((GV*)POPs);                 /* symbol table variable */
+       GV *gv = (GV*)POPs;
+       svp = &GvSV(gv);                        /* symbol table variable */
        SAVEGENERICSV(*svp);
        *svp = NEWSV(0,0);
+#ifdef USE_ITHREADS
+       iterdata = (void*)gv;
+#endif
     }
 
     ENTER;
 
-    PUSHBLOCK(cx, CXt_LOOP, SP);
+    PUSHBLOCK(cx, cxtype, SP);
+#ifdef USE_ITHREADS
+    PUSHLOOP(cx, iterdata, MARK);
+#else
     PUSHLOOP(cx, svp, MARK);
+#endif
     if (PL_op->op_flags & OPf_STACKED) {
        cx->blk_loop.iterary = (AV*)SvREFCNT_inc(POPs);
        if (SvTYPE(cx->blk_loop.iterary) != SVt_PVAV) {
            dPOPss;
            if (SvNIOKp(sv) || !SvPOKp(sv) ||
-               (looks_like_number(sv) && *SvPVX(sv) != '0')) {
+               SvNIOKp(cx->blk_loop.iterary) || !SvPOKp(cx->blk_loop.iterary) ||
+               (looks_like_number(sv) && *SvPVX(sv) != '0' &&
+                looks_like_number((SV*)cx->blk_loop.iterary) &&
+                *SvPVX(cx->blk_loop.iterary) != '0'))
+           {
                 if (SvNV(sv) < IV_MIN ||
                     SvNV((SV*)cx->blk_loop.iterary) >= IV_MAX)
                     DIE(aTHX_ "Range iterator outside integer range");
@@ -1704,7 +1791,9 @@ PP(pp_return)
     SV *sv;
 
     if (PL_curstackinfo->si_type == PERLSI_SORT) {
-       if (cxstack_ix == PL_sortcxix || dopoptosub(cxstack_ix) <= PL_sortcxix) {
+       if (cxstack_ix == PL_sortcxix
+           || dopoptosub(cxstack_ix) <= PL_sortcxix)
+       {
            if (cxstack_ix > PL_sortcxix)
                dounwind(PL_sortcxix);
            AvARRAY(PL_curstack)[1] = *SP;
@@ -1733,11 +1822,14 @@ PP(pp_return)
            (MARK == SP || (gimme == G_SCALAR && !SvTRUE(*SP))) )
        {
            /* Unassume the success we assumed earlier. */
-           char *name = cx->blk_eval.old_name;
-           (void)hv_delete(GvHVn(PL_incgv), name, strlen(name), G_DISCARD);
-           DIE(aTHX_ "%s did not return a true value", name);
+           SV *nsv = cx->blk_eval.old_namesv;
+           (void)hv_delete(GvHVn(PL_incgv), SvPVX(nsv), SvCUR(nsv), G_DISCARD);
+           DIE(aTHX_ "%s did not return a true value", SvPVX(nsv));
        }
        break;
+    case CXt_FORMAT:
+       POPFORMAT(cx);
+       break;
     default:
        DIE(aTHX_ "panic: return");
     }
@@ -1801,7 +1893,7 @@ PP(pp_last)
     if (PL_op->op_flags & OPf_SPECIAL) {
        cxix = dopoptoloop(cxstack_ix);
        if (cxix < 0)
-           DIE(aTHX_ "Can't \"last\" outside a block");
+           DIE(aTHX_ "Can't \"last\" outside a loop block");
     }
     else {
        cxix = dopoptolabel(cPVOP->op_pv);
@@ -1827,6 +1919,10 @@ PP(pp_last)
        POPEVAL(cx);
        nextop = pop_return();
        break;
+    case CXt_FORMAT:
+       POPFORMAT(cx);
+       nextop = pop_return();
+       break;
     default:
        DIE(aTHX_ "panic: last");
     }
@@ -1875,7 +1971,7 @@ PP(pp_next)
     if (PL_op->op_flags & OPf_SPECIAL) {
        cxix = dopoptoloop(cxstack_ix);
        if (cxix < 0)
-           DIE(aTHX_ "Can't \"next\" outside a block");
+           DIE(aTHX_ "Can't \"next\" outside a loop block");
     }
     else {
        cxix = dopoptolabel(cPVOP->op_pv);
@@ -1886,8 +1982,12 @@ PP(pp_next)
        dounwind(cxix);
 
     TOPBLOCK(cx);
-    oldsave = PL_scopestack[PL_scopestack_ix - 1];
-    LEAVE_SCOPE(oldsave);
+
+    /* clean scope, but only if there's no continue block */
+    if (!(cx->blk_loop.last_op->op_private & OPpLOOP_CONTINUE)) {
+       oldsave = PL_scopestack[PL_scopestack_ix - 1];
+       LEAVE_SCOPE(oldsave);
+    }
     return cx->blk_loop.next_op;
 }
 
@@ -1900,7 +2000,7 @@ PP(pp_redo)
     if (PL_op->op_flags & OPf_SPECIAL) {
        cxix = dopoptoloop(cxstack_ix);
        if (cxix < 0)
-           DIE(aTHX_ "Can't \"redo\" outside a block");
+           DIE(aTHX_ "Can't \"redo\" outside a loop block");
     }
     else {
        cxix = dopoptolabel(cPVOP->op_pv);
@@ -1951,7 +2051,7 @@ S_dofindlabel(pTHX_ OP *o, char *label, OP **opstack, OP **oplimit)
                 (ops[-1]->op_type != OP_NEXTSTATE &&
                  ops[-1]->op_type != OP_DBSTATE)))
                *ops++ = kid;
-           if (o = dofindlabel(kid, label, ops, oplimit))
+           if ((o = dofindlabel(kid, label, ops, oplimit)))
                return o;
        }
     }
@@ -2045,7 +2145,6 @@ PP(pp_goto)
            }
            else if (CvXSUB(cv)) {      /* put GvAV(defgv) back onto stack */
                AV* av;
-               int i;
 #ifdef USE_THREADS
                av = (AV*)PL_curpad[0];
 #else
@@ -2073,7 +2172,7 @@ PP(pp_goto)
                        SP[1] = SP[0];
                        SP--;
                    }
-                   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);
@@ -2117,9 +2216,10 @@ PP(pp_goto)
                        AV *newpad = newAV();
                        SV **oldpad = AvARRAY(svp[CvDEPTH(cv)-1]);
                        I32 ix = AvFILLp((AV*)svp[1]);
+                       I32 names_fill = AvFILLp((AV*)svp[0]);
                        svp = AvARRAY(svp[0]);
                        for ( ;ix > 0; ix--) {
-                           if (svp[ix] != &PL_sv_undef) {
+                           if (names_fill >= ix && svp[ix] != &PL_sv_undef) {
                                char *name = SvPVX(svp[ix]);
                                if ((SvFLAGS(svp[ix]) & SVf_FAKE)
                                    || *name == '&')
@@ -2138,6 +2238,9 @@ PP(pp_goto)
                                    SvPADMY_on(sv);
                                }
                            }
+                           else if (IS_PADGV(oldpad[ix]) || IS_PADCONST(oldpad[ix])) {
+                               av_store(newpad, ix, sv = SvREFCNT_inc(oldpad[ix]));
+                           }
                            else {
                                av_store(newpad, ix, sv = NEWSV(0,0));
                                SvPADTMP_on(sv);
@@ -2168,7 +2271,7 @@ PP(pp_goto)
                    }
                }
 #endif /* USE_THREADS */               
-               SAVESPTR(PL_curpad);
+               SAVEVPTR(PL_curpad);
                PL_curpad = AvARRAY((AV*)svp[CvDEPTH(cv)]);
 #ifndef USE_THREADS
                if (cx->blk_sub.hasargs)
@@ -2273,18 +2376,21 @@ PP(pp_goto)
                    break;
                }
                /* FALL THROUGH */
+           case CXt_FORMAT:
            case CXt_NULL:
-               DIE(aTHX_ "Can't \"goto\" outside a block");
+               DIE(aTHX_ "Can't \"goto\" out of a pseudo block");
            default:
                if (ix)
                    DIE(aTHX_ "panic: goto");
                gotoprobe = PL_main_root;
                break;
            }
-           retop = dofindlabel(gotoprobe, label,
-                               enterops, enterops + GOTO_DEPTH);
-           if (retop)
-               break;
+           if (gotoprobe) {
+               retop = dofindlabel(gotoprobe, label,
+                                   enterops, enterops + GOTO_DEPTH);
+               if (retop)
+                   break;
+           }
            PL_lastgotoprobe = gotoprobe;
        }
        if (!retop)
@@ -2312,8 +2418,7 @@ PP(pp_goto)
                /* Eventually we may want to stack the needed arguments
                 * for each op.  For now, we punt on the hard ones. */
                if (PL_op->op_type == OP_ENTERITER)
-                   DIE(aTHX_ "Can't \"goto\" into the middle of a foreach loop",
-                       label);
+                   DIE(aTHX_ "Can't \"goto\" into the middle of a foreach loop");
                CALL_FPTR(PL_op->op_ppaddr)(aTHX);
            }
            PL_op = oldop;
@@ -2350,6 +2455,7 @@ PP(pp_exit)
            anum = 0;
 #endif
     }
+    PL_exit_flags |= PERL_EXIT_EXPECTED;
     my_exit(anum);
     PUSHs(&PL_sv_undef);
     RETURN;
@@ -2422,9 +2528,17 @@ S_save_lines(pTHX_ AV *array, SV *sv)
     }
 }
 
+#ifdef PERL_FLEXIBLE_EXCEPTIONS
 STATIC void *
 S_docatch_body(pTHX_ va_list args)
 {
+    return docatch_body();
+}
+#endif
+
+STATIC void *
+S_docatch_body(pTHX)
+{
     CALLRUNOPS(aTHX);
     return NULL;
 }
@@ -2442,10 +2556,18 @@ S_docatch(pTHX_ OP *o)
     assert(CATCH_GET == TRUE);
 #endif
     PL_op = o;
+#ifdef PERL_FLEXIBLE_EXCEPTIONS
  redo_body:
     CALLPROTECT(aTHX_ pcur_env, &ret, MEMBER_TO_FPTR(S_docatch_body));
+#else
+    JMPENV_PUSH(ret);
+#endif
     switch (ret) {
     case 0:
+#ifndef PERL_FLEXIBLE_EXCEPTIONS
+ redo_body:
+       docatch_body();
+#endif
        break;
     case 3:
        if (PL_restartop && cursi == PL_curstackinfo) {
@@ -2455,10 +2577,12 @@ S_docatch(pTHX_ OP *o)
        }
        /* FALL THROUGH */
     default:
+       JMPENV_POP;
        PL_op = oldop;
        JMPENV_JUMP(ret);
        /* NOTREACHED */
     }
+    JMPENV_POP;
     PL_op = oldop;
     return Nullop;
 }
@@ -2475,8 +2599,9 @@ Perl_sv_compile_2op(pTHX_ SV *sv, OP** startop, char *code, AV** avp)
     I32 gimme = 0;   /* SUSPECT - INITIALZE TO WHAT?  NI-S */
     I32 optype;
     OP dummy;
-    OP *oop = PL_op, *rop;
-    char tmpbuf[TYPE_DIGITS(long) + 12 + 10];
+    OP *rop;
+    char tbuf[TYPE_DIGITS(long) + 12 + 10];
+    char *tmpbuf = tbuf;
     char *safestr;
 
     ENTER;
@@ -2485,14 +2610,22 @@ Perl_sv_compile_2op(pTHX_ SV *sv, OP** startop, char *code, AV** avp)
     /* switch to eval mode */
 
     if (PL_curcop == &PL_compiling) {
-       SAVESPTR(PL_compiling.cop_stash);
-       PL_compiling.cop_stash = PL_curstash;
+       SAVECOPSTASH(&PL_compiling);
+       CopSTASH_set(&PL_compiling, PL_curstash);
+    }
+    SAVECOPFILE(&PL_compiling);
+    SAVECOPLINE(&PL_compiling);
+    if (PERLDB_NAMEEVAL && CopLINE(PL_curcop)) {
+       SV *sv = sv_newmortal();
+       Perl_sv_setpvf(aTHX_ sv, "_<(%.10seval %lu)[%s:%"IVdf"]",
+                      code, (unsigned long)++PL_evalseq,
+                      CopFILE(PL_curcop), (IV)CopLINE(PL_curcop));
+       tmpbuf = SvPVX(sv);
     }
-    SAVESPTR(CopFILEGV(&PL_compiling));
-    SAVEI16(PL_compiling.cop_line);
-    sprintf(tmpbuf, "_<(%.10s_eval %lu)", code, (unsigned long)++PL_evalseq);
-    CopFILEGV_set(&PL_compiling, gv_fetchfile(tmpbuf+2));
-    PL_compiling.cop_line = 1;
+    else
+       sprintf(tmpbuf, "_<(%.10s_eval %lu)", code, (unsigned long)++PL_evalseq);
+    CopFILE_set(&PL_compiling, tmpbuf+2);
+    CopLINE_set(&PL_compiling, 1);
     /* XXX For C<eval "...">s within BEGIN {} blocks, this ends up
        deleting the eval's FILEGV from the stash before gv_check() runs
        (i.e. before run-time proper). To work around the coredump that
@@ -2504,7 +2637,7 @@ Perl_sv_compile_2op(pTHX_ SV *sv, OP** startop, char *code, AV** avp)
 #ifdef OP_IN_REGISTER
     PL_opsave = op;
 #else
-    SAVEPPTR(PL_op);
+    SAVEVPTR(PL_op);
 #endif
     PL_hints = 0;
 
@@ -2536,7 +2669,6 @@ S_doeval(pTHX_ int gimme, OP** startop)
 {
     dSP;
     OP *saveop = PL_op;
-    HV *newstash;
     CV *caller;
     AV* comppadlist;
     I32 i;
@@ -2548,7 +2680,7 @@ S_doeval(pTHX_ int gimme, OP** startop)
     /* set up a scratch pad */
 
     SAVEI32(PL_padix);
-    SAVESPTR(PL_curpad);
+    SAVEVPTR(PL_curpad);
     SAVESPTR(PL_comppad);
     SAVESPTR(PL_comppad_name);
     SAVEI32(PL_comppad_name_fill);
@@ -2560,7 +2692,7 @@ S_doeval(pTHX_ int gimme, OP** startop)
        PERL_CONTEXT *cx = &cxstack[i];
        if (CxTYPE(cx) == CXt_EVAL)
            break;
-       else if (CxTYPE(cx) == CXt_SUB) {
+       else if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT) {
            caller = cx->blk_sub.cv;
            break;
        }
@@ -2595,17 +2727,19 @@ S_doeval(pTHX_ int gimme, OP** startop)
     av_store(comppadlist, 1, (SV*)PL_comppad);
     CvPADLIST(PL_compcv) = comppadlist;
 
-    if (!saveop || saveop->op_type != OP_REQUIRE)
+    if (!saveop ||
+       (saveop->op_type != OP_REQUIRE && saveop->op_type != OP_DOFILE))
+    {
        CvOUTSIDE(PL_compcv) = (CV*)SvREFCNT_inc(caller);
+    }
 
     SAVEFREESV(PL_compcv);
 
     /* make sure we compile in the right package */
 
-    newstash = PL_curcop->cop_stash;
-    if (PL_curstash != newstash) {
+    if (CopSTASH_ne(PL_curcop, PL_curstash)) {
        SAVESPTR(PL_curstash);
-       PL_curstash = newstash;
+       PL_curstash = CopSTASH(PL_curcop);
     }
     SAVESPTR(PL_beginav);
     PL_beginav = newAV();
@@ -2668,7 +2802,7 @@ S_doeval(pTHX_ int gimme, OP** startop)
     }
     SvREFCNT_dec(PL_rs);
     PL_rs = SvREFCNT_inc(PL_nrs);
-    PL_compiling.cop_line = 0;
+    CopLINE_set(&PL_compiling, 0);
     if (startop) {
        *startop = PL_eval_root;
        SvREFCNT_dec(CvOUTSIDE(PL_compcv));
@@ -2762,10 +2896,56 @@ PP(pp_require)
     SV *filter_sub = 0;
 
     sv = POPs;
-    if (SvNIOKp(sv) && !SvPOKp(sv)) {
-       if (Atof(PL_patchlevel) + 0.00000999 < SvNV(sv))
-           DIE(aTHX_ "Perl %s required--this is only version %s, stopped",
-               SvPV(sv,n_a),PL_patchlevel);
+    if (SvNIOKp(sv)) {
+       UV rev, ver, sver;
+       if (SvPOKp(sv)) {               /* require v5.6.1 */
+           I32 len;
+           U8 *s = (U8*)SvPVX(sv);
+           U8 *end = (U8*)SvPVX(sv) + SvCUR(sv);
+           if (s < end) {
+               rev = utf8_to_uv(s, &len);
+               s += len;
+               if (s < end) {
+                   ver = utf8_to_uv(s, &len);
+                   s += len;
+                   if (s < end)
+                       sver = utf8_to_uv(s, &len);
+                   else
+                       sver = 0;
+               }
+               else
+                   ver = 0;
+           }
+           else
+               rev = 0;
+           if (PERL_REVISION < rev
+               || (PERL_REVISION == rev
+                   && (PERL_VERSION < ver
+                       || (PERL_VERSION == ver
+                           && PERL_SUBVERSION < sver))))
+           {
+               DIE(aTHX_ "Perl v%"UVuf".%"UVuf".%"UVuf" required--this is only version "
+                   "v%d.%d.%d, stopped", rev, ver, sver, PERL_REVISION,
+                   PERL_VERSION, PERL_SUBVERSION);
+           }
+       }
+       else if (!SvPOKp(sv)) {                 /* require 5.005_03 */
+           if ((NV)PERL_REVISION + ((NV)PERL_VERSION/(NV)1000)
+               + ((NV)PERL_SUBVERSION/(NV)1000000)
+               + 0.00000099 < SvNV(sv))
+           {
+               NV nrev = SvNV(sv);
+               UV rev = (UV)nrev;
+               NV nver = (nrev - rev) * 1000;
+               UV ver = (UV)(nver + 0.0009);
+               NV nsver = (nver - ver) * 1000;
+               UV sver = (UV)(nsver + 0.0009);
+
+               DIE(aTHX_ "Perl v%"UVuf".%"UVuf".%"UVuf" required--this is only version "
+                   "v%d.%d.%d, stopped", rev, ver, sver, PERL_REVISION,
+                   PERL_VERSION, PERL_SUBVERSION);
+           }
+       }
        RETPUSHYES;
     }
     name = SvPV(sv, len);
@@ -2779,21 +2959,9 @@ PP(pp_require)
 
     /* prepare to compile file */
 
-    if (*name == '/' ||
-       (*name == '.' && 
-           (name[1] == '/' ||
-            (name[1] == '.' && name[2] == '/')))
-#ifdef DOSISH
-      || (name[0] && name[1] == ':')
-#endif
-#ifdef WIN32
-      || (name[0] == '\\' && name[1] == '\\')  /* UNC path */
-#endif
-#ifdef VMS
-       || (strchr(name,':')  || ((*name == '[' || *name == '<') &&
-           (isALNUM(name[1]) || strchr("$-_]>",name[1]))))
-#endif
-    )
+    if (PERL_FILE_IS_ABSOLUTE(name)
+       || (*name == '.' && (name[1] == '/' ||
+                            (name[1] == '.' && name[2] == '/'))))
     {
        tryname = name;
        tryrsfp = doopen_pmc(name,PERL_SCRIPT_MODE);
@@ -2937,8 +3105,8 @@ PP(pp_require)
            }
        }
     }
-    SAVESPTR(CopFILEGV(&PL_compiling));
-    CopFILEGV_set(&PL_compiling, gv_fetchfile(tryrsfp ? tryname : name));
+    SAVECOPFILE(&PL_compiling);
+    CopFILE_set(&PL_compiling, tryrsfp ? tryname : name);
     SvREFCNT_dec(namesv);
     if (!tryrsfp) {
        if (PL_op->op_type == OP_REQUIRE) {
@@ -2973,7 +3141,7 @@ PP(pp_require)
 
     /* Assume success here to prevent recursive requirement. */
     (void)hv_store(GvHVn(PL_incgv), name, strlen(name),
-                  newSVsv(CopFILESV(&PL_compiling)), 0 );
+                  newSVpv(CopFILE(&PL_compiling), 0), 0 );
 
     ENTER;
     SAVETMPS;
@@ -2982,11 +3150,9 @@ PP(pp_require)
     PL_rsfp_filters = Nullav;
 
     PL_rsfp = tryrsfp;
-    name = savepv(name);
-    SAVEFREEPV(name);
     SAVEHINTS();
     PL_hints = 0;
-    SAVEPPTR(PL_compiling.cop_warnings);
+    SAVESPTR(PL_compiling.cop_warnings);
     if (PL_dowarn & G_WARN_ALL_ON)
         PL_compiling.cop_warnings = WARN_ALL ;
     else if (PL_dowarn & G_WARN_ALL_OFF)
@@ -3007,8 +3173,8 @@ PP(pp_require)
     PUSHBLOCK(cx, CXt_EVAL, SP);
     PUSHEVAL(cx, name, Nullgv);
 
-    SAVEI16(PL_compiling.cop_line);
-    PL_compiling.cop_line = 0;
+    SAVECOPLINE(&PL_compiling);
+    CopLINE_set(&PL_compiling, 0);
 
     PUTBACK;
 #ifdef USE_THREADS
@@ -3033,7 +3199,8 @@ PP(pp_entereval)
     register PERL_CONTEXT *cx;
     dPOPss;
     I32 gimme = GIMME_V, was = PL_sub_generation;
-    char tmpbuf[TYPE_DIGITS(long) + 12];
+    char tbuf[TYPE_DIGITS(long) + 12];
+    char *tmpbuf = tbuf;
     char *safestr;
     STRLEN len;
     OP *ret;
@@ -3048,10 +3215,18 @@ PP(pp_entereval)
  
     /* switch to eval mode */
 
-    SAVESPTR(CopFILEGV(&PL_compiling));
-    sprintf(tmpbuf, "_<(eval %lu)", (unsigned long)++PL_evalseq);
-    CopFILEGV_set(&PL_compiling, gv_fetchfile(tmpbuf+2));
-    PL_compiling.cop_line = 1;
+    SAVECOPFILE(&PL_compiling);
+    if (PERLDB_NAMEEVAL && CopLINE(PL_curcop)) {
+       SV *sv = sv_newmortal();
+       Perl_sv_setpvf(aTHX_ sv, "_<(eval %lu)[%s:%"IVdf"]",
+                      (unsigned long)++PL_evalseq,
+                      CopFILE(PL_curcop), (IV)CopLINE(PL_curcop));
+       tmpbuf = SvPVX(sv);
+    }
+    else
+       sprintf(tmpbuf, "_<(eval %lu)", (unsigned long)++PL_evalseq);
+    CopFILE_set(&PL_compiling, tmpbuf+2);
+    CopLINE_set(&PL_compiling, 1);
     /* XXX For C<eval "...">s within BEGIN {} blocks, this ends up
        deleting the eval's FILEGV from the stash before gv_check() runs
        (i.e. before run-time proper). To work around the coredump that
@@ -3061,7 +3236,7 @@ PP(pp_entereval)
     SAVEDELETE(PL_defstash, safestr, strlen(safestr));
     SAVEHINTS();
     PL_hints = PL_op->op_targ;
-    SAVEPPTR(PL_compiling.cop_warnings);
+    SAVESPTR(PL_compiling.cop_warnings);
     if (!specialWARN(PL_compiling.cop_warnings)) {
         PL_compiling.cop_warnings = newSVsv(PL_compiling.cop_warnings) ;
         SAVEFREESV(PL_compiling.cop_warnings) ;
@@ -3149,9 +3324,9 @@ PP(pp_leaveeval)
        !(gimme == G_SCALAR ? SvTRUE(*SP) : SP > newsp))
     {
        /* Unassume the success we assumed earlier. */
-       char *name = cx->blk_eval.old_name;
-       (void)hv_delete(GvHVn(PL_incgv), name, strlen(name), G_DISCARD);
-       retop = Perl_die(aTHX_ "%s did not return a true value", name);
+       SV *nsv = cx->blk_eval.old_namesv;
+       (void)hv_delete(GvHVn(PL_incgv), SvPVX(nsv), SvCUR(nsv), G_DISCARD);
+       retop = Perl_die(aTHX_ "%s did not return a true value", SvPVX(nsv));
        /* die_where() did LEAVE, or we won't be here */
     }
     else {
@@ -3824,7 +3999,7 @@ S_qsortsv(pTHX_ SV ** array, size_t num_elts, SVCOMPARE_t compare)
                on the correct side of the partition. If I find a greater
                value, then stop the scan.
             */
-            while (still_work_on_left = (u_right >= part_left)) {
+            while ((still_work_on_left = (u_right >= part_left))) {
                s = qsort_cmp(u_right, pc_left);
                if (s < 0) {
                   --u_right;
@@ -3845,7 +4020,7 @@ S_qsortsv(pTHX_ SV ** array, size_t num_elts, SVCOMPARE_t compare)
 
             /* Do a mirror image scan of uncompared values on the right
             */
-            while (still_work_on_right = (u_left <= part_right)) {
+            while ((still_work_on_right = (u_left <= part_right))) {
                s = qsort_cmp(pc_right, u_left);
                if (s < 0) {
                   ++u_left;
@@ -4119,6 +4294,80 @@ sortcv(pTHXo_ SV *a, SV *b)
     return result;
 }
 
+static I32
+sortcv_stacked(pTHXo_ SV *a, SV *b)
+{
+    dTHR;
+    I32 oldsaveix = PL_savestack_ix;
+    I32 oldscopeix = PL_scopestack_ix;
+    I32 result;
+    AV *av;
+
+#ifdef USE_THREADS
+    av = (AV*)PL_curpad[0];
+#else
+    av = GvAV(PL_defgv);
+#endif
+
+    if (AvMAX(av) < 1) {
+       SV** ary = AvALLOC(av);
+       if (AvARRAY(av) != ary) {
+           AvMAX(av) += AvARRAY(av) - AvALLOC(av);
+           SvPVX(av) = (char*)ary;
+       }
+       if (AvMAX(av) < 1) {
+           AvMAX(av) = 1;
+           Renew(ary,2,SV*);
+           SvPVX(av) = (char*)ary;
+       }
+    }
+    AvFILLp(av) = 1;
+
+    AvARRAY(av)[0] = a;
+    AvARRAY(av)[1] = b;
+    PL_stack_sp = PL_stack_base;
+    PL_op = PL_sortcop;
+    CALLRUNOPS(aTHX);
+    if (PL_stack_sp != PL_stack_base + 1)
+       Perl_croak(aTHX_ "Sort subroutine didn't return single value");
+    if (!SvNIOKp(*PL_stack_sp))
+       Perl_croak(aTHX_ "Sort subroutine didn't return a numeric value");
+    result = SvIV(*PL_stack_sp);
+    while (PL_scopestack_ix > oldscopeix) {
+       LEAVE;
+    }
+    leave_scope(oldsaveix);
+    return result;
+}
+
+static I32
+sortcv_xsub(pTHXo_ SV *a, SV *b)
+{
+    dSP;
+    I32 oldsaveix = PL_savestack_ix;
+    I32 oldscopeix = PL_scopestack_ix;
+    I32 result;
+    CV *cv=(CV*)PL_sortcop;
+
+    SP = PL_stack_base;
+    PUSHMARK(SP);
+    EXTEND(SP, 2);
+    *++SP = a;
+    *++SP = b;
+    PUTBACK;
+    (void)(*CvXSUB(cv))(aTHXo_ cv);
+    if (PL_stack_sp != PL_stack_base + 1)
+       Perl_croak(aTHX_ "Sort subroutine didn't return single value");
+    if (!SvNIOKp(*PL_stack_sp))
+       Perl_croak(aTHX_ "Sort subroutine didn't return a numeric value");
+    result = SvIV(*PL_stack_sp);
+    while (PL_scopestack_ix > oldscopeix) {
+       LEAVE;
+    }
+    leave_scope(oldsaveix);
+    return result;
+}
+
 
 static I32
 sv_ncmp(pTHXo_ SV *a, SV *b)