change#3534 didn't preserve undef return values from caller()
[p5sagit/p5-mst-13.2.git] / pp_ctl.c
index d44a490..ab6466b 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -17,6 +17,7 @@
  */
 
 #include "EXTERN.h"
+#define PERL_IN_PP_CTL_C
 #include "perl.h"
 
 #ifndef WORD_ALIGN
 #define CALLOP this->*PL_op
 #else
 #define CALLOP *PL_op
-static void *docatch_body (va_list args);
-static OP *docatch (OP *o);
-static OP *dofindlabel (OP *o, char *label, OP **opstack, OP **oplimit);
-static void doparseform (SV *sv);
-static I32 dopoptoeval (I32 startingblock);
-static I32 dopoptolabel (char *label);
-static I32 dopoptoloop (I32 startingblock);
-static I32 dopoptosub (I32 startingblock);
-static I32 dopoptosub_at (PERL_CONTEXT *cxstk, I32 startingblock);
-static void save_lines (AV *array, SV *sv);
-static I32 sortcv (SV *a, SV *b);
-static void qsortsv (SV **array, size_t num_elts, I32 (*fun)(SV *a, SV *b));
-static OP *doeval (int gimme, OP** startop);
-static PerlIO *doopen_pmc (const char *name, const char *mode);
-static I32 sv_ncmp (SV *a, SV *b);
-static I32 sv_i_ncmp (SV *a, SV *b);
-static I32 amagic_ncmp (SV *a, SV *b);
-static I32 amagic_i_ncmp (SV *a, SV *b);
-static I32 amagic_cmp (SV *str1, SV *str2);
-static I32 amagic_cmp_locale (SV *str1, SV *str2);
-static void free_closures (void);
+#endif
+
+static I32 sortcv(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);
+static I32 amagic_i_ncmp(pTHXo_ SV *a, SV *b);
+static I32 amagic_cmp(pTHXo_ SV *a, SV *b);
+static I32 amagic_cmp_locale(pTHXo_ SV *a, SV *b);
+#ifdef PERL_OBJECT
+static I32 sv_cmp_static(pTHXo_ SV *a, SV *b);
+static I32 sv_cmp_locale_static(pTHXo_ SV *a, SV *b);
+#else
+#define sv_cmp_static Perl_sv_cmp
+#define sv_cmp_locale_static Perl_sv_cmp_locale
 #endif
 
 PP(pp_wantarray)
@@ -121,7 +116,7 @@ PP(pp_regcomp)
                PL_reginterp_cnt = I32_MAX; /* Mark as safe.  */
 
            pm->op_pmflags = pm->op_pmpermflags;        /* reset case sensitivity */
-           pm->op_pmregexp = CALLREGCOMP(t, t + len, pm);
+           pm->op_pmregexp = CALLREGCOMP(aTHX_ t, t + len, pm);
            PL_reginterp_cnt = 0;               /* XXXX Be extra paranoid - needed
                                           inside tie/overload accessors.  */
        }
@@ -163,14 +158,14 @@ PP(pp_substcont)
 
     if (cx->sb_iters++) {
        if (cx->sb_iters > cx->sb_maxiters)
-           DIE("Substitution loop");
+           DIE(aTHX_ "Substitution loop");
 
        if (!(cx->sb_rxtainted & 2) && SvTAINTED(TOPs))
            cx->sb_rxtainted |= 2;
        sv_catsv(dstr, POPs);
 
        /* Are we done */
-       if (cx->sb_once || !CALLREGEXEC(rx, s, cx->sb_strend, orig,
+       if (cx->sb_once || !CALLREGEXEC(aTHX_ rx, s, cx->sb_strend, orig,
                                     s == m, cx->sb_targ, NULL,
                                     ((cx->sb_rflags & REXEC_COPY_STR)
                                      ? (REXEC_IGNOREPOS|REXEC_NOT_FIRST)
@@ -218,7 +213,7 @@ PP(pp_substcont)
 }
 
 void
-rxres_save(void **rsp, REGEXP *rx)
+Perl_rxres_save(pTHX_ void **rsp, REGEXP *rx)
 {
     UV *p = (UV*)*rsp;
     U32 i;
@@ -246,7 +241,7 @@ rxres_save(void **rsp, REGEXP *rx)
 }
 
 void
-rxres_restore(void **rsp, REGEXP *rx)
+Perl_rxres_restore(pTHX_ void **rsp, REGEXP *rx)
 {
     UV *p = (UV*)*rsp;
     U32 i;
@@ -267,7 +262,7 @@ rxres_restore(void **rsp, REGEXP *rx)
 }
 
 void
-rxres_free(void **rsp)
+Perl_rxres_free(pTHX_ void **rsp)
 {
     UV *p = (UV*)*rsp;
 
@@ -296,7 +291,7 @@ PP(pp_formline)
     bool chopspace = (strchr(PL_chopset, ' ') != Nullch);
     char *chophere;
     char *linemark;
-    double value;
+    NV value;
     bool gotsome;
     STRLEN len;
     STRLEN fudge = SvCUR(tmpForm) * (IN_UTF8 ? 3 : 1) + 1;
@@ -370,7 +365,7 @@ PP(pp_formline)
            else {
                sv = &PL_sv_no;
                if (ckWARN(WARN_SYNTAX))
-                   warner(WARN_SYNTAX, "Not enough format arguments");
+                   Perl_warner(aTHX_ WARN_SYNTAX, "Not enough format arguments");
            }
            break;
 
@@ -587,11 +582,25 @@ PP(pp_formline)
            gotsome = TRUE;
            value = SvNV(sv);
            /* Formats aren't yet marked for locales, so assume "yes". */
-           SET_NUMERIC_LOCAL();
-           if (arg & 256) {
-               sprintf(t, "%#*.*f", (int) fieldsize, (int) arg & 255, value);
-           } else {
-               sprintf(t, "%*.0f", (int) fieldsize, value);
+           {
+               RESTORE_NUMERIC_LOCAL();
+#if defined(USE_LONG_DOUBLE)
+               if (arg & 256) {
+                   sprintf(t, "%#*.*Lf",
+                           (int) fieldsize, (int) arg & 255, value);
+               } else {
+                   sprintf(t, "%*.0Lf", (int) fieldsize, value);
+               }
+#else
+               if (arg & 256) {
+                   sprintf(t, "%#*.*f",
+                           (int) fieldsize, (int) arg & 255, value);
+               } else {
+                   sprintf(t, "%*.0f",
+                           (int) fieldsize, value);
+               }
+#endif
+               RESTORE_NUMERIC_STANDARD();
            }
            t += fieldsize;
            break;
@@ -613,7 +622,7 @@ PP(pp_formline)
                    if (lines == 200) {
                        arg = t - linemark;
                        if (strnEQ(linemark, linemark - arg, arg))
-                           DIE("Runaway format");
+                           DIE(aTHX_ "Runaway format");
                    }
                    FmLINES(PL_formtarget) = lines;
                    SP = ORIGMARK;
@@ -673,8 +682,8 @@ PP(pp_grepstart)
        RETURNOP(PL_op->op_next->op_next);
     }
     PL_stack_sp = PL_stack_base + *PL_markstack_ptr + 1;
-    pp_pushmark(ARGS);                         /* push dst */
-    pp_pushmark(ARGS);                         /* push src */
+    pp_pushmark();                             /* push dst */
+    pp_pushmark();                             /* push src */
     ENTER;                                     /* enter outer scope */
 
     SAVETMPS;
@@ -689,13 +698,13 @@ PP(pp_grepstart)
 
     PUTBACK;
     if (PL_op->op_type == OP_MAPSTART)
-       pp_pushmark(ARGS);                      /* push top */
+       pp_pushmark();                  /* push top */
     return ((LOGOP*)PL_op->op_next)->op_other;
 }
 
 PP(pp_mapstart)
 {
-    DIE("panic: mapstart");    /* uses grepstart */
+    DIE(aTHX_ "panic: mapstart");      /* uses grepstart */
 }
 
 PP(pp_mapwhile)
@@ -761,119 +770,6 @@ PP(pp_mapwhile)
     }
 }
 
-STATIC I32
-sv_ncmp (SV *a, SV *b)
-{
-    double nv1 = SvNV(a);
-    double nv2 = SvNV(b);
-    return nv1 < nv2 ? -1 : nv1 > nv2 ? 1 : 0;
-}
-STATIC I32
-sv_i_ncmp (SV *a, SV *b)
-{
-    IV iv1 = SvIV(a);
-    IV iv2 = SvIV(b);
-    return iv1 < iv2 ? -1 : iv1 > iv2 ? 1 : 0;
-}
-#define tryCALL_AMAGICbin(left,right,meth,svp) STMT_START { \
-         *svp = Nullsv;                                \
-          if (PL_amagic_generation) { \
-           if (SvAMAGIC(left)||SvAMAGIC(right))\
-               *svp = amagic_call(left, \
-                                  right, \
-                                  CAT2(meth,_amg), \
-                                  0); \
-         } \
-       } STMT_END
-
-STATIC I32
-amagic_ncmp(register SV *a, register SV *b)
-{
-    SV *tmpsv;
-    tryCALL_AMAGICbin(a,b,ncmp,&tmpsv);
-    if (tmpsv) {
-       double d;
-       
-        if (SvIOK(tmpsv)) {
-            I32 i = SvIVX(tmpsv);
-            if (i > 0)
-               return 1;
-            return i? -1 : 0;
-        }
-        d = SvNV(tmpsv);
-        if (d > 0)
-           return 1;
-        return d? -1 : 0;
-     }
-     return sv_ncmp(a, b);
-}
-
-STATIC I32
-amagic_i_ncmp(register SV *a, register SV *b)
-{
-    SV *tmpsv;
-    tryCALL_AMAGICbin(a,b,ncmp,&tmpsv);
-    if (tmpsv) {
-       double d;
-       
-        if (SvIOK(tmpsv)) {
-            I32 i = SvIVX(tmpsv);
-            if (i > 0)
-               return 1;
-            return i? -1 : 0;
-        }
-        d = SvNV(tmpsv);
-        if (d > 0)
-           return 1;
-        return d? -1 : 0;
-    }
-    return sv_i_ncmp(a, b);
-}
-
-STATIC I32
-amagic_cmp(register SV *str1, register SV *str2)
-{
-    SV *tmpsv;
-    tryCALL_AMAGICbin(str1,str2,scmp,&tmpsv);
-    if (tmpsv) {
-       double d;
-       
-        if (SvIOK(tmpsv)) {
-            I32 i = SvIVX(tmpsv);
-            if (i > 0)
-               return 1;
-            return i? -1 : 0;
-        }
-        d = SvNV(tmpsv);
-        if (d > 0)
-           return 1;
-        return d? -1 : 0;
-    }
-    return sv_cmp(str1, str2);
-}
-
-STATIC I32
-amagic_cmp_locale(register SV *str1, register SV *str2)
-{
-    SV *tmpsv;
-    tryCALL_AMAGICbin(str1,str2,scmp,&tmpsv);
-    if (tmpsv) {
-       double d;
-       
-        if (SvIOK(tmpsv)) {
-            I32 i = SvIVX(tmpsv);
-            if (i > 0)
-               return 1;
-            return i? -1 : 0;
-        }
-        d = SvNV(tmpsv);
-        if (d > 0)
-           return 1;
-        return d? -1 : 0;
-    }
-    return sv_cmp_locale(str1, str2);
-}
-
 PP(pp_sort)
 {
     djSP; dMARK; dORIGMARK;
@@ -909,16 +805,16 @@ PP(pp_sort)
                    SV *tmpstr = sv_newmortal();
                    gv_efullname3(tmpstr, gv, Nullch);
                    if (cv && CvXSUB(cv))
-                       DIE("Xsub \"%s\" called in sort", SvPVX(tmpstr));
-                   DIE("Undefined sort subroutine \"%s\" called",
+                       DIE(aTHX_ "Xsub \"%s\" called in sort", SvPVX(tmpstr));
+                   DIE(aTHX_ "Undefined sort subroutine \"%s\" called",
                        SvPVX(tmpstr));
                }
                if (cv) {
                    if (CvXSUB(cv))
-                       DIE("Xsub called in sort");
-                   DIE("Undefined subroutine in sort");
+                       DIE(aTHX_ "Xsub called in sort");
+                   DIE(aTHX_ "Undefined subroutine in sort");
                }
-               DIE("Not a CODE reference in sort");
+               DIE(aTHX_ "Not a CODE reference in sort");
            }
            PL_sortcop = CvSTART(cv);
            SAVESPTR(CvROOT(cv)->op_ppaddr);
@@ -979,7 +875,7 @@ PP(pp_sort)
                    (void)SvREFCNT_inc(cv); /* in preparation for POPSUB */
            }
            PL_sortcxix = cxstack_ix;
-           qsortsv((myorigmark+1), max, FUNC_NAME_TO_PTR(sortcv));
+           qsortsv((myorigmark+1), max, sortcv);
 
            POPBLOCK(cx,PL_curpm);
            PL_stack_sp = newsp;
@@ -993,19 +889,13 @@ PP(pp_sort)
            qsortsv(ORIGMARK+1, max,
                    (PL_op->op_private & OPpSORT_NUMERIC)
                        ? ( (PL_op->op_private & OPpSORT_INTEGER)
-                           ? ( overloading
-                               ? FUNC_NAME_TO_PTR(amagic_i_ncmp)
-                               : FUNC_NAME_TO_PTR(sv_i_ncmp))
-                           : ( overloading
-                               ? FUNC_NAME_TO_PTR(amagic_ncmp)
-                               : FUNC_NAME_TO_PTR(sv_ncmp)))
+                           ? ( overloading ? amagic_i_ncmp : sv_i_ncmp)
+                           : ( overloading ? amagic_ncmp : sv_ncmp))
                        : ( (PL_op->op_private & OPpLOCALE)
                            ? ( overloading
-                               ? FUNC_NAME_TO_PTR(amagic_cmp_locale)
-                               : FUNC_NAME_TO_PTR(sv_cmp_locale))
-                           : ( overloading
-                               ? FUNC_NAME_TO_PTR(amagic_cmp)
-                   : FUNC_NAME_TO_PTR(sv_cmp) )));
+                               ? amagic_cmp_locale
+                               : sv_cmp_locale_static)
+                           : ( overloading ? amagic_cmp : sv_cmp_static)));
            if (PL_op->op_private & OPpSORT_REVERSE) {
                SV **p = ORIGMARK+1;
                SV **q = ORIGMARK+max;
@@ -1027,11 +917,11 @@ PP(pp_sort)
 PP(pp_range)
 {
     if (GIMME == G_ARRAY)
-       return cCONDOP->op_true;
+       return NORMAL;
     if (SvTRUEx(PAD_SV(PL_op->op_targ)))
-       return cCONDOP->op_false;
+       return cLOGOP->op_other;
     else
-       return cCONDOP->op_true;
+       return NORMAL;
 }
 
 PP(pp_flip)
@@ -1039,7 +929,7 @@ PP(pp_flip)
     djSP;
 
     if (GIMME == G_ARRAY) {
-       RETURNOP(((CONDOP*)cUNOP->op_first)->op_false);
+       RETURNOP(((LOGOP*)cUNOP->op_first)->op_other);
     }
     else {
        dTOPss;
@@ -1057,7 +947,7 @@ PP(pp_flip)
            else {
                sv_setiv(targ, 0);
                SP--;
-               RETURNOP(((CONDOP*)cUNOP->op_first)->op_false);
+               RETURNOP(((LOGOP*)cUNOP->op_first)->op_other);
            }
        }
        sv_setpv(TARG, "");
@@ -1085,7 +975,7 @@ PP(pp_flop)
          (looks_like_number(left) && *SvPVX(left) != '0') )
        {
            if (SvNV(left) < IV_MIN || SvNV(right) > IV_MAX)
-               croak("Range iterator outside integer range");
+               Perl_croak(aTHX_ "Range iterator outside integer range");
            i = SvIV(left);
            max = SvIV(right);
            if (max >= i) {
@@ -1135,7 +1025,7 @@ PP(pp_flop)
 /* Control. */
 
 STATIC I32
-dopoptolabel(char *label)
+S_dopoptolabel(pTHX_ char *label)
 {
     dTHR;
     register I32 i;
@@ -1146,32 +1036,32 @@ dopoptolabel(char *label)
        switch (CxTYPE(cx)) {
        case CXt_SUBST:
            if (ckWARN(WARN_UNSAFE))
-               warner(WARN_UNSAFE, "Exiting substitution via %s", 
+               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting substitution via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_SUB:
            if (ckWARN(WARN_UNSAFE))
-               warner(WARN_UNSAFE, "Exiting subroutine via %s", 
+               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting subroutine via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_EVAL:
            if (ckWARN(WARN_UNSAFE))
-               warner(WARN_UNSAFE, "Exiting eval via %s", 
+               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting eval via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_NULL:
            if (ckWARN(WARN_UNSAFE))
-               warner(WARN_UNSAFE, "Exiting pseudo-block via %s", 
+               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting pseudo-block via %s", 
                        PL_op_name[PL_op->op_type]);
            return -1;
        case CXt_LOOP:
            if (!cx->blk_loop.label ||
              strNE(label, cx->blk_loop.label) ) {
-               DEBUG_l(deb("(Skipping label #%ld %s)\n",
+               DEBUG_l(Perl_deb(aTHX_ "(Skipping label #%ld %s)\n",
                        (long)i, cx->blk_loop.label));
                continue;
            }
-           DEBUG_l( deb("(Found label #%ld %s)\n", (long)i, label));
+           DEBUG_l( Perl_deb(aTHX_ "(Found label #%ld %s)\n", (long)i, label));
            return i;
        }
     }
@@ -1179,14 +1069,14 @@ dopoptolabel(char *label)
 }
 
 I32
-dowantarray(void)
+Perl_dowantarray(pTHX)
 {
     I32 gimme = block_gimme();
     return (gimme == G_VOID) ? G_SCALAR : gimme;
 }
 
 I32
-block_gimme(void)
+Perl_block_gimme(pTHX)
 {
     dTHR;
     I32 cxix;
@@ -1203,21 +1093,21 @@ block_gimme(void)
     case G_ARRAY:
        return G_ARRAY;
     default:
-       croak("panic: bad gimme: %d\n", cxstack[cxix].blk_gimme);
+       Perl_croak(aTHX_ "panic: bad gimme: %d\n", cxstack[cxix].blk_gimme);
        /* NOTREACHED */
        return 0;
     }
 }
 
 STATIC I32
-dopoptosub(I32 startingblock)
+S_dopoptosub(pTHX_ I32 startingblock)
 {
     dTHR;
     return dopoptosub_at(cxstack, startingblock);
 }
 
 STATIC I32
-dopoptosub_at(PERL_CONTEXT *cxstk, I32 startingblock)
+S_dopoptosub_at(pTHX_ PERL_CONTEXT *cxstk, I32 startingblock)
 {
     dTHR;
     I32 i;
@@ -1229,7 +1119,7 @@ dopoptosub_at(PERL_CONTEXT *cxstk, I32 startingblock)
            continue;
        case CXt_EVAL:
        case CXt_SUB:
-           DEBUG_l( deb("(Found sub #%ld)\n", (long)i));
+           DEBUG_l( Perl_deb(aTHX_ "(Found sub #%ld)\n", (long)i));
            return i;
        }
     }
@@ -1237,7 +1127,7 @@ dopoptosub_at(PERL_CONTEXT *cxstk, I32 startingblock)
 }
 
 STATIC I32
-dopoptoeval(I32 startingblock)
+S_dopoptoeval(pTHX_ I32 startingblock)
 {
     dTHR;
     I32 i;
@@ -1248,7 +1138,7 @@ dopoptoeval(I32 startingblock)
        default:
            continue;
        case CXt_EVAL:
-           DEBUG_l( deb("(Found eval #%ld)\n", (long)i));
+           DEBUG_l( Perl_deb(aTHX_ "(Found eval #%ld)\n", (long)i));
            return i;
        }
     }
@@ -1256,7 +1146,7 @@ dopoptoeval(I32 startingblock)
 }
 
 STATIC I32
-dopoptoloop(I32 startingblock)
+S_dopoptoloop(pTHX_ I32 startingblock)
 {
     dTHR;
     I32 i;
@@ -1266,26 +1156,26 @@ dopoptoloop(I32 startingblock)
        switch (CxTYPE(cx)) {
        case CXt_SUBST:
            if (ckWARN(WARN_UNSAFE))
-               warner(WARN_UNSAFE, "Exiting substitution via %s", 
+               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting substitution via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_SUB:
            if (ckWARN(WARN_UNSAFE))
-               warner(WARN_UNSAFE, "Exiting subroutine via %s", 
+               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting subroutine via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_EVAL:
            if (ckWARN(WARN_UNSAFE))
-               warner(WARN_UNSAFE, "Exiting eval via %s", 
+               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting eval via %s", 
                        PL_op_name[PL_op->op_type]);
            break;
        case CXt_NULL:
            if (ckWARN(WARN_UNSAFE))
-               warner(WARN_UNSAFE, "Exiting pseudo-block via %s", 
+               Perl_warner(aTHX_ WARN_UNSAFE, "Exiting pseudo-block via %s", 
                        PL_op_name[PL_op->op_type]);
            return -1;
        case CXt_LOOP:
-           DEBUG_l( deb("(Found loop #%ld)\n", (long)i));
+           DEBUG_l( Perl_deb(aTHX_ "(Found loop #%ld)\n", (long)i));
            return i;
        }
     }
@@ -1293,7 +1183,7 @@ dopoptoloop(I32 startingblock)
 }
 
 void
-dounwind(I32 cxix)
+Perl_dounwind(pTHX_ I32 cxix)
 {
     dTHR;
     register PERL_CONTEXT *cx;
@@ -1335,7 +1225,7 @@ dounwind(I32 cxix)
  * relying on the incidental global values.
  */
 STATIC void
-free_closures(void)
+S_free_closures(pTHX)
 {
     dTHR;
     SV **svp = AvARRAY(PL_comppad_name);
@@ -1362,7 +1252,7 @@ free_closures(void)
 }
 
 OP *
-die_where(char *message, STRLEN msglen)
+Perl_die_where(pTHX_ char *message, STRLEN msglen)
 {
     dSP;
     STRLEN n_a;
@@ -1390,7 +1280,7 @@ die_where(char *message, STRLEN msglen)
                        sv_catpvn(err, message, msglen);
                        if (ckWARN(WARN_UNSAFE)) {
                            STRLEN start = SvCUR(err)-msglen-sizeof(prefix)+1;
-                           warner(WARN_UNSAFE, SvPVX(err)+start);
+                           Perl_warner(aTHX_ WARN_UNSAFE, SvPVX(err)+start);
                        }
                    }
                    sv_inc(*svp);
@@ -1429,7 +1319,7 @@ die_where(char *message, STRLEN msglen)
 
            if (optype == OP_REQUIRE) {
                char* msg = SvPVx(ERRSV, n_a);
-               DIE("%s", *msg ? msg : "Compilation failed in require");
+               DIE(aTHX_ "%s", *msg ? msg : "Compilation failed in require");
            }
            return pop_return();
        }
@@ -1494,7 +1384,7 @@ PP(pp_caller)
 
     if (MAXARG)
        count = POPi;
-    EXTEND(SP, 6);
+    EXTEND(SP, 7);
     for (;;) {
        /* we may be in a higher stacklevel, so dig down deeper */
        while (cxix < 0 && top_si->si_type != PERLSI_MAIN) {
@@ -1572,9 +1462,12 @@ PP(pp_caller)
            PUSHs(&PL_sv_yes);
        }
     }
-    else if (CxTYPE(cx) == CXt_SUB &&
-           cx->blk_sub.hasargs &&
-           PL_curcop->cop_stash == PL_debstash)
+    else {
+       PUSHs(&PL_sv_undef);
+       PUSHs(&PL_sv_undef);
+    }
+    if (CxTYPE(cx) == CXt_SUB && cx->blk_sub.hasargs
+       && PL_curcop->cop_stash == PL_debstash)
     {
        AV *ary = cx->blk_sub.argarray;
        int off = AvARRAY(ary) - AvALLOC(ary);
@@ -1592,33 +1485,14 @@ PP(pp_caller)
        Copy(AvALLOC(ary), AvARRAY(PL_dbargs), AvFILLp(ary) + 1 + off, SV*);
        AvFILLp(PL_dbargs) = AvFILLp(ary) + off;
     }
+    /* XXX only hints propagated via op_private are currently
+     * visible (others are not easily accessible, since they
+     * use the global PL_hints) */
+    PUSHs(sv_2mortal(newSViv((I32)cx->blk_oldcop->op_private &
+                            HINT_PRIVATE_MASK)));
     RETURN;
 }
 
-STATIC I32
-sortcv(SV *a, SV *b)
-{
-    dTHR;
-    I32 oldsaveix = PL_savestack_ix;
-    I32 oldscopeix = PL_scopestack_ix;
-    I32 result;
-    GvSV(PL_firstgv) = a;
-    GvSV(PL_secondgv) = b;
-    PL_stack_sp = PL_stack_base;
-    PL_op = PL_sortcop;
-    CALLRUNOPS();
-    if (PL_stack_sp != PL_stack_base + 1)
-       croak("Sort subroutine didn't return single value");
-    if (!SvNIOKp(*PL_stack_sp))
-       croak("Sort subroutine didn't return a numeric value");
-    result = SvIV(*PL_stack_sp);
-    while (PL_scopestack_ix > oldscopeix) {
-       LEAVE;
-    }
-    leave_scope(oldsaveix);
-    return result;
-}
-
 PP(pp_reset)
 {
     djSP;
@@ -1658,7 +1532,7 @@ PP(pp_dbstate)
        gv = PL_DBgv;
        cv = GvCV(gv);
        if (!cv)
-           DIE("No DB::DB routine defined");
+           DIE(aTHX_ "No DB::DB routine defined");
 
        if (CvDEPTH(cv) >= 1 && !(PL_debug & (1<<30))) /* don't do recursive DB::DB call */
            return NORMAL;
@@ -1731,7 +1605,7 @@ PP(pp_enteriter)
                (looks_like_number(sv) && *SvPVX(sv) != '0')) {
                 if (SvNV(sv) < IV_MIN ||
                     SvNV((SV*)cx->blk_loop.iterary) >= IV_MAX)
-                    croak("Range iterator outside integer range");
+                    Perl_croak(aTHX_ "Range iterator outside integer range");
                 cx->blk_loop.iterix = SvIV(sv);
                 cx->blk_loop.itermax = SvIV((SV*)cx->blk_loop.iterary);
            }
@@ -1829,7 +1703,7 @@ PP(pp_return)
 
     cxix = dopoptosub(cxstack_ix);
     if (cxix < 0)
-       DIE("Can't return outside a subroutine");
+       DIE(aTHX_ "Can't return outside a subroutine");
     if (cxix < cxstack_ix)
        dounwind(cxix);
 
@@ -1850,11 +1724,11 @@ PP(pp_return)
            /* 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("%s did not return a true value", name);
+           DIE(aTHX_ "%s did not return a true value", name);
        }
        break;
     default:
-       DIE("panic: return");
+       DIE(aTHX_ "panic: return");
     }
 
     TAINT_NOT;
@@ -1914,12 +1788,12 @@ PP(pp_last)
     if (PL_op->op_flags & OPf_SPECIAL) {
        cxix = dopoptoloop(cxstack_ix);
        if (cxix < 0)
-           DIE("Can't \"last\" outside a block");
+           DIE(aTHX_ "Can't \"last\" outside a block");
     }
     else {
        cxix = dopoptolabel(cPVOP->op_pv);
        if (cxix < 0)
-           DIE("Label not found for \"last %s\"", cPVOP->op_pv);
+           DIE(aTHX_ "Label not found for \"last %s\"", cPVOP->op_pv);
     }
     if (cxix < cxstack_ix)
        dounwind(cxix);
@@ -1941,7 +1815,7 @@ PP(pp_last)
        nextop = pop_return();
        break;
     default:
-       DIE("panic: last");
+       DIE(aTHX_ "panic: last");
     }
 
     TAINT_NOT;
@@ -1987,12 +1861,12 @@ PP(pp_next)
     if (PL_op->op_flags & OPf_SPECIAL) {
        cxix = dopoptoloop(cxstack_ix);
        if (cxix < 0)
-           DIE("Can't \"next\" outside a block");
+           DIE(aTHX_ "Can't \"next\" outside a block");
     }
     else {
        cxix = dopoptolabel(cPVOP->op_pv);
        if (cxix < 0)
-           DIE("Label not found for \"next %s\"", cPVOP->op_pv);
+           DIE(aTHX_ "Label not found for \"next %s\"", cPVOP->op_pv);
     }
     if (cxix < cxstack_ix)
        dounwind(cxix);
@@ -2012,12 +1886,12 @@ PP(pp_redo)
     if (PL_op->op_flags & OPf_SPECIAL) {
        cxix = dopoptoloop(cxstack_ix);
        if (cxix < 0)
-           DIE("Can't \"redo\" outside a block");
+           DIE(aTHX_ "Can't \"redo\" outside a block");
     }
     else {
        cxix = dopoptolabel(cPVOP->op_pv);
        if (cxix < 0)
-           DIE("Label not found for \"redo %s\"", cPVOP->op_pv);
+           DIE(aTHX_ "Label not found for \"redo %s\"", cPVOP->op_pv);
     }
     if (cxix < cxstack_ix)
        dounwind(cxix);
@@ -2029,14 +1903,14 @@ PP(pp_redo)
 }
 
 STATIC OP *
-dofindlabel(OP *o, char *label, OP **opstack, OP **oplimit)
+S_dofindlabel(pTHX_ OP *o, char *label, OP **opstack, OP **oplimit)
 {
     OP *kid;
     OP **ops = opstack;
     static char too_deep[] = "Target of goto is too deeply nested";
 
     if (ops >= oplimit)
-       croak(too_deep);
+       Perl_croak(aTHX_ too_deep);
     if (o->op_type == OP_LEAVE ||
        o->op_type == OP_SCOPE ||
        o->op_type == OP_LEAVELOOP ||
@@ -2044,36 +1918,39 @@ dofindlabel(OP *o, char *label, OP **opstack, OP **oplimit)
     {
        *ops++ = cUNOPo->op_first;
        if (ops >= oplimit)
-           croak(too_deep);
+           Perl_croak(aTHX_ too_deep);
+       *ops = 0;
     }
-    *ops = 0;
     if (o->op_flags & OPf_KIDS) {
        dTHR;
        /* 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))
+           if ((kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE)
+               && kCOP->cop_label && strEQ(kCOP->cop_label, label))
+           {
                return kid;
+           }
        }
        for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) {
            if (kid == PL_lastgotoprobe)
                continue;
-           if ((kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) &&
-               (ops == opstack ||
-                (ops[-1]->op_type != OP_NEXTSTATE &&
-                 ops[-1]->op_type != OP_DBSTATE)))
+           if ((kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE)
+               && (ops == opstack || (ops[-1]->op_type != OP_NEXTSTATE
+                                      && ops[-1]->op_type != OP_DBSTATE)))
+           {
                *ops++ = kid;
+               *ops = 0;
+           }
            if (o = dofindlabel(kid, label, ops, oplimit))
                return o;
        }
     }
-    *ops = 0;
     return 0;
 }
 
 PP(pp_dump)
 {
-    return pp_goto(ARGS);
+    return pp_goto();
     /*NOTREACHED*/
 }
 
@@ -2119,20 +1996,20 @@ PP(pp_goto)
                        goto retry;
                    tmpstr = sv_newmortal();
                    gv_efullname3(tmpstr, gv, Nullch);
-                   DIE("Goto undefined subroutine &%s",SvPVX(tmpstr));
+                   DIE(aTHX_ "Goto undefined subroutine &%s",SvPVX(tmpstr));
                }
-               DIE("Goto undefined subroutine");
+               DIE(aTHX_ "Goto undefined subroutine");
            }
 
            /* First do some returnish stuff. */
            cxix = dopoptosub(cxstack_ix);
            if (cxix < 0)
-               DIE("Can't goto subroutine outside a subroutine");
+               DIE(aTHX_ "Can't goto subroutine outside a subroutine");
            if (cxix < cxstack_ix)
                dounwind(cxix);
            TOPBLOCK(cx);
            if (CxTYPE(cx) == CXt_EVAL && cx->blk_eval.old_op_type == OP_ENTEREVAL) 
-               DIE("Can't goto subroutine from an eval-string");
+               DIE(aTHX_ "Can't goto subroutine from an eval-string");
            mark = PL_stack_sp;
            if (CxTYPE(cx) == CXt_SUB &&
                cx->blk_sub.hasargs) {   /* put @_ back onto stack */
@@ -2198,7 +2075,7 @@ PP(pp_goto)
                    PL_stack_sp--;              /* There is no cv arg. */
                    /* Push a mark for the start of arglist */
                    PUSHMARK(mark); 
-                   (void)(*CvXSUB(cv))(cv _PERL_OBJECT_THIS);
+                   (void)(*CvXSUB(cv))(aTHXo_ cv);
                    /* Pop the current context like a decent sub should */
                    POPBLOCK(cx, PL_curpm);
                    /* Do _not_ use PUTBACK, keep the XSUB's return stack! */
@@ -2335,9 +2212,9 @@ PP(pp_goto)
                        gv_efullname3(sv, CvGV(cv), Nullch);
                    }
                    if (  PERLDB_GOTO
-                         && (gotocv = perl_get_cv("DB::goto", FALSE)) ) {
+                         && (gotocv = get_cv("DB::goto", FALSE)) ) {
                        PUSHMARK( PL_stack_sp );
-                       perl_call_sv((SV*)gotocv, G_SCALAR | G_NODEBUG);
+                       call_sv((SV*)gotocv, G_SCALAR | G_NODEBUG);
                        PL_stack_sp--;
                    }
                }
@@ -2347,12 +2224,12 @@ PP(pp_goto)
        else {
            label = SvPV(sv,n_a);
            if (!(do_dump || *label))
-               DIE(must_have_label);
+               DIE(aTHX_ must_have_label);
        }
     }
     else if (PL_op->op_flags & OPf_SPECIAL) {
        if (! do_dump)
-           DIE(must_have_label);
+           DIE(aTHX_ must_have_label);
     }
     else
        label = cPVOP->op_pv;
@@ -2388,10 +2265,10 @@ PP(pp_goto)
                }
                /* FALL THROUGH */
            case CXt_NULL:
-               DIE("Can't \"goto\" outside a block");
+               DIE(aTHX_ "Can't \"goto\" outside a block");
            default:
                if (ix)
-                   DIE("panic: goto");
+                   DIE(aTHX_ "panic: goto");
                gotoprobe = PL_main_root;
                break;
            }
@@ -2402,7 +2279,7 @@ PP(pp_goto)
            PL_lastgotoprobe = gotoprobe;
        }
        if (!retop)
-           DIE("Can't find label %s", label);
+           DIE(aTHX_ "Can't find label %s", label);
 
        /* pop unwanted frames */
 
@@ -2426,9 +2303,9 @@ 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("Can't \"goto\" into the middle of a foreach loop",
+                   DIE(aTHX_ "Can't \"goto\" into the middle of a foreach loop",
                        label);
-               (CALLOP->op_ppaddr)(ARGS);
+               (CALLOP->op_ppaddr)(aTHX);
            }
            PL_op = oldop;
        }
@@ -2473,11 +2350,11 @@ PP(pp_exit)
 PP(pp_nswitch)
 {
     djSP;
-    double value = SvNVx(GvSV(cCOP->cop_gv));
+    NV value = SvNVx(GvSV(cCOP->cop_gv));
     register I32 match = I_32(value);
 
     if (value < 0.0) {
-       if (((double)match) > value)
+       if (((NV)match) > value)
            --match;            /* was fractional--truncate other way */
     }
     match -= cCOP->uop.scop.scop_offset;
@@ -2513,7 +2390,7 @@ PP(pp_cswitch)
 /* Eval. */
 
 STATIC void
-save_lines(AV *array, SV *sv)
+S_save_lines(pTHX_ AV *array, SV *sv)
 {
     register char *s = SvPVX(sv);
     register char *send = SvPVX(sv) + SvCUR(sv);
@@ -2537,14 +2414,14 @@ save_lines(AV *array, SV *sv)
 }
 
 STATIC void *
-docatch_body(va_list args)
+S_docatch_body(pTHX_ va_list args)
 {
-    CALLRUNOPS();
+    CALLRUNOPS(aTHX);
     return NULL;
 }
 
 STATIC OP *
-docatch(OP *o)
+S_docatch(pTHX_ OP *o)
 {
     dTHR;
     int ret;
@@ -2555,7 +2432,7 @@ docatch(OP *o)
 #endif
     PL_op = o;
  redo_body:
-    CALLPROTECT(&ret, FUNC_NAME_TO_PTR(docatch_body));
+    CALLPROTECT(aTHX_ &ret, MEMBER_TO_FPTR(S_docatch_body));
     switch (ret) {
     case 0:
        break;
@@ -2576,7 +2453,7 @@ docatch(OP *o)
 }
 
 OP *
-sv_compile_2op(SV *sv, OP** startop, char *code, AV** avp)
+Perl_sv_compile_2op(pTHX_ SV *sv, OP** startop, char *code, AV** avp)
 /* sv Text to convert to OP tree. */
 /* startop op_free() this to undo. */
 /* code Short string id of the caller. */
@@ -2644,7 +2521,7 @@ sv_compile_2op(SV *sv, OP** startop, char *code, AV** avp)
 
 /* With USE_THREADS, eval_owner must be held on entry to doeval */
 STATIC OP *
-doeval(int gimme, OP** startop)
+S_doeval(pTHX_ int gimme, OP** startop)
 {
     dSP;
     OP *saveop = PL_op;
@@ -2741,7 +2618,7 @@ doeval(int gimme, OP** startop)
        PERL_CONTEXT *cx;
        I32 optype = 0;                 /* Might be reset by POPEVAL. */
        STRLEN n_a;
-
+       
        PL_op = saveop;
        if (PL_eval_root) {
            op_free(PL_eval_root);
@@ -2757,13 +2634,13 @@ doeval(int gimme, OP** startop)
        LEAVE;
        if (optype == OP_REQUIRE) {
            char* msg = SvPVx(ERRSV, n_a);
-           DIE("%s", *msg ? msg : "Compilation failed in require");
+           DIE(aTHX_ "%s", *msg ? msg : "Compilation failed in require");
        } else if (startop) {
            char* msg = SvPVx(ERRSV, n_a);
 
            POPBLOCK(cx,PL_curpm);
            POPEVAL(cx);
-           croak("%sCompilation failed in regexp", (*msg ? msg : "Unknown error\n"));
+           Perl_croak(aTHX_ "%sCompilation failed in regexp", (*msg ? msg : "Unknown error\n"));
        }
        SvREFCNT_dec(PL_rs);
        PL_rs = SvREFCNT_inc(PL_nrs);
@@ -2795,13 +2672,13 @@ doeval(int gimme, OP** startop)
 
     /* Register with debugger: */
     if (PERLDB_INTER && saveop->op_type == OP_REQUIRE) {
-       CV *cv = perl_get_cv("DB::postponed", FALSE);
+       CV *cv = get_cv("DB::postponed", FALSE);
        if (cv) {
            dSP;
            PUSHMARK(SP);
            XPUSHs((SV*)PL_compiling.cop_filegv);
            PUTBACK;
-           perl_call_sv((SV*)cv, G_DISCARD);
+           call_sv((SV*)cv, G_DISCARD);
        }
     }
 
@@ -2821,13 +2698,13 @@ doeval(int gimme, OP** startop)
 }
 
 STATIC PerlIO *
-doopen_pmc(const char *name, const char *mode)
+S_doopen_pmc(pTHX_ const char *name, const char *mode)
 {
     STRLEN namelen = strlen(name);
     PerlIO *fp;
 
-    if (namelen > 3 && strcmp(name + namelen - 3, ".pm") == 0) {
-       SV *pmcsv = newSVpvf("%s%c", name, 'c');
+    if (namelen > 3 && strEQ(name + namelen - 3, ".pm")) {
+       SV *pmcsv = Perl_newSVpvf(aTHX_ "%s%c", name, 'c');
        char *pmc = SvPV_nolen(pmcsv);
        Stat_t pmstat;
        Stat_t pmcstat;
@@ -2868,15 +2745,14 @@ PP(pp_require)
 
     sv = POPs;
     if (SvNIOKp(sv) && !SvPOKp(sv)) {
-       SET_NUMERIC_STANDARD();
-       if (atof(PL_patchlevel) + 0.00000999 < SvNV(sv))
-           DIE("Perl %s required--this is only version %s, stopped",
+       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);
        RETPUSHYES;
     }
     name = SvPV(sv, len);
     if (!(name && len > 0 && *name))
-       DIE("Null filename used");
+       DIE(aTHX_ "Null filename used");
     TAINT_PROPER("require");
     if (PL_op->op_type == OP_REQUIRE &&
       (svp = hv_fetch(GvHVn(PL_incgv), name, len, 0)) &&
@@ -2922,7 +2798,7 @@ PP(pp_require)
                sv_setpv(namesv, unixdir);
                sv_catpv(namesv, unixname);
 #else
-               sv_setpvf(namesv, "%s/%s", dir, name);
+               Perl_sv_setpvf(aTHX_ namesv, "%s/%s", dir, name);
 #endif
                TAINT_PROPER("require");
                tryname = SvPVX(namesv);
@@ -2954,14 +2830,14 @@ PP(pp_require)
                sv_catpv(msg, " (@INC contains:");
                for (i = 0; i <= AvFILL(ar); i++) {
                    char *dir = SvPVx(*av_fetch(ar, i, TRUE), n_a);
-                   sv_setpvf(dirmsgsv, " %s", dir);
+                   Perl_sv_setpvf(aTHX_ dirmsgsv, " %s", dir);
                    sv_catsv(msg, dirmsgsv);
                }
                sv_catpvn(msg, ")", 1);
                SvREFCNT_dec(dirmsgsv);
                msgstr = SvPV_nolen(msg);
            }
-           DIE("Can't locate %s", msgstr);
+           DIE(aTHX_ "Can't locate %s", msgstr);
        }
 
        RETPUSHUNDEF;
@@ -2985,9 +2861,13 @@ PP(pp_require)
     SAVEHINTS();
     PL_hints = 0;
     SAVEPPTR(PL_compiling.cop_warnings);
-    PL_compiling.cop_warnings = ((PL_dowarn & G_WARN_ALL_ON) ? WARN_ALL 
-                                                            : WARN_NONE);
+    if (PL_dowarn & G_WARN_ALL_ON)
+        PL_compiling.cop_warnings = WARN_ALL ;
+    else if (PL_dowarn & G_WARN_ALL_OFF)
+        PL_compiling.cop_warnings = WARN_NONE ;
+    else 
+        PL_compiling.cop_warnings = WARN_STD ;
+    
     /* switch to eval mode */
 
     push_return(PL_op->op_next);
@@ -3011,7 +2891,7 @@ PP(pp_require)
 
 PP(pp_dofile)
 {
-    return pp_require(ARGS);
+    return pp_require();
 }
 
 PP(pp_entereval)
@@ -3049,8 +2929,7 @@ PP(pp_entereval)
     SAVEHINTS();
     PL_hints = PL_op->op_targ;
     SAVEPPTR(PL_compiling.cop_warnings);
-    if (PL_compiling.cop_warnings != WARN_ALL 
-       && PL_compiling.cop_warnings != WARN_NONE){
+    if (!specialWARN(PL_compiling.cop_warnings)) {
         PL_compiling.cop_warnings = newSVsv(PL_compiling.cop_warnings) ;
         SAVEFREESV(PL_compiling.cop_warnings) ;
     }
@@ -3138,7 +3017,7 @@ PP(pp_leaveeval)
        /* 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 = die("%s did not return a true value", name);
+       retop = Perl_die(aTHX_ "%s did not return a true value", name);
        /* die_where() did LEAVE, or we won't be here */
     }
     else {
@@ -3218,7 +3097,7 @@ PP(pp_leavetry)
 }
 
 STATIC void
-doparseform(SV *sv)
+S_doparseform(pTHX_ SV *sv)
 {
     STRLEN len;
     register char *s = SvPV_force(sv, len);
@@ -3235,7 +3114,7 @@ doparseform(SV *sv)
     bool ischop;
 
     if (len == 0)
-       croak("Null picture in formline");
+       Perl_croak(aTHX_ "Null picture in formline");
     
     New(804, fops, (send - s)*3+10, U16);    /* Almost certainly too long... */
     fpc = fops;
@@ -3501,13 +3380,8 @@ struct partition_stack_entry {
 
 /* Return < 0 == 0 or > 0 as the value of elt1 is < elt2, == elt2, > elt2
 */
-#ifdef PERL_OBJECT
 #define qsort_cmp(elt1, elt2) \
-   ((this->*compare)(array[elt1], array[elt2]))
-#else
-#define qsort_cmp(elt1, elt2) \
-   ((*compare)(array[elt1], array[elt2]))
-#endif
+   ((*compare)(aTHXo_ array[elt1], array[elt2]))
 
 #ifdef QSORT_ORDER_GUESS
 #define QSORT_NOTICE_SWAP swapped++;
@@ -3588,11 +3462,7 @@ doqsort_all_asserts(
 /* ****************************************************************** qsort */
 
 STATIC void
-#ifdef PERL_OBJECT
-qsortsv(SV ** array, size_t num_elts, SVCOMPARE compare)
-#else
-qsortsv(SV ** array, size_t num_elts, I32 (*compare)(SV *a, SV *b))
-#endif
+S_qsortsv(pTHX_ SV ** array, size_t num_elts, SVCOMPARE_t compare)
 {
    register SV * temp;
 
@@ -4082,3 +3952,167 @@ qsortsv(SV ** array, size_t num_elts, I32 (*compare)(SV *a, SV *b))
 
    /* Believe it or not, the array is sorted at this point! */
 }
+
+
+#ifdef PERL_OBJECT
+#define NO_XSLOCKS
+#undef this
+#define this pPerl
+#include "XSUB.h"
+#endif
+
+
+static I32
+sortcv(pTHXo_ SV *a, SV *b)
+{
+    dTHR;
+    I32 oldsaveix = PL_savestack_ix;
+    I32 oldscopeix = PL_scopestack_ix;
+    I32 result;
+    GvSV(PL_firstgv) = a;
+    GvSV(PL_secondgv) = 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
+sv_ncmp(pTHXo_ SV *a, SV *b)
+{
+    NV nv1 = SvNV(a);
+    NV nv2 = SvNV(b);
+    return nv1 < nv2 ? -1 : nv1 > nv2 ? 1 : 0;
+}
+
+static I32
+sv_i_ncmp(pTHXo_ SV *a, SV *b)
+{
+    IV iv1 = SvIV(a);
+    IV iv2 = SvIV(b);
+    return iv1 < iv2 ? -1 : iv1 > iv2 ? 1 : 0;
+}
+#define tryCALL_AMAGICbin(left,right,meth,svp) STMT_START { \
+         *svp = Nullsv;                                \
+          if (PL_amagic_generation) { \
+           if (SvAMAGIC(left)||SvAMAGIC(right))\
+               *svp = amagic_call(left, \
+                                  right, \
+                                  CAT2(meth,_amg), \
+                                  0); \
+         } \
+       } STMT_END
+
+static I32
+amagic_ncmp(pTHXo_ register SV *a, register SV *b)
+{
+    SV *tmpsv;
+    tryCALL_AMAGICbin(a,b,ncmp,&tmpsv);
+    if (tmpsv) {
+       NV d;
+       
+        if (SvIOK(tmpsv)) {
+            I32 i = SvIVX(tmpsv);
+            if (i > 0)
+               return 1;
+            return i? -1 : 0;
+        }
+        d = SvNV(tmpsv);
+        if (d > 0)
+           return 1;
+        return d? -1 : 0;
+     }
+     return sv_ncmp(aTHXo_ a, b);
+}
+
+static I32
+amagic_i_ncmp(pTHXo_ register SV *a, register SV *b)
+{
+    SV *tmpsv;
+    tryCALL_AMAGICbin(a,b,ncmp,&tmpsv);
+    if (tmpsv) {
+       NV d;
+       
+        if (SvIOK(tmpsv)) {
+            I32 i = SvIVX(tmpsv);
+            if (i > 0)
+               return 1;
+            return i? -1 : 0;
+        }
+        d = SvNV(tmpsv);
+        if (d > 0)
+           return 1;
+        return d? -1 : 0;
+    }
+    return sv_i_ncmp(aTHXo_ a, b);
+}
+
+static I32
+amagic_cmp(pTHXo_ register SV *str1, register SV *str2)
+{
+    SV *tmpsv;
+    tryCALL_AMAGICbin(str1,str2,scmp,&tmpsv);
+    if (tmpsv) {
+       NV d;
+       
+        if (SvIOK(tmpsv)) {
+            I32 i = SvIVX(tmpsv);
+            if (i > 0)
+               return 1;
+            return i? -1 : 0;
+        }
+        d = SvNV(tmpsv);
+        if (d > 0)
+           return 1;
+        return d? -1 : 0;
+    }
+    return sv_cmp(str1, str2);
+}
+
+static I32
+amagic_cmp_locale(pTHXo_ register SV *str1, register SV *str2)
+{
+    SV *tmpsv;
+    tryCALL_AMAGICbin(str1,str2,scmp,&tmpsv);
+    if (tmpsv) {
+       NV d;
+       
+        if (SvIOK(tmpsv)) {
+            I32 i = SvIVX(tmpsv);
+            if (i > 0)
+               return 1;
+            return i? -1 : 0;
+        }
+        d = SvNV(tmpsv);
+        if (d > 0)
+           return 1;
+        return d? -1 : 0;
+    }
+    return sv_cmp_locale(str1, str2);
+}
+
+#ifdef PERL_OBJECT
+
+static I32
+sv_cmp_locale_static(pTHXo_ register SV *str1, register SV *str2)
+{
+    return sv_cmp_locale(str1, str2);
+}
+
+static I32
+sv_cmp_static(pTHXo_ register SV *str1, register SV *str2)
+{
+    return sv_cmp(str1, str2);
+}
+
+#endif /* PERL_OBJECT */