This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
expunge gratuitous Unicode punctuation in comments
[perl5.git] / pp.c
diff --git a/pp.c b/pp.c
index 7e6a438..99f08b9 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -141,48 +141,57 @@ PP(pp_padhv)
 static const char S_no_symref_sv[] =
     "Can't use string (\"%" SVf32 "\"%s) as %s ref while \"strict refs\" in use";
 
-PP(pp_rv2gv)
-{
-    dVAR; dSP; dTOPss;
+/* In some cases this function inspects PL_op.  If this function is called
+   for new op types, more bool parameters may need to be added in place of
+   the checks.
+
+   When noinit is true, the absence of a gv will cause a retval of undef.
+   This is unrelated to the cv-to-gv assignment case.
+
+   Make sure to use SPAGAIN after calling this.
+*/
 
+static SV *
+S_rv2gv(pTHX_ SV *sv, const bool vivify_sv, const bool strict,
+              const bool noinit)
+{
+    dVAR;
     if (!isGV(sv) || SvFAKE(sv)) SvGETMAGIC(sv);
     if (SvROK(sv)) {
        if (SvAMAGIC(sv)) {
            sv = amagic_deref_call(sv, to_gv_amg);
-           SPAGAIN;
        }
       wasref:
        sv = SvRV(sv);
        if (SvTYPE(sv) == SVt_PVIO) {
            GV * const gv = MUTABLE_GV(sv_newmortal());
-           gv_init(gv, 0, "", 0, 0);
+           gv_init(gv, 0, "$__ANONIO__", 11, 0);
            GvIOp(gv) = MUTABLE_IO(sv);
            SvREFCNT_inc_void_NN(sv);
            sv = MUTABLE_SV(gv);
        }
        else if (!isGV_with_GP(sv))
-           DIE(aTHX_ "Not a GLOB reference");
+           return (SV *)Perl_die(aTHX_ "Not a GLOB reference");
     }
     else {
        if (!isGV_with_GP(sv)) {
-           if (!SvOK(sv) && sv != &PL_sv_undef) {
+           if (!SvOK(sv)) {
                /* If this is a 'my' scalar and flag is set then vivify
                 * NI-S 1999/05/07
                 */
-               if (SvREADONLY(sv))
-                   Perl_croak_no_modify(aTHX);
-               if (PL_op->op_private & OPpDEREF) {
+               if (vivify_sv && sv != &PL_sv_undef) {
                    GV *gv;
+                   if (SvREADONLY(sv))
+                       Perl_croak_no_modify(aTHX);
                    if (cUNOP->op_targ) {
-                       STRLEN len;
                        SV * const namesv = PAD_SV(cUNOP->op_targ);
-                       const char * const name = SvPV(namesv, len);
                        gv = MUTABLE_GV(newSV(0));
-                       gv_init(gv, CopSTASH(PL_curcop), name, len, 0);
+                       gv_init_sv(gv, CopSTASH(PL_curcop), namesv, 0);
                    }
                    else {
                        const char * const name = CopSTASHPV(PL_curcop);
-                       gv = newGVgen(name);
+                       gv = newGVgen_flags(name,
+                                        HvNAMEUTF8(CopSTASH(PL_curcop)) ? SVf_UTF8 : 0 );
                    }
                    prepare_SV_for_RV(sv);
                    SvRV_set(sv, MUTABLE_SV(gv));
@@ -190,55 +199,61 @@ PP(pp_rv2gv)
                    SvSETMAGIC(sv);
                    goto wasref;
                }
-               if (PL_op->op_flags & OPf_REF ||
-                   PL_op->op_private & HINT_STRICT_REFS)
-                   DIE(aTHX_ PL_no_usym, "a symbol");
+               if (PL_op->op_flags & OPf_REF || strict)
+                   return (SV *)Perl_die(aTHX_ PL_no_usym, "a symbol");
                if (ckWARN(WARN_UNINITIALIZED))
                    report_uninit(sv);
-               RETSETUNDEF;
+               return &PL_sv_undef;
            }
-           if ((PL_op->op_flags & OPf_SPECIAL) &&
-               !(PL_op->op_flags & OPf_MOD))
+           if (noinit)
            {
-               SV * const temp = MUTABLE_SV(gv_fetchsv(sv, 0, SVt_PVGV));
-               if (!temp
-                   && (!is_gv_magical_sv(sv,0)
-                       || !(sv = MUTABLE_SV(gv_fetchsv(sv, GV_ADD,
-                                                       SVt_PVGV))))) {
-                   RETSETUNDEF;
-               }
-               if (temp) sv = temp;
+               if (!(sv = MUTABLE_SV(gv_fetchsv_nomg(
+                          sv, GV_ADDMG, SVt_PVGV
+                  ))))
+                   return &PL_sv_undef;
            }
            else {
-               if (PL_op->op_private & HINT_STRICT_REFS)
-                   DIE(aTHX_ S_no_symref_sv, sv, (SvPOK(sv) && SvCUR(sv)>32 ? "..." : ""), "a symbol");
+               if (strict)
+                   return
+                    (SV *)Perl_die(aTHX_
+                           S_no_symref_sv,
+                           sv,
+                           (SvPOK(sv) && SvCUR(sv)>32 ? "..." : ""),
+                           "a symbol"
+                          );
                if ((PL_op->op_private & (OPpLVAL_INTRO|OPpDONT_INIT_GV))
                    == OPpDONT_INIT_GV) {
                    /* We are the target of a coderef assignment.  Return
                       the scalar unchanged, and let pp_sasssign deal with
                       things.  */
-                   RETURN;
-               }
-               {
-                   STRLEN len;
-                   const char * const nambeg = SvPV_nomg_const(sv, len);
-                   sv = MUTABLE_SV(
-                       gv_fetchpvn_flags(
-                           nambeg, len, GV_ADD | SvUTF8(sv), SVt_PVGV
-                       )
-                   );
+                   return sv;
                }
+               sv = MUTABLE_SV(gv_fetchsv_nomg(sv, GV_ADD, SVt_PVGV));
            }
            /* FAKE globs in the symbol table cause weird bugs (#77810) */
-           if (sv) SvFAKE_off(sv);
+           SvFAKE_off(sv);
        }
     }
-    if (sv && SvFAKE(sv)) {
+    if (SvFAKE(sv)) {
        SV *newsv = sv_newmortal();
        sv_setsv_flags(newsv, sv, 0);
        SvFAKE_off(newsv);
        sv = newsv;
     }
+    return sv;
+}
+
+PP(pp_rv2gv)
+{
+    dVAR; dSP; dTOPss;
+
+    sv = S_rv2gv(aTHX_
+          sv, PL_op->op_private & OPpDEREF,
+          PL_op->op_private & HINT_STRICT_REFS,
+          ((PL_op->op_flags & OPf_SPECIAL) && !(PL_op->op_flags & OPf_MOD))
+             || PL_op->op_type == OP_READLINE
+         );
+    SPAGAIN;
     if (PL_op->op_private & OPpLVAL_INTRO)
        save_gp(MUTABLE_GV(sv), !(PL_op->op_flags & OPf_SPECIAL));
     SETs(sv);
@@ -279,19 +294,14 @@ Perl_softref2xv(pTHX_ SV *const sv, const char *const what,
     if ((PL_op->op_flags & OPf_SPECIAL) &&
        !(PL_op->op_flags & OPf_MOD))
        {
-           gv = gv_fetchsv(sv, 0, type);
-           if (!gv
-               && (!is_gv_magical_sv(sv,0)
-                   || !(gv = gv_fetchsv(sv, GV_ADD, type))))
+           if (!(gv = gv_fetchsv_nomg(sv, GV_ADDMG, type)))
                {
                    **spp = &PL_sv_undef;
                    return NULL;
                }
        }
     else {
-       STRLEN len;
-       const char * const nambeg = SvPV_nomg_const(sv, len);
-       gv = gv_fetchpvn_flags(nambeg, len, GV_ADD | SvUTF8(sv), type);
+       gv = gv_fetchsv_nomg(sv, GV_ADD, type);
     }
     return gv;
 }
@@ -301,8 +311,7 @@ PP(pp_rv2sv)
     dVAR; dSP; dTOPss;
     GV *gv = NULL;
 
-    if (!(PL_op->op_private & OPpDEREFed))
-       SvGETMAGIC(sv);
+    SvGETMAGIC(sv);
     if (SvROK(sv)) {
        if (SvAMAGIC(sv)) {
            sv = amagic_deref_call(sv, to_sv_amg);
@@ -340,7 +349,7 @@ PP(pp_rv2sv)
                Perl_croak(aTHX_ "%s", PL_no_localize_ref);
        }
        else if (PL_op->op_private & OPpDEREF)
-           vivify_ref(sv, PL_op->op_private & OPpDEREF);
+           sv = vivify_ref(sv, PL_op->op_private & OPpDEREF);
     }
     SETs(sv);
     RETURN;
@@ -359,9 +368,7 @@ PP(pp_av2arylen)
        }
        SETs(*sv);
     } else {
-       SETs(sv_2mortal(newSViv(
-           AvFILL(MUTABLE_AV(av)) + CopARYBASE_get(PL_curcop)
-       )));
+       SETs(sv_2mortal(newSViv(AvFILL(MUTABLE_AV(av)))));
     }
     RETURN;
 }
@@ -386,7 +393,7 @@ PP(pp_pos)
                I32 i = mg->mg_len;
                if (DO_UTF8(sv))
                    sv_pos_b2u(sv, &i);
-               PUSHi(i + CopARYBASE_get(PL_curcop));
+               PUSHi(i);
                RETURN;
            }
        }
@@ -400,7 +407,7 @@ PP(pp_rv2cv)
     GV *gv;
     HV *stash_unused;
     const I32 flags = (PL_op->op_flags & OPf_SPECIAL)
-       ? 0
+       ? GV_ADDMG
        : ((PL_op->op_private & (OPpLVAL_INTRO|OPpMAY_RETURN_CONSTANT)) == OPpMAY_RETURN_CONSTANT)
            ? GV_ADD|GV_NOEXPAND
            : GV_ADD;
@@ -412,7 +419,7 @@ PP(pp_rv2cv)
        if (CvCLONE(cv))
            cv = MUTABLE_CV(sv_2mortal(MUTABLE_SV(cv_clone(cv))));
        if ((PL_op->op_private & OPpLVAL_INTRO)) {
-           if (gv && GvCV(gv) == cv && (gv = gv_autoload4(GvSTASH(gv), GvNAME(gv), GvNAMELEN(gv), FALSE)))
+           if (gv && GvCV(gv) == cv && (gv = gv_autoload_pvn(GvSTASH(gv), GvNAME(gv), GvNAMELEN(gv), GvNAMEUTF8(gv) ? SVf_UTF8 : 0)))
                cv = GvCV(gv);
            if (!CvLVALUE(cv))
                DIE(aTHX_ "Can't modify non-lvalue subroutine call");
@@ -450,7 +457,9 @@ PP(pp_prototype)
     }
     cv = sv_2cv(TOPs, &stash, &gv, 0);
     if (cv && SvPOK(cv))
-       ret = newSVpvn_flags(SvPVX_const(cv), SvCUR(cv), SVs_TEMP);
+       ret = newSVpvn_flags(
+           CvPROTO(cv), CvPROTOLEN(cv), SVs_TEMP | SvUTF8(cv)
+       );
   set:
     SETs(ret);
     RETURN;
@@ -530,7 +539,6 @@ S_refto(pTHX_ SV *sv)
 PP(pp_ref)
 {
     dVAR; dSP; dTARGET;
-    const char *pv;
     SV * const sv = POPs;
 
     if (sv)
@@ -539,8 +547,8 @@ PP(pp_ref)
     if (!sv || !SvROK(sv))
        RETPUSHNO;
 
-    pv = sv_reftype(SvRV(sv),TRUE);
-    PUSHp(pv, strlen(pv));
+    (void)sv_ref(TARG,SvRV(sv),TRUE);
+    PUSHTARG;
     RETURN;
 }
 
@@ -550,19 +558,21 @@ PP(pp_bless)
     HV *stash;
 
     if (MAXARG == 1)
+      curstash:
        stash = CopSTASH(PL_curcop);
     else {
        SV * const ssv = POPs;
        STRLEN len;
        const char *ptr;
 
-       if (ssv && !SvGMAGICAL(ssv) && !SvAMAGIC(ssv) && SvROK(ssv))
+       if (!ssv) goto curstash;
+       if (!SvGMAGICAL(ssv) && !SvAMAGIC(ssv) && SvROK(ssv))
            Perl_croak(aTHX_ "Attempt to bless into a reference");
        ptr = SvPV_const(ssv,len);
        if (len == 0)
            Perl_ck_warner(aTHX_ packWARN(WARN_MISC),
                           "Explicit blessing to '' (assuming package main)");
-       stash = gv_stashpvn(ptr, len, GV_ADD);
+       stash = gv_stashpvn(ptr, len, GV_ADD|SvUTF8(ssv));
     }
 
     (void)sv_bless(TOPs, stash);
@@ -574,7 +584,8 @@ PP(pp_gelem)
     dVAR; dSP;
 
     SV *sv = POPs;
-    const char * const elem = SvPV_nolen_const(sv);
+    STRLEN len;
+    const char * const elem = SvPV_const(sv, len);
     GV * const gv = MUTABLE_GV(POPs);
     SV * tmpRef = NULL;
 
@@ -584,48 +595,48 @@ PP(pp_gelem)
        const char * const second_letter = elem + 1;
        switch (*elem) {
        case 'A':
-           if (strEQ(second_letter, "RRAY"))
+           if (len == 5 && strEQ(second_letter, "RRAY"))
                tmpRef = MUTABLE_SV(GvAV(gv));
            break;
        case 'C':
-           if (strEQ(second_letter, "ODE"))
+           if (len == 4 && strEQ(second_letter, "ODE"))
                tmpRef = MUTABLE_SV(GvCVu(gv));
            break;
        case 'F':
-           if (strEQ(second_letter, "ILEHANDLE")) {
+           if (len == 10 && strEQ(second_letter, "ILEHANDLE")) {
                /* finally deprecated in 5.8.0 */
                deprecate("*glob{FILEHANDLE}");
                tmpRef = MUTABLE_SV(GvIOp(gv));
            }
            else
-               if (strEQ(second_letter, "ORMAT"))
+               if (len == 6 && strEQ(second_letter, "ORMAT"))
                    tmpRef = MUTABLE_SV(GvFORM(gv));
            break;
        case 'G':
-           if (strEQ(second_letter, "LOB"))
+           if (len == 4 && strEQ(second_letter, "LOB"))
                tmpRef = MUTABLE_SV(gv);
            break;
        case 'H':
-           if (strEQ(second_letter, "ASH"))
+           if (len == 4 && strEQ(second_letter, "ASH"))
                tmpRef = MUTABLE_SV(GvHV(gv));
            break;
        case 'I':
-           if (*second_letter == 'O' && !elem[2])
+           if (*second_letter == 'O' && !elem[2] && len == 2)
                tmpRef = MUTABLE_SV(GvIOp(gv));
            break;
        case 'N':
-           if (strEQ(second_letter, "AME"))
+           if (len == 4 && strEQ(second_letter, "AME"))
                sv = newSVhek(GvNAME_HEK(gv));
            break;
        case 'P':
-           if (strEQ(second_letter, "ACKAGE")) {
+           if (len == 7 && strEQ(second_letter, "ACKAGE")) {
                const HV * const stash = GvSTASH(gv);
                const HEK * const hek = stash ? HvNAME_HEK(stash) : NULL;
                sv = hek ? newSVhek(hek) : newSVpvs("__ANON__");
            }
            break;
        case 'S':
-           if (strEQ(second_letter, "CALAR"))
+           if (len == 6 && strEQ(second_letter, "CALAR"))
                tmpRef = GvSVn(gv);
            break;
        }
@@ -972,9 +983,11 @@ PP(pp_undef)
        break;
     case SVt_PVCV:
        if (cv_const_sv((const CV *)sv))
-           Perl_ck_warner(aTHX_ packWARN(WARN_MISC), "Constant subroutine %s undefined",
-                          CvANON((const CV *)sv) ? "(anonymous)"
-                          : GvENAME(CvGV((const CV *)sv)));
+           Perl_ck_warner(aTHX_ packWARN(WARN_MISC),
+                          "Constant subroutine %"SVf" undefined",
+                          SVfARG(CvANON((const CV *)sv)
+                             ? newSVpvs_flags("(anonymous)", SVs_TEMP)
+                             : sv_2mortal(newSVhek(GvENAME_HEK(CvGV((const CV *)sv))))));
        /* FALLTHROUGH */
     case SVt_PVFM:
        {
@@ -1041,68 +1054,33 @@ PP(pp_undef)
     RETPUSHUNDEF;
 }
 
-PP(pp_predec)
-{
-    dVAR; dSP;
-    if (SvTYPE(TOPs) >= SVt_PVAV || isGV_with_GP(TOPs))
-       Perl_croak_no_modify(aTHX);
-    if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
-        && SvIVX(TOPs) != IV_MIN)
-    {
-       SvIV_set(TOPs, SvIVX(TOPs) - 1);
-       SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
-    }
-    else
-       sv_dec(TOPs);
-    SvSETMAGIC(TOPs);
-    return NORMAL;
-}
-
 PP(pp_postinc)
 {
     dVAR; dSP; dTARGET;
-    if (SvTYPE(TOPs) >= SVt_PVAV || isGV_with_GP(TOPs))
+    const bool inc =
+       PL_op->op_type == OP_POSTINC || PL_op->op_type == OP_I_POSTINC;
+    if (SvTYPE(TOPs) >= SVt_PVAV || (isGV_with_GP(TOPs) && !SvFAKE(TOPs)))
        Perl_croak_no_modify(aTHX);
     if (SvROK(TOPs))
        TARG = sv_newmortal();
     sv_setsv(TARG, TOPs);
     if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
-        && SvIVX(TOPs) != IV_MAX)
+        && SvIVX(TOPs) != (inc ? IV_MAX : IV_MIN))
     {
-       SvIV_set(TOPs, SvIVX(TOPs) + 1);
+       SvIV_set(TOPs, SvIVX(TOPs) + (inc ? 1 : -1));
        SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
     }
-    else
+    else if (inc)
        sv_inc_nomg(TOPs);
+    else sv_dec_nomg(TOPs);
     SvSETMAGIC(TOPs);
     /* special case for undef: see thread at 2003-03/msg00536.html in archive */
-    if (!SvOK(TARG))
+    if (inc && !SvOK(TARG))
        sv_setiv(TARG, 0);
     SETs(TARG);
     return NORMAL;
 }
 
-PP(pp_postdec)
-{
-    dVAR; dSP; dTARGET;
-    if (SvTYPE(TOPs) >= SVt_PVAV || isGV_with_GP(TOPs))
-       Perl_croak_no_modify(aTHX);
-    if (SvROK(TOPs))
-       TARG = sv_newmortal();
-    sv_setsv(TARG, TOPs);
-    if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
-        && SvIVX(TOPs) != IV_MIN)
-    {
-       SvIV_set(TOPs, SvIVX(TOPs) - 1);
-       SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
-    }
-    else
-       sv_dec_nomg(TOPs);
-    SvSETMAGIC(TOPs);
-    SETs(TARG);
-    return NORMAL;
-}
-
 /* Ordinary operators. */
 
 PP(pp_pow)
@@ -2772,6 +2750,9 @@ PP(pp_rand)
     NV value;
     if (MAXARG < 1)
        value = 1.0;
+    else if (!TOPs) {
+       value = 1.0; (void)POPs;
+    }
     else
        value = POPn;
     if (value == 0.0)
@@ -2788,7 +2769,7 @@ PP(pp_rand)
 PP(pp_srand)
 {
     dVAR; dSP; dTARGET;
-    const UV anum = (MAXARG < 1) ? seed() : POPu;
+    const UV anum = (MAXARG < 1 || (!TOPs && !POPs)) ? seed() : POPu;
     (void)seedDrand01((Rand_seed_t)anum);
     PL_srand_called = TRUE;
     if (anum)
@@ -2990,24 +2971,28 @@ PP(pp_substr)
     IV     len_iv = 0;
     int    len_is_uv = 1;
     const I32 lvalue = PL_op->op_flags & OPf_MOD || LVRET;
+    const bool rvalue = (GIMME_V != G_VOID);
     const char *tmps;
-    const IV arybase = CopARYBASE_get(PL_curcop);
     SV *repl_sv = NULL;
     const char *repl = NULL;
     STRLEN repl_len;
-    const int num_args = PL_op->op_private & 7;
+    int num_args = PL_op->op_private & 7;
     bool repl_need_utf8_upgrade = FALSE;
     bool repl_is_utf8 = FALSE;
 
     if (num_args > 2) {
        if (num_args > 3) {
-           repl_sv = POPs;
+         if((repl_sv = POPs)) {
            repl = SvPV_const(repl_sv, repl_len);
-           repl_is_utf8 = DO_UTF8(repl_sv) && SvCUR(repl_sv);
+           repl_is_utf8 = DO_UTF8(repl_sv) && repl_len;
+         }
+         else num_args--;
        }
-       len_sv    = POPs;
-       len_iv    = SvIV(len_sv);
-       len_is_uv = SvIOK_UV(len_sv);
+       if ((len_sv = POPs)) {
+           len_iv    = SvIV(len_sv);
+           len_is_uv = SvIOK_UV(len_sv);
+       }
+       else num_args--;
     }
     pos_sv     = POPs;
     pos1_iv    = SvIV(pos_sv);
@@ -3033,32 +3018,12 @@ PP(pp_substr)
     else
        utf8_curlen = 0;
 
-    if ( (pos1_is_uv && arybase < 0) || (pos1_iv >= arybase) ) { /* pos >= $[ */
-       UV pos1_uv = pos1_iv-arybase;
-       /* Overflow can occur when $[ < 0 */
-       if (arybase < 0 && pos1_uv < (UV)pos1_iv)
-           goto bound_fail;
-       pos1_iv = pos1_uv;
-       pos1_is_uv = 1;
-    }
-    else if (pos1_is_uv ? (UV)pos1_iv > 0 : pos1_iv > 0) {
-       goto bound_fail;  /* $[=3; substr($_,2,...) */
-    }
-    else { /* pos < $[ */
-       if (pos1_iv == 0) { /* $[=1; substr($_,0,...) */
-           pos1_iv = curlen;
-           pos1_is_uv = 1;
-       } else {
-           if (curlen) {
-               pos1_is_uv = curlen-1 > ~(UV)pos1_iv;
-               pos1_iv += curlen;
-          }
-       }
-    }
-    if (pos1_is_uv || pos1_iv > 0) {
-       if ((UV)pos1_iv > curlen)
-           goto bound_fail;
+    if (!pos1_is_uv && pos1_iv < 0 && curlen) {
+       pos1_is_uv = curlen-1 > ~(UV)pos1_iv;
+       pos1_iv += curlen;
     }
+    if ((pos1_is_uv || pos1_iv > 0) && (UV)pos1_iv > curlen)
+       goto bound_fail;
 
     if (num_args > 2) {
        if (!len_is_uv && len_iv < 0) {
@@ -3135,16 +3100,18 @@ PP(pp_substr)
            RETURN;
        }
 
-       SvTAINTED_off(TARG);                    /* decontaminate */
-       SvUTF8_off(TARG);                       /* decontaminate */
-
        tmps += byte_pos;
-       sv_setpvn(TARG, tmps, byte_len);
+
+       if (rvalue) {
+           SvTAINTED_off(TARG);                        /* decontaminate */
+           SvUTF8_off(TARG);                   /* decontaminate */
+           sv_setpvn(TARG, tmps, byte_len);
 #ifdef USE_LOCALE_COLLATE
-       sv_unmagic(TARG, PERL_MAGIC_collxfrm);
+           sv_unmagic(TARG, PERL_MAGIC_collxfrm);
 #endif
-       if (utf8_curlen)
-           SvUTF8_on(TARG);
+           if (utf8_curlen)
+               SvUTF8_on(TARG);
+       }
 
        if (repl) {
            SV* repl_sv_copy = NULL;
@@ -3153,7 +3120,7 @@ PP(pp_substr)
                repl_sv_copy = newSVsv(repl_sv);
                sv_utf8_upgrade(repl_sv_copy);
                repl = SvPV_const(repl_sv_copy, repl_len);
-               repl_is_utf8 = DO_UTF8(repl_sv_copy) && SvCUR(sv);
+               repl_is_utf8 = DO_UTF8(repl_sv_copy) && repl_len;
            }
            if (!SvOK(sv))
                sv_setpvs(sv, "");
@@ -3164,8 +3131,10 @@ PP(pp_substr)
        }
     }
     SPAGAIN;
-    SvSETMAGIC(TARG);
-    PUSHs(TARG);
+    if (rvalue) {
+       SvSETMAGIC(TARG);
+       PUSHs(TARG);
+    }
     RETURN;
 
 bound_fail:
@@ -3215,16 +3184,13 @@ PP(pp_index)
     I32 retval;
     const char *big_p;
     const char *little_p;
-    const I32 arybase = CopARYBASE_get(PL_curcop);
     bool big_utf8;
     bool little_utf8;
     const bool is_index = PL_op->op_type == OP_INDEX;
+    const bool threeargs = MAXARG >= 3 && (TOPs || ((void)POPs,0));
 
-    if (MAXARG >= 3) {
-       /* arybase is in characters, like offset, so combine prior to the
-          UTF-8 to bytes calculation.  */
-       offset = POPi - arybase;
-    }
+    if (threeargs)
+       offset = POPi;
     little = POPs;
     big = POPs;
     big_p = SvPV_const(big, biglen);
@@ -3294,7 +3260,7 @@ PP(pp_index)
        little_p = SvPVX(little);
     }
 
-    if (MAXARG < 3)
+    if (!threeargs)
        offset = is_index ? 0 : biglen;
     else {
        if (big_utf8 && offset > 0)
@@ -3319,7 +3285,7 @@ PP(pp_index)
     }
     SvREFCNT_dec(temp);
  fail:
-    PUSHi(retval + arybase);
+    PUSHi(retval);
     RETURN;
 }
 
@@ -3464,63 +3430,15 @@ PP(pp_crypt)
 /* Generally UTF-8 and UTF-EBCDIC are indistinguishable at this level.  So 
  * most comments below say UTF-8, when in fact they mean UTF-EBCDIC as well */
 
-/* Below are several macros that generate code */
 /* Generates code to store a unicode codepoint c that is known to occupy
- * exactly two UTF-8 and UTF-EBCDIC bytes; it is stored into p and p+1. */
-#define STORE_UNI_TO_UTF8_TWO_BYTE(p, c)                                   \
-    STMT_START {                                                           \
-       *(p) = UTF8_TWO_BYTE_HI(c);                                         \
-       *((p)+1) = UTF8_TWO_BYTE_LO(c);                                     \
-    } STMT_END
-
-/* Like STORE_UNI_TO_UTF8_TWO_BYTE, but advances p to point to the next
- * available byte after the two bytes */
+ * exactly two UTF-8 and UTF-EBCDIC bytes; it is stored into p and p+1,
+ * and p is advanced to point to the next available byte after the two bytes */
 #define CAT_UNI_TO_UTF8_TWO_BYTE(p, c)                                     \
     STMT_START {                                                           \
        *(p)++ = UTF8_TWO_BYTE_HI(c);                                       \
        *((p)++) = UTF8_TWO_BYTE_LO(c);                                     \
     } STMT_END
 
-/* Generates code to store the upper case of latin1 character l which is known
- * to have its upper case be non-latin1 into the two bytes p and p+1.  There
- * are only two characters that fit this description, and this macro knows
- * about them, and that the upper case values fit into two UTF-8 or UTF-EBCDIC
- * bytes */
-#define STORE_NON_LATIN1_UC(p, l)                                          \
-STMT_START {                                                               \
-    if ((l) == LATIN_SMALL_LETTER_Y_WITH_DIAERESIS) {                      \
-       STORE_UNI_TO_UTF8_TWO_BYTE((p), LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS);  \
-    } else { /* Must be the following letter */                                                                    \
-       STORE_UNI_TO_UTF8_TWO_BYTE((p), GREEK_CAPITAL_LETTER_MU);           \
-    }                                                                      \
-} STMT_END
-
-/* Like STORE_NON_LATIN1_UC, but advances p to point to the next available byte
- * after the character stored */
-#define CAT_NON_LATIN1_UC(p, l)                                                    \
-STMT_START {                                                               \
-    if ((l) == LATIN_SMALL_LETTER_Y_WITH_DIAERESIS) {                      \
-       CAT_UNI_TO_UTF8_TWO_BYTE((p), LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS);    \
-    } else {                                                               \
-       CAT_UNI_TO_UTF8_TWO_BYTE((p), GREEK_CAPITAL_LETTER_MU);             \
-    }                                                                      \
-} STMT_END
-
-/* Generates code to add the two UTF-8 bytes (probably u) that are the upper
- * case of l into p and p+1.  u must be the result of toUPPER_LATIN1_MOD(l),
- * and must require two bytes to store it.  Advances p to point to the next
- * available position */
-#define CAT_TWO_BYTE_UNI_UPPER_MOD(p, l, u)                                \
-STMT_START {                                                               \
-    if ((u) != LATIN_SMALL_LETTER_Y_WITH_DIAERESIS) {                      \
-       CAT_UNI_TO_UTF8_TWO_BYTE((p), (u)); /* not special, just save it */ \
-    } else if (l == LATIN_SMALL_LETTER_SHARP_S) {                          \
-       *(p)++ = 'S'; *(p)++ = 'S'; /* upper case is 'SS' */                \
-    } else {/* else is one of the other two special cases */               \
-       CAT_NON_LATIN1_UC((p), (l));                                        \
-    }                                                                      \
-} STMT_END
-
 PP(pp_ucfirst)
 {
     /* Actually is both lcfirst() and ucfirst().  Only the first character
@@ -3568,107 +3486,22 @@ PP(pp_ucfirst)
 
     if (! slen) {   /* If empty */
        need = 1; /* still need a trailing NUL */
+       ulen = 0;
     }
     else if (DO_UTF8(source)) {        /* Is the source utf8? */
        doing_utf8 = TRUE;
+        ulen = UTF8SKIP(s);
+        if (op_type == OP_UCFIRST) toTITLE_utf8(s, tmpbuf, &tculen);
+        else toLOWER_utf8(s, tmpbuf, &tculen);
 
-/* TODO: This is #ifdefd out because it has hard-coded the standard mappings,
- * and doesn't allow for the user to specify their own.  When code is added to
- * detect if there is a user-defined mapping in force here, and if so to use
- * that, then the code below can be compiled.  The detection would be a good
- * thing anyway, as currently the user-defined mappings only work on utf8
- * strings, and thus depend on the chosen internal storage method, which is a
- * bad thing */
-#ifdef GO_AHEAD_AND_BREAK_USER_DEFINED_CASE_MAPPINGS
-       if (UTF8_IS_INVARIANT(*s)) {
-
-           /* An invariant source character is either ASCII or, in EBCDIC, an
-            * ASCII equivalent or a caseless C1 control.  In both these cases,
-            * the lower and upper cases of any character are also invariants
-            * (and title case is the same as upper case).  So it is safe to
-            * use the simple case change macros which avoid the overhead of
-            * the general functions.  Note that if perl were to be extended to
-            * do locale handling in UTF-8 strings, this wouldn't be true in,
-            * for example, Lithuanian or Turkic.  */
-           *tmpbuf = (op_type == OP_LCFIRST) ? toLOWER(*s) : toUPPER(*s);
-           tculen = ulen = 1;
-           need = slen + 1;
-       }
-       else if (UTF8_IS_DOWNGRADEABLE_START(*s)) {
-           U8 chr;
-
-           /* Similarly, if the source character isn't invariant but is in the
-            * latin1 range (or EBCDIC equivalent thereof), we have the case
-            * changes compiled into perl, and can avoid the overhead of the
-            * general functions.  In this range, the characters are stored as
-            * two UTF-8 bytes, and it so happens that any changed-case version
-            * is also two bytes (in both ASCIIish and EBCDIC machines). */
-           tculen = ulen = 2;
-           need = slen + 1;
-
-           /* Convert the two source bytes to a single Unicode code point
-            * value, change case and save for below */
-           chr = TWO_BYTE_UTF8_TO_UNI(*s, *(s+1));
-           if (op_type == OP_LCFIRST) {    /* lower casing is easy */
-               U8 lower = toLOWER_LATIN1(chr);
-               STORE_UNI_TO_UTF8_TWO_BYTE(tmpbuf, lower);
-           }
-           else {      /* ucfirst */
-               U8 upper = toUPPER_LATIN1_MOD(chr);
-
-               /* Most of the latin1 range characters are well-behaved.  Their
-                * title and upper cases are the same, and are also in the
-                * latin1 range.  The macro above returns their upper (hence
-                * title) case, and all that need be done is to save the result
-                * for below.  However, several characters are problematic, and
-                * have to be handled specially.  The MOD in the macro name
-                * above means that these tricky characters all get mapped to
-                * the single character LATIN_SMALL_LETTER_Y_WITH_DIAERESIS.
-                * This mapping saves some tests for the majority of the
-                * characters */
-
-               if (upper != LATIN_SMALL_LETTER_Y_WITH_DIAERESIS) {
-
-                   /* Not tricky.  Just save it. */
-                   STORE_UNI_TO_UTF8_TWO_BYTE(tmpbuf, upper);
-               }
-               else if (chr == LATIN_SMALL_LETTER_SHARP_S) {
-
-                   /* This one is tricky because it is two characters long,
-                    * though the UTF-8 is still two bytes, so the stored
-                    * length doesn't change */
-                   *tmpbuf = 'S';  /* The UTF-8 is 'Ss' */
-                   *(tmpbuf + 1) = 's';
-               }
-               else {
-
-                   /* The other two have their title and upper cases the same,
-                    * but are tricky because the changed-case characters
-                    * aren't in the latin1 range.  They, however, do fit into
-                    * two UTF-8 bytes */
-                   STORE_NON_LATIN1_UC(tmpbuf, chr);    
-               }
-           }
-       }
-       else {
-#endif /* end of dont want to break user-defined casing */
-
-           /* Here, can't short-cut the general case */
-
-           utf8_to_uvchr(s, &ulen);
-           if (op_type == OP_UCFIRST) toTITLE_utf8(s, tmpbuf, &tculen);
-           else toLOWER_utf8(s, tmpbuf, &tculen);
-
-           /* we can't do in-place if the length changes.  */
-           if (ulen != tculen) inplace = FALSE;
-           need = slen + 1 - ulen + tculen;
-#ifdef GO_AHEAD_AND_BREAK_USER_DEFINED_CASE_MAPPINGS
-       }
-#endif
+        /* we can't do in-place if the length changes.  */
+        if (ulen != tculen) inplace = FALSE;
+        need = slen + 1 - ulen + tculen;
     }
     else { /* Non-zero length, non-UTF-8,  Need to consider locale and if
            * latin1 is treated as caseless.  Note that a locale takes
            * precedence */ 
+       ulen = 1;       /* Original character is 1 byte */
        tculen = 1;     /* Most characters will require one byte, but this will
                         * need to be overridden for the tricky ones */
        need = slen + 1;
@@ -3691,44 +3524,42 @@ PP(pp_ucfirst)
                                         * native function does */
        }
        else { /* is ucfirst non-UTF-8, not in locale, and cased latin1 */
-           *tmpbuf = toUPPER_LATIN1_MOD(*s);
-
-           /* tmpbuf now has the correct title case for all latin1 characters
-            * except for the several ones that have tricky handling.  All
-            * of these are mapped by the MOD to the letter below. */
-           if (*tmpbuf == LATIN_SMALL_LETTER_Y_WITH_DIAERESIS) {
-
-               /* The length is going to change, with all three of these, so
-                * can't replace just the first character */
-               inplace = FALSE;
-
-               /* We use the original to distinguish between these tricky
-                * cases */
-               if (*s == LATIN_SMALL_LETTER_SHARP_S) {
-                   /* Two character title case 'Ss', but can remain non-UTF-8 */
-                   need = slen + 2;
-                   *tmpbuf = 'S';
-                   *(tmpbuf + 1) = 's';   /* Assert: length(tmpbuf) >= 2 */
-                   tculen = 2;
+           UV title_ord = _to_upper_title_latin1(*s, tmpbuf, &tculen, 's');
+           if (tculen > 1) {
+               assert(tculen == 2);
+
+                /* If the result is an upper Latin1-range character, it can
+                 * still be represented in one byte, which is its ordinal */
+               if (UTF8_IS_DOWNGRADEABLE_START(*tmpbuf)) {
+                   *tmpbuf = (U8) title_ord;
+                   tculen = 1;
                }
                else {
-
-                   /* The other two tricky ones have their title case outside
-                    * latin1.  It is the same as their upper case. */
-                   doing_utf8 = TRUE;
-                   STORE_NON_LATIN1_UC(tmpbuf, *s);
-
-                   /* The UTF-8 and UTF-EBCDIC lengths of both these characters
-                    * and their upper cases is 2. */
-                   tculen = ulen = 2;
-
-                   /* The entire result will have to be in UTF-8.  Assume worst
-                    * case sizing in conversion. (all latin1 characters occupy
-                    * at most two bytes in utf8) */
-                   convert_source_to_utf8 = TRUE;
-                   need = slen * 2 + 1;
+                    /* Otherwise it became more than one ASCII character (in
+                     * the case of LATIN_SMALL_LETTER_SHARP_S) or changed to
+                     * beyond Latin1, so the number of bytes changed, so can't
+                     * replace just the first character in place. */
+                   inplace = FALSE;
+
+                   /* If the result won't fit in a byte, the entire result will
+                    * have to be in UTF-8.  Assume worst case sizing in
+                    * conversion. (all latin1 characters occupy at most two bytes
+                    * in utf8) */
+                   if (title_ord > 255) {
+                       doing_utf8 = TRUE;
+                       convert_source_to_utf8 = TRUE;
+                       need = slen * 2 + 1;
+
+                        /* The (converted) UTF-8 and UTF-EBCDIC lengths of all
+                         * (both) characters whose title case is above 255 is
+                         * 2. */
+                       ulen = 2;
+                   }
+                    else { /* LATIN_SMALL_LETTER_SHARP_S expands by 1 byte */
+                       need = slen + 1 + 1;
+                   }
                }
-           } /* End of is one of the three special chars */
+           }
        } /* End of use Unicode (Latin1) semantics */
     } /* End of changing the case of the first character */
 
@@ -3912,70 +3743,47 @@ PP(pp_uc)
        bool in_iota_subscript = FALSE;
 
        while (s < send) {
+           STRLEN u;
+           STRLEN ulen;
+           UV uv;
            if (in_iota_subscript && ! is_utf8_mark(s)) {
+
                /* A non-mark.  Time to output the iota subscript */
 #define GREEK_CAPITAL_LETTER_IOTA 0x0399
 #define COMBINING_GREEK_YPOGEGRAMMENI 0x0345
 
                CAT_UNI_TO_UTF8_TWO_BYTE(d, GREEK_CAPITAL_LETTER_IOTA);
                in_iota_subscript = FALSE;
-           }
-
-
-/* See comments at the first instance in this file of this ifdef */
-#ifdef GO_AHEAD_AND_BREAK_USER_DEFINED_CASE_MAPPINGS
-
-           /* If the UTF-8 character is invariant, then it is in the range
-            * known by the standard macro; result is only one byte long */
-           if (UTF8_IS_INVARIANT(*s)) {
-               *d++ = toUPPER(*s);
-               s++;
-           }
-           else if (UTF8_IS_DOWNGRADEABLE_START(*s)) {
-
-               /* Likewise, if it fits in a byte, its case change is in our
-                * table */
-               U8 orig = TWO_BYTE_UTF8_TO_UNI(*s, *s++);
-               U8 upper = toUPPER_LATIN1_MOD(orig);
-               CAT_TWO_BYTE_UNI_UPPER_MOD(d, orig, upper);
-               s++;
-           }
-           else {
-#else
-           {
-#endif
-
-               /* Otherwise, need the general UTF-8 case.  Get the changed
-                * case value and copy it to the output buffer */
+            }
 
-               const STRLEN u = UTF8SKIP(s);
-               STRLEN ulen;
+            /* Then handle the current character.  Get the changed case value
+             * and copy it to the output buffer */
 
-               const UV uv = toUPPER_utf8(s, tmpbuf, &ulen);
-               if (uv == GREEK_CAPITAL_LETTER_IOTA
-                   && utf8_to_uvchr(s, 0) == COMBINING_GREEK_YPOGEGRAMMENI)
-               {
-                   in_iota_subscript = TRUE;
-               }
-               else {
-                   if (ulen > u && (SvLEN(dest) < (min += ulen - u))) {
-                       /* If the eventually required minimum size outgrows
-                        * the available space, we need to grow. */
-                       const UV o = d - (U8*)SvPVX_const(dest);
-
-                       /* If someone uppercases one million U+03B0s we
-                        * SvGROW() one million times.  Or we could try
-                        * guessing how much to allocate without allocating too
-                        * much.  Such is life.  See corresponding comment in
-                        * lc code for another option */
-                       SvGROW(dest, min);
-                       d = (U8*)SvPVX(dest) + o;
-                   }
-                   Copy(tmpbuf, d, ulen, U8);
-                   d += ulen;
-               }
-               s += u;
-           }
+            u = UTF8SKIP(s);
+            uv = toUPPER_utf8(s, tmpbuf, &ulen);
+            if (uv == GREEK_CAPITAL_LETTER_IOTA
+                && utf8_to_uvchr(s, 0) == COMBINING_GREEK_YPOGEGRAMMENI)
+            {
+                in_iota_subscript = TRUE;
+            }
+            else {
+                if (ulen > u && (SvLEN(dest) < (min += ulen - u))) {
+                    /* If the eventually required minimum size outgrows the
+                     * available space, we need to grow. */
+                    const UV o = d - (U8*)SvPVX_const(dest);
+
+                    /* If someone uppercases one million U+03B0s we SvGROW()
+                     * one million times.  Or we could try guessing how much to
+                     * allocate without allocating too much.  Such is life.
+                     * See corresponding comment in lc code for another option
+                     * */
+                    SvGROW(dest, min);
+                    d = (U8*)SvPVX(dest) + o;
+                }
+                Copy(tmpbuf, d, ulen, U8);
+                d += ulen;
+            }
+            s += u;
        }
        if (in_iota_subscript) {
            CAT_UNI_TO_UTF8_TWO_BYTE(d, GREEK_CAPITAL_LETTER_IOTA);
@@ -4005,7 +3813,7 @@ PP(pp_uc)
            else {
                for (; s < send; d++, s++) {
                    *d = toUPPER_LATIN1_MOD(*s);
-                   if (*d != LATIN_SMALL_LETTER_Y_WITH_DIAERESIS) continue;
+                   if (LIKELY(*d != LATIN_SMALL_LETTER_Y_WITH_DIAERESIS)) continue;
 
                    /* The mainstream case is the tight loop above.  To avoid
                     * extra tests in that, all three characters that require
@@ -4066,23 +3874,13 @@ PP(pp_uc)
                                                (send -s) * 2 + 1);
                    d = (U8*)SvPVX(dest) + len;
 
-                   /* And append the current character's upper case in UTF-8 */
-                   CAT_NON_LATIN1_UC(d, *s);
-
                    /* Now process the remainder of the source, converting to
                     * upper and UTF-8.  If a resulting byte is invariant in
                     * UTF-8, output it as-is, otherwise convert to UTF-8 and
                     * append it to the output. */
-
-                   s++;
                    for (; s < send; s++) {
-                       U8 upper = toUPPER_LATIN1_MOD(*s);
-                       if UTF8_IS_INVARIANT(upper) {
-                           *d++ = upper;
-                       }
-                       else {
-                           CAT_TWO_BYTE_UNI_UPPER_MOD(d, *s, upper);
-                       }
+                       (void) _to_upper_title_latin1(*s, d, &len, 'S');
+                       d += len;
                    }
 
                    /* Here have processed the whole source; no need to continue
@@ -4163,133 +3961,35 @@ PP(pp_lc)
        U8 tmpbuf[UTF8_MAXBYTES_CASE+1];
 
        while (s < send) {
-/* See comments at the first instance in this file of this ifdef */
-#ifdef GO_AHEAD_AND_BREAK_USER_DEFINED_CASE_MAPPINGS
-           if (UTF8_IS_INVARIANT(*s)) {
+           const STRLEN u = UTF8SKIP(s);
+           STRLEN ulen;
 
-               /* Invariant characters use the standard mappings compiled in.
-                */
-               *d++ = toLOWER(*s);
-               s++;
-           }
-           else if (UTF8_IS_DOWNGRADEABLE_START(*s)) {
+           toLOWER_utf8(s, tmpbuf, &ulen);
 
-               /* As do the ones in the Latin1 range */
-               U8 lower = toLOWER_LATIN1(TWO_BYTE_UTF8_TO_UNI(*s, *s++));
-               CAT_UNI_TO_UTF8_TWO_BYTE(d, lower);
-               s++;
-           }
-           else {
-#endif
-               /* Here, is utf8 not in Latin-1 range, have to go out and get
-                * the mappings from the tables. */
+           /* Here is where we would do context-sensitive actions.  See the
+            * commit message for this comment for why there isn't any */
 
-               const STRLEN u = UTF8SKIP(s);
-               STRLEN ulen;
+           if (ulen > u && (SvLEN(dest) < (min += ulen - u))) {
 
-#ifndef CONTEXT_DEPENDENT_CASING
-               toLOWER_utf8(s, tmpbuf, &ulen);
-#else
-/* This is ifdefd out because it needs more work and thought.  It isn't clear
- * that we should do it.
- * A minor objection is that this is based on a hard-coded rule from the
- *  Unicode standard, and may change, but this is not very likely at all.
- *  mktables should check and warn if it does.
- * More importantly, if the sigma occurs at the end of the string, we don't
- * have enough context to know whether it is part of a larger string or going
- * to be or not.  It may be that we are passed a subset of the context, via
- * a \U...\E, for example, and we could conceivably know the larger context if
- * code were changed to pass that in.  But, if the string passed in is an
- * intermediate result, and the user concatenates two strings together
- * after we have made a final sigma, that would be wrong.  If the final sigma
- * occurs in the middle of the string we are working on, then we know that it
- * should be a final sigma, but otherwise we can't be sure. */
-
-               const UV uv = toLOWER_utf8(s, tmpbuf, &ulen);
-
-               /* If the lower case is a small sigma, it may be that we need
-                * to change it to a final sigma.  This happens at the end of 
-                * a word that contains more than just this character, and only
-                * when we started with a capital sigma. */
-               if (uv == UNICODE_GREEK_SMALL_LETTER_SIGMA &&
-                   s > send - len &&   /* Makes sure not the first letter */
-                   utf8_to_uvchr(s, 0) == UNICODE_GREEK_CAPITAL_LETTER_SIGMA
-               ) {
-
-                   /* We use the algorithm in:
-                    * http://www.unicode.org/versions/Unicode5.0.0/ch03.pdf (C
-                    * is a CAPITAL SIGMA): If C is preceded by a sequence
-                    * consisting of a cased letter and a case-ignorable
-                    * sequence, and C is not followed by a sequence consisting
-                    * of a case ignorable sequence and then a cased letter,
-                    * then when lowercasing C, C becomes a final sigma */
-
-                   /* To determine if this is the end of a word, need to peek
-                    * ahead.  Look at the next character */
-                   const U8 *peek = s + u;
-
-                   /* Skip any case ignorable characters */
-                   while (peek < send && is_utf8_case_ignorable(peek)) {
-                       peek += UTF8SKIP(peek);
-                   }
+               /* If the eventually required minimum size outgrows the
+                * available space, we need to grow. */
+               const UV o = d - (U8*)SvPVX_const(dest);
 
-                   /* If we reached the end of the string without finding any
-                    * non-case ignorable characters, or if the next such one
-                    * is not-cased, then we have met the conditions for it
-                    * being a final sigma with regards to peek ahead, and so
-                    * must do peek behind for the remaining conditions. (We
-                    * know there is stuff behind to look at since we tested
-                    * above that this isn't the first letter) */
-                   if (peek >= send || ! is_utf8_cased(peek)) {
-                       peek = utf8_hop(s, -1);
-
-                       /* Here are at the beginning of the first character
-                        * before the original upper case sigma.  Keep backing
-                        * up, skipping any case ignorable characters */
-                       while (is_utf8_case_ignorable(peek)) {
-                           peek = utf8_hop(peek, -1);
-                       }
-
-                       /* Here peek points to the first byte of the closest
-                        * non-case-ignorable character before the capital
-                        * sigma.  If it is cased, then by the Unicode
-                        * algorithm, we should use a small final sigma instead
-                        * of what we have */
-                       if (is_utf8_cased(peek)) {
-                           STORE_UNI_TO_UTF8_TWO_BYTE(tmpbuf,
-                                       UNICODE_GREEK_SMALL_LETTER_FINAL_SIGMA);
-                       }
-                   }
-               }
-               else {  /* Not a context sensitive mapping */
-#endif /* End of commented out context sensitive */
-                   if (ulen > u && (SvLEN(dest) < (min += ulen - u))) {
-
-                       /* If the eventually required minimum size outgrows
-                        * the available space, we need to grow. */
-                       const UV o = d - (U8*)SvPVX_const(dest);
-
-                       /* If someone lowercases one million U+0130s we
-                        * SvGROW() one million times.  Or we could try
-                        * guessing how much to allocate without allocating too
-                        * much.  Such is life.  Another option would be to
-                        * grow an extra byte or two more each time we need to
-                        * grow, which would cut down the million to 500K, with
-                        * little waste */
-                       SvGROW(dest, min);
-                       d = (U8*)SvPVX(dest) + o;
-                   }
-#ifdef CONTEXT_DEPENDENT_CASING
-               }
-#endif
-               /* Copy the newly lowercased letter to the output buffer we're
-                * building */
-               Copy(tmpbuf, d, ulen, U8);
-               d += ulen;
-               s += u;
-#ifdef GO_AHEAD_AND_BREAK_USER_DEFINED_CASE_MAPPINGS
+               /* If someone lowercases one million U+0130s we SvGROW() one
+                * million times.  Or we could try guessing how much to
+                * allocate without allocating too much.  Such is life.
+                * Another option would be to grow an extra byte or two more
+                * each time we need to grow, which would cut down the million
+                * to 500K, with little waste */
+               SvGROW(dest, min);
+               d = (U8*)SvPVX(dest) + o;
            }
-#endif
+
+           /* Copy the newly lowercased letter to the output buffer we're
+            * building */
+           Copy(tmpbuf, d, ulen, U8);
+           d += ulen;
+           s += u;
        }   /* End of looping through the source string */
        SvUTF8_on(dest);
        *d = '\0';
@@ -4387,7 +4087,6 @@ PP(pp_aslice)
     register const I32 lval = (PL_op->op_flags & OPf_MOD || LVRET);
 
     if (SvTYPE(av) == SVt_PVAV) {
-       const I32 arybase = CopARYBASE_get(PL_curcop);
        const bool localizing = PL_op->op_private & OPpLVAL_INTRO;
        bool can_preserve = FALSE;
 
@@ -4415,8 +4114,6 @@ PP(pp_aslice)
            I32 elem = SvIV(*MARK);
            bool preeminent = TRUE;
 
-           if (elem > 0)
-               elem -= arybase;
            if (localizing && can_preserve) {
                /* If we can determine whether the element exist,
                 * Try to preserve the existenceness of a tied array
@@ -4502,7 +4199,7 @@ PP(pp_aeach)
     }
 
     EXTEND(SP, 2);
-    mPUSHi(CopARYBASE_get(PL_curcop) + current);
+    mPUSHi(current);
     if (gimme == G_ARRAY) {
        SV **const element = av_fetch(array, current, 0);
         PUSHs(element ? *element : &PL_sv_undef);
@@ -4525,13 +4222,12 @@ PP(pp_akeys)
     }
     else if (gimme == G_ARRAY) {
         IV n = Perl_av_len(aTHX_ array);
-        IV i = CopARYBASE_get(PL_curcop);
+        IV i;
 
         EXTEND(SP, n + 1);
 
        if (PL_op->op_type == OP_AKEYS || PL_op->op_type == OP_RKEYS) {
-           n += i;
-           for (;  i <= n;  i++) {
+           for (i = 0;  i <= n;  i++) {
                mPUSHi(i);
            }
        }
@@ -4937,7 +4633,6 @@ PP(pp_lslice)
     SV ** const lastlelem = PL_stack_base + POPMARK;
     SV ** const firstlelem = PL_stack_base + POPMARK + 1;
     register SV ** const firstrelem = lastlelem + 1;
-    const I32 arybase = CopARYBASE_get(PL_curcop);
     I32 is_something_there = FALSE;
 
     register const I32 max = lastrelem - lastlelem;
@@ -4947,8 +4642,6 @@ PP(pp_lslice)
        I32 ix = SvIV(*lastlelem);
        if (ix < 0)
            ix += max;
-       else
-           ix -= arybase;
        if (ix < 0 || ix >= max)
            *firstlelem = &PL_sv_undef;
        else
@@ -4966,8 +4659,6 @@ PP(pp_lslice)
        I32 ix = SvIV(*lelem);
        if (ix < 0)
            ix += max;
-       else
-           ix -= arybase;
        if (ix < 0 || ix >= max)
            *lelem = &PL_sv_undef;
        else {
@@ -5071,8 +4762,6 @@ PP(pp_splice)
        offset = i = SvIV(*MARK);
        if (offset < 0)
            offset += AvFILLp(ary) + 1;
-       else
-           offset -= CopARYBASE_get(PL_curcop);
        if (offset < 0)
            DIE(aTHX_ PL_no_aelem, i);
        if (++MARK < SP) {
@@ -5968,14 +5657,22 @@ PP(pp_coreargs)
 {
     dSP;
     int opnum = SvIOK(cSVOP_sv) ? (int)SvUV(cSVOP_sv) : 0;
+    int defgv = PL_opargs[opnum] & OA_DEFGV, whicharg = 0;
     AV * const at_ = GvAV(PL_defgv);
+    SV **svp = AvARRAY(at_);
     I32 minargs = 0, maxargs = 0, numargs = AvFILLp(at_)+1;
     I32 oa = opnum ? PL_opargs[opnum] >> OASHIFT : 0;
+    bool seen_question = 0;
     const char *err = NULL;
+    const bool pushmark = PL_op->op_private & OPpCOREARGS_PUSHMARK;
 
-    /* Count how many args there are. */
+    /* Count how many args there are first, to get some idea how far to
+       extend the stack. */
     while (oa) {
+       if ((oa & 7) == OA_LIST) { maxargs = I32_MAX; break; }
        maxargs++;
+       if (oa & OA_OPTIONAL) seen_question = 1;
+       if (!seen_question) minargs++;
        oa >>= 4;
     }
 
@@ -5991,10 +5688,107 @@ PP(pp_coreargs)
     /* Reset the stack pointer.  Without this, we end up returning our own
        arguments in list context, in addition to the values we are supposed
        to return.  nextstate usually does this on sub entry, but we need
-       to run the next op with the callers hints, so we cannot have a
+       to run the next op with the caller's hints, so we cannot have a
        nextstate. */
     SP = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
 
+    if(!maxargs) RETURN;
+
+    /* We do this here, rather than with a separate pushmark op, as it has
+       to come in between two things this function does (stack reset and
+       arg pushing).  This seems the easiest way to do it. */
+    if (pushmark) {
+       PUTBACK;
+       (void)Perl_pp_pushmark(aTHX);
+    }
+
+    EXTEND(SP, maxargs == I32_MAX ? numargs : maxargs);
+    PUTBACK; /* The code below can die in various places. */
+
+    oa = PL_opargs[opnum] >> OASHIFT;
+    for (; oa&&(numargs||!pushmark); (void)(numargs&&(++svp,--numargs))) {
+       whicharg++;
+       switch (oa & 7) {
+       case OA_SCALAR:
+           if (!numargs && defgv && whicharg == minargs + 1) {
+               PERL_SI * const oldsi = PL_curstackinfo;
+               I32 const oldcxix = oldsi->si_cxix;
+               CV *caller;
+               if (oldcxix) oldsi->si_cxix--;
+               else PL_curstackinfo = oldsi->si_prev;
+               caller = find_runcv(NULL);
+               PL_curstackinfo = oldsi;
+               oldsi->si_cxix = oldcxix;
+               PUSHs(find_rundefsv2(
+                   caller,cxstack[cxstack_ix].blk_oldcop->cop_seq
+               ));
+           }
+           else PUSHs(numargs ? svp && *svp ? *svp : &PL_sv_undef : NULL);
+           break;
+       case OA_LIST:
+           while (numargs--) {
+               PUSHs(svp && *svp ? *svp : &PL_sv_undef);
+               svp++;
+           }
+           RETURN;
+       case OA_HVREF:
+           if (!svp || !*svp || !SvROK(*svp)
+            || SvTYPE(SvRV(*svp)) != SVt_PVHV)
+               DIE(aTHX_
+               /* diag_listed_as: Type of arg %d to &CORE::%s must be %s*/
+                "Type of arg %d to &CORE::%s must be hash reference",
+                 whicharg, OP_DESC(PL_op->op_next)
+               );
+           PUSHs(SvRV(*svp));
+           break;
+       case OA_FILEREF:
+           if (!numargs) PUSHs(NULL);
+           else if(svp && *svp && SvROK(*svp) && isGV_with_GP(SvRV(*svp)))
+               /* no magic here, as the prototype will have added an extra
+                  refgen and we just want what was there before that */
+               PUSHs(SvRV(*svp));
+           else {
+               const bool constr = PL_op->op_private & whicharg;
+               PUSHs(S_rv2gv(aTHX_
+                   svp && *svp ? *svp : &PL_sv_undef,
+                   constr, CopHINTS_get(PL_curcop) & HINT_STRICT_REFS,
+                   !constr
+               ));
+           }
+           break;
+       case OA_SCALARREF:
+         {
+           const bool wantscalar =
+               PL_op->op_private & OPpCOREARGS_SCALARMOD;
+           if (!svp || !*svp || !SvROK(*svp)
+               /* We have to permit globrefs even for the \$ proto, as
+                  *foo is indistinguishable from ${\*foo}, and the proto-
+                  type permits the latter. */
+            || SvTYPE(SvRV(*svp)) > (
+                    wantscalar       ? SVt_PVLV
+                  : opnum == OP_LOCK ? SVt_PVCV
+                  :                    SVt_PVHV
+               )
+              )
+               DIE(aTHX_
+               /* diag_listed_as: Type of arg %d to &CORE::%s must be %s*/
+                "Type of arg %d to &CORE::%s must be %s",
+                 whicharg, OP_DESC(PL_op->op_next),
+                 wantscalar
+                   ? "scalar reference"
+                   : opnum == OP_LOCK
+                      ? "reference to one of [$@%&*]"
+                      : "reference to one of [$@%*]"
+               );
+           PUSHs(SvRV(*svp));
+           break;
+         }
+       default:
+           DIE(aTHX_ "panic: unknown OA_*: %x", (unsigned)(oa&7));
+       }
+       oa = oa >> 4;
+    }
+
     RETURN;
 }