This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perldelta entries for op_class() and op_dump()
[perl5.git] / gv.c
diff --git a/gv.c b/gv.c
index d52c5c3..ae800c9 100644 (file)
--- a/gv.c
+++ b/gv.c
@@ -21,7 +21,6 @@
 
 /*
 =head1 GV Functions
-
 A GV is a structure which corresponds to to a Perl typeglob, ie *foo.
 It is a structure that holds a pointer to a scalar, an array, a hash etc,
 corresponding to $foo, @foo, %foo.
@@ -35,12 +34,12 @@ Perl stores its global variables.
 #include "EXTERN.h"
 #define PERL_IN_GV_C
 #include "perl.h"
-#include "overload.c"
+#include "overload.inc"
 #include "keywords.h"
 #include "feature.h"
 
 static const char S_autoload[] = "AUTOLOAD";
-static const STRLEN S_autolen = sizeof(S_autoload)-1;
+#define S_autolen (sizeof("AUTOLOAD")-1)
 
 GV *
 Perl_gv_add_by_type(pTHX_ GV *gv, svtype type)
@@ -85,7 +84,7 @@ Perl_gv_add_by_type(pTHX_ GV *gv, svtype type)
     {
        *where = newSV_type(type);
            if (type == SVt_PVAV && GvNAMELEN(gv) == 3
-            && strnEQ(GvNAME(gv), "ISA", 3))
+            && strEQs(GvNAME(gv), "ISA"))
            sv_magic(*where, (SV *)gv, PERL_MAGIC_isa, NULL, 0);
     }
     return gv;
@@ -102,7 +101,6 @@ GV *
 Perl_gv_fetchfile_flags(pTHX_ const char *const name, const STRLEN namelen,
                        const U32 flags)
 {
-    dVAR;
     char smallbuf[128];
     char *tmpbuf;
     const STRLEN tmplen = namelen + 2;
@@ -131,7 +129,7 @@ Perl_gv_fetchfile_flags(pTHX_ const char *const name, const STRLEN namelen,
        sv_setpvn(GvSV(gv), name, namelen);
 #endif
     }
-    if ((PERLDB_LINE || PERLDB_SAVESRC) && !GvAV(gv))
+    if (PERLDB_LINE_OR_SAVESRC && !GvAV(gv))
            hv_magic(GvHVn(gv), GvAVn(gv), PERL_MAGIC_dbfile);
     if (tmpbuf != smallbuf)
        Safefree(tmpbuf);
@@ -144,7 +142,7 @@ Perl_gv_fetchfile_flags(pTHX_ const char *const name, const STRLEN namelen,
 If C<gv> is a typeglob whose subroutine entry is a constant sub eligible for
 inlining, or C<gv> is a placeholder reference that would be promoted to such
 a typeglob, then returns the value returned by the sub.  Otherwise, returns
-NULL.
+C<NULL>.
 
 =cut
 */
@@ -153,10 +151,11 @@ SV *
 Perl_gv_const_sv(pTHX_ GV *gv)
 {
     PERL_ARGS_ASSERT_GV_CONST_SV;
+    PERL_UNUSED_CONTEXT;
 
     if (SvTYPE(gv) == SVt_PVGV)
        return cv_const_sv(GvCVu(gv));
-    return SvROK(gv) && SvTYPE(SvRV(gv)) != SVt_PVAV ? SvRV(gv) : NULL;
+    return SvROK(gv) && SvTYPE(SvRV(gv)) != SVt_PVAV && SvTYPE(SvRV(gv)) != SVt_PVCV ? SvRV(gv) : NULL;
 }
 
 GP *
@@ -217,7 +216,7 @@ Perl_newGP(pTHX_ GV *const gv)
 void
 Perl_cvgv_set(pTHX_ CV* cv, GV* gv)
 {
-    GV * const oldgv = CvGV(cv);
+    GV * const oldgv = CvNAMED(cv) ? NULL : SvANY(cv)->xcv_gv_u.xcv_gv;
     HEK *hek;
     PERL_ARGS_ASSERT_CVGV_SET;
 
@@ -233,8 +232,12 @@ Perl_cvgv_set(pTHX_ CV* cv, GV* gv)
            sv_del_backref(MUTABLE_SV(oldgv), MUTABLE_SV(cv));
        }
     }
-    else if ((hek = CvNAME_HEK(cv))) unshare_hek(hek);
+    else if ((hek = CvNAME_HEK(cv))) {
+       unshare_hek(hek);
+       CvLEXICAL_off(cv);
+    }
 
+    CvNAMED_off(cv);
     SvANY(cv)->xcv_gv_u.xcv_gv = gv;
     assert(!CvCVGV_RC(cv));
 
@@ -249,6 +252,37 @@ Perl_cvgv_set(pTHX_ CV* cv, GV* gv)
     }
 }
 
+/* Convert CvSTASH + CvNAME_HEK into a GV.  Conceptually, all subs have a
+   GV, but for efficiency that GV may not in fact exist.  This function,
+   called by CvGV, reifies it. */
+
+GV *
+Perl_cvgv_from_hek(pTHX_ CV *cv)
+{
+    GV *gv;
+    SV **svp;
+    PERL_ARGS_ASSERT_CVGV_FROM_HEK;
+    assert(SvTYPE(cv) == SVt_PVCV);
+    if (!CvSTASH(cv)) return NULL;
+    ASSUME(CvNAME_HEK(cv));
+    svp = hv_fetchhek(CvSTASH(cv), CvNAME_HEK(cv), 0);
+    gv = MUTABLE_GV(svp && *svp ? *svp : newSV(0));
+    if (!isGV(gv))
+       gv_init_pvn(gv, CvSTASH(cv), HEK_KEY(CvNAME_HEK(cv)),
+               HEK_LEN(CvNAME_HEK(cv)),
+               SVf_UTF8 * !!HEK_UTF8(CvNAME_HEK(cv)));
+    if (!CvNAMED(cv)) { /* gv_init took care of it */
+       assert (SvANY(cv)->xcv_gv_u.xcv_gv == gv);
+       return gv;
+    }
+    unshare_hek(CvNAME_HEK(cv));
+    CvNAMED_off(cv);
+    SvANY(cv)->xcv_gv_u.xcv_gv = gv;
+    if (svp && *svp) SvREFCNT_inc_simple_void_NN(gv);
+    CvCVGV_RC_on(cv);
+    return gv;
+}
+
 /* Assign CvSTASH(cv) = st, handling weak references. */
 
 void
@@ -270,8 +304,8 @@ Perl_cvstash_set(pTHX_ CV *cv, HV *st)
 
 Converts a scalar into a typeglob.  This is an incoercible typeglob;
 assigning a reference to it will assign to one of its slots, instead of
-overwriting it as happens with typeglobs created by SvSetSV.  Converting
-any scalar that is SvOK() may produce unpredictable results and is reserved
+overwriting it as happens with typeglobs created by C<SvSetSV>.  Converting
+any scalar that is C<SvOK()> may produce unpredictable results and is reserved
 for perl's internal use.
 
 C<gv> is the scalar to be converted.
@@ -284,25 +318,25 @@ stash element, it is the caller's responsibility to ensure that the name
 passed to this function matches the name of the element.  If it does not
 match, perl's internal bookkeeping will get out of sync.
 
-C<flags> can be set to SVf_UTF8 if C<name> is a UTF8 string, or
+C<flags> can be set to C<SVf_UTF8> if C<name> is a UTF-8 string, or
 the return value of SvUTF8(sv).  It can also take the
-GV_ADDMULTI flag, which means to pretend that the GV has been
+C<GV_ADDMULTI> flag, which means to pretend that the GV has been
 seen before (i.e., suppress "Used once" warnings).
 
 =for apidoc gv_init
 
-The old form of gv_init_pvn().  It does not work with UTF8 strings, as it
+The old form of C<gv_init_pvn()>.  It does not work with UTF-8 strings, as it
 has no flags parameter.  If the C<multi> parameter is set, the
-GV_ADDMULTI flag will be passed to gv_init_pvn().
+C<GV_ADDMULTI> flag will be passed to C<gv_init_pvn()>.
 
 =for apidoc gv_init_pv
 
-Same as gv_init_pvn(), but takes a nul-terminated string for the name
+Same as C<gv_init_pvn()>, but takes a nul-terminated string for the name
 instead of separate char * and length parameters.
 
 =for apidoc gv_init_sv
 
-Same as gv_init_pvn(), but takes an SV * for the name instead of separate
+Same as C<gv_init_pvn()>, but takes an SV * for the name instead of separate
 char * and length parameters.  C<flags> is currently unused.
 
 =cut
@@ -330,7 +364,6 @@ Perl_gv_init_pv(pTHX_ GV *gv, HV *stash, const char *name, U32 flags)
 void
 Perl_gv_init_pvn(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len, U32 flags)
 {
-    dVAR;
     const U32 old_type = SvTYPE(gv);
     const bool doproto = old_type > SVt_NULL;
     char * const proto = (doproto && SvPOK(gv))
@@ -345,15 +378,15 @@ Perl_gv_init_pvn(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len, U32 flag
     assert (!(proto && has_constant));
 
     if (has_constant) {
-       /* The constant has to be a simple scalar type.  */
+       /* The constant has to be a scalar, array or subroutine.  */
        switch (SvTYPE(has_constant)) {
        case SVt_PVHV:
-       case SVt_PVCV:
        case SVt_PVFM:
        case SVt_PVIO:
             Perl_croak(aTHX_ "Cannot convert a reference to %s to typeglob",
                       sv_reftype(has_constant, 0));
             break;
+
        default: NOOP;
        }
        SvRV_set(gv, NULL);
@@ -384,7 +417,21 @@ Perl_gv_init_pvn(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len, U32 flag
     gv_name_set(gv, name, len, GV_ADD | ( flags & SVf_UTF8 ? SVf_UTF8 : 0 ));
     if (flags & GV_ADDMULTI || doproto)        /* doproto means it */
        GvMULTI_on(gv);                 /* _was_ mentioned */
-    if (doproto) {
+    if (has_constant && SvTYPE(has_constant) == SVt_PVCV) {
+       /* Not actually a constant.  Just a regular sub.  */
+       CV * const cv = (CV *)has_constant;
+       GvCV_set(gv,cv);
+       if (CvSTASH(cv) == stash && (
+              CvNAME_HEK(cv) == GvNAME_HEK(gv)
+           || (  HEK_LEN(CvNAME_HEK(cv)) == HEK_LEN(GvNAME_HEK(gv))
+              && HEK_FLAGS(CvNAME_HEK(cv)) != HEK_FLAGS(GvNAME_HEK(gv))
+              && HEK_UTF8(CvNAME_HEK(cv)) == HEK_UTF8(GvNAME_HEK(gv))
+              && memEQ(HEK_KEY(CvNAME_HEK(cv)), GvNAME(gv), GvNAMELEN(gv))
+              )
+          ))
+           CvGV_set(cv,gv);
+    }
+    else if (doproto) {
        CV *cv;
        if (has_constant) {
            /* newCONSTSUB takes ownership of the reference from us.  */
@@ -484,18 +531,12 @@ S_maybe_add_coresub(pTHX_ HV * const stash, GV *gv,
        return NULL;
     case KEY_chdir:
     case KEY_chomp: case KEY_chop: case KEY_defined: case KEY_delete:
-    case KEY_each : case KEY_eof : case KEY_exec   : case KEY_exists:
-    case KEY_keys:
+    case KEY_eof  : case KEY_exec: case KEY_exists :
     case KEY_lstat:
-    case KEY_pop:
-    case KEY_push:
-    case KEY_shift:
-    case KEY_splice: case KEY_split:
+    case KEY_split:
     case KEY_stat:
     case KEY_system:
     case KEY_truncate: case KEY_unlink:
-    case KEY_unshift:
-    case KEY_values:
        ampable = FALSE;
     }
     if (!gv) {
@@ -522,10 +563,13 @@ S_maybe_add_coresub(pTHX_ HV * const stash, GV *gv,
        GvCVGEN(gv) = 0;
        CvISXSUB_on(cv);
        CvXSUB(cv) = core_xsub;
+       PoisonPADLIST(cv);
     }
     CvGV_set(cv, gv); /* This stops new ATTRSUB from setting CvFILE
                          from PL_curcop. */
-    (void)gv_fetchfile(file);
+    /* XSUBs can't be perl lang/perl5db.pl debugged
+    if (PERLDB_LINE_OR_SAVESRC)
+        (void)gv_fetchfile(file); */
     CvFILE(cv) = (char *)file;
     /* XXX This is inefficient, as doing things this order causes
            a prototype check in newATTRSUB.  But we have to do
@@ -554,7 +598,7 @@ S_maybe_add_coresub(pTHX_ HV * const stash, GV *gv,
                )) != NULL) {
             assert(GvCV(gv) == orig_cv);
             if (opnum != OP_VEC && opnum != OP_SUBSTR && opnum != OP_POS
-                && opnum != OP_UNDEF)
+                && opnum != OP_UNDEF && opnum != OP_KEYS)
                 CvLVALUE_off(cv); /* Now *that* was a neat trick. */
         }
        LEAVE;
@@ -589,13 +633,14 @@ of an SV instead of a string/length pair.
 GV *
 Perl_gv_fetchmeth_sv(pTHX_ HV *stash, SV *namesv, I32 level, U32 flags)
 {
-   char *namepv;
-   STRLEN namelen;
-   PERL_ARGS_ASSERT_GV_FETCHMETH_SV;
-   namepv = SvPV(namesv, namelen);
-   if (SvUTF8(namesv))
-       flags |= SVf_UTF8;
-   return gv_fetchmeth_pvn(stash, namepv, namelen, level, flags);
+    char *namepv;
+    STRLEN namelen;
+    PERL_ARGS_ASSERT_GV_FETCHMETH_SV;
+    if (LIKELY(SvPOK_nog(namesv))) /* common case */
+        return gv_fetchmeth_internal(stash, namesv, NULL, 0, level, flags);
+    namepv = SvPV(namesv, namelen);
+    if (SvUTF8(namesv)) flags |= SVf_UTF8;
+    return gv_fetchmeth_pvn(stash, namepv, namelen, level, flags);
 }
 
 /*
@@ -611,7 +656,7 @@ GV *
 Perl_gv_fetchmeth_pv(pTHX_ HV *stash, const char *name, I32 level, U32 flags)
 {
     PERL_ARGS_ASSERT_GV_FETCHMETH_PV;
-    return gv_fetchmeth_pvn(stash, name, strlen(name), level, flags);
+    return gv_fetchmeth_internal(stash, NULL, name, strlen(name), level, flags);
 }
 
 /*
@@ -619,16 +664,16 @@ Perl_gv_fetchmeth_pv(pTHX_ HV *stash, const char *name, I32 level, U32 flags)
 
 Returns the glob with the given C<name> and a defined subroutine or
 C<NULL>.  The glob lives in the given C<stash>, or in the stashes
-accessible via @ISA and UNIVERSAL::.
+accessible via C<@ISA> and C<UNIVERSAL::>.
 
 The argument C<level> should be either 0 or -1.  If C<level==0>, as a
 side-effect creates a glob with the given C<name> in the given C<stash>
 which in the case of success contains an alias for the subroutine, and sets
 up caching info for this glob.
 
-The only significant values for C<flags> are GV_SUPER and SVf_UTF8.
+The only significant values for C<flags> are C<GV_SUPER> and C<SVf_UTF8>.
 
-GV_SUPER indicates that we want to look up the method in the superclasses
+C<GV_SUPER> indicates that we want to look up the method in the superclasses
 of the C<stash>.
 
 The
@@ -642,11 +687,11 @@ obtained from the GV with the C<GvCV> macro.
 
 /* NOTE: No support for tied ISA */
 
-GV *
-Perl_gv_fetchmeth_pvn(pTHX_ HV *stash, const char *name, STRLEN len, I32 level, U32 flags)
+PERL_STATIC_INLINE GV*
+S_gv_fetchmeth_internal(pTHX_ HV* stash, SV* meth, const char* name, STRLEN len, I32 level, U32 flags)
 {
-    dVAR;
     GV** gvp;
+    HE* he;
     AV* linear_av;
     SV** linear_svp;
     SV* linear_sv;
@@ -655,13 +700,11 @@ Perl_gv_fetchmeth_pvn(pTHX_ HV *stash, const char *name, STRLEN len, I32 level,
     CV* cand_cv = NULL;
     GV* topgv = NULL;
     const char *hvname;
-    I32 create = (level >= 0) ? 1 : 0;
+    I32 create = (level >= 0) ? HV_FETCH_LVALUE : 0;
     I32 items;
     U32 topgen_cmp;
     U32 is_utf8 = flags & SVf_UTF8;
 
-    PERL_ARGS_ASSERT_GV_FETCHMETH_PVN;
-
     /* UNIVERSAL methods should be callable without a stash */
     if (!stash) {
        create = 0;  /* probably appropriate */
@@ -676,10 +719,11 @@ Perl_gv_fetchmeth_pvn(pTHX_ HV *stash, const char *name, STRLEN len, I32 level,
       Perl_croak(aTHX_ "Can't use anonymous symbol table for method lookup");
 
     assert(hvname);
-    assert(name);
+    assert(name || meth);
 
     DEBUG_o( Perl_deb(aTHX_ "Looking for %smethod %s in package %s\n",
-                     flags & GV_SUPER ? "SUPER " : "",name,hvname) );
+                     flags & GV_SUPER ? "SUPER " : "",
+                     name ? name : SvPV_nolen(meth), hvname) );
 
     topgen_cmp = HvMROMETA(stash)->cache_gen + PL_sub_generation;
 
@@ -691,14 +735,22 @@ Perl_gv_fetchmeth_pvn(pTHX_ HV *stash, const char *name, STRLEN len, I32 level,
     else cachestash = stash;
 
     /* check locally for a real method or a cache entry */
-    gvp = (GV**)hv_fetch(cachestash, name, is_utf8 ? -(I32)len : (I32)len,
-                        create);
+    he = (HE*)hv_common(
+        cachestash, meth, name, len, (flags & SVf_UTF8) ? HVhek_UTF8 : 0, create, NULL, 0
+    );
+    if (he) gvp = (GV**)&HeVAL(he);
+    else gvp = NULL;
+
     if(gvp) {
         topgv = *gvp;
       have_gv:
         assert(topgv);
         if (SvTYPE(topgv) != SVt_PVGV)
+        {
+            if (!name)
+                name = SvPV_nomg(meth, len);
             gv_init_pvn(topgv, stash, name, len, GV_ADDMULTI|is_utf8);
+        }
         if ((cand_cv = GvCV(topgv))) {
             /* If genuine method or valid cache entry, use it */
             if (!GvCVGEN(topgv) || GvCVGEN(topgv) == topgen_cmp) {
@@ -718,7 +770,7 @@ Perl_gv_fetchmeth_pvn(pTHX_ HV *stash, const char *name, STRLEN len, I32 level,
         }
        else if (stash == cachestash
              && len > 1 /* shortest is uc */ && HvNAMELEN_get(stash) == 4
-              && strnEQ(hvname, "CORE", 4)
+              && strEQs(hvname, "CORE")
               && S_maybe_add_coresub(aTHX_ NULL,topgv,name,len))
            goto have_gv;
     }
@@ -733,7 +785,7 @@ Perl_gv_fetchmeth_pvn(pTHX_ HV *stash, const char *name, STRLEN len, I32 level,
 
         if (!cstash) {
            Perl_ck_warner(aTHX_ packWARN(WARN_SYNTAX),
-                           "Can't locate package %"SVf" for @%"HEKf"::ISA",
+                           "Can't locate package %" SVf " for @%" HEKf "::ISA",
                           SVfARG(linear_sv),
                            HEKfARG(HvNAME_HEK(stash)));
             continue;
@@ -745,7 +797,7 @@ Perl_gv_fetchmeth_pvn(pTHX_ HV *stash, const char *name, STRLEN len, I32 level,
         if (!gvp) {
             if (len > 1 && HvNAMELEN_get(cstash) == 4) {
                 const char *hvname = HvNAME(cstash); assert(hvname);
-                if (strnEQ(hvname, "CORE", 4)
+                if (strEQs(hvname, "CORE")
                  && (candidate =
                       S_maybe_add_coresub(aTHX_ cstash,NULL,name,len)
                     ))
@@ -777,7 +829,8 @@ Perl_gv_fetchmeth_pvn(pTHX_ HV *stash, const char *name, STRLEN len, I32 level,
 
     /* Check UNIVERSAL without caching */
     if(level == 0 || level == -1) {
-        candidate = gv_fetchmeth_pvn(NULL, name, len, 1, flags &~GV_SUPER);
+        candidate = gv_fetchmeth_internal(NULL, meth, name, len, 1,
+                                          flags &~GV_SUPER);
         if(candidate) {
             cand_cv = GvCV(candidate);
             if (topgv && (GvREFCNT(topgv) == 1) && (CvROOT(cand_cv) || CvXSUB(cand_cv))) {
@@ -799,6 +852,13 @@ Perl_gv_fetchmeth_pvn(pTHX_ HV *stash, const char *name, STRLEN len, I32 level,
     return 0;
 }
 
+GV *
+Perl_gv_fetchmeth_pvn(pTHX_ HV *stash, const char *name, STRLEN len, I32 level, U32 flags)
+{
+    PERL_ARGS_ASSERT_GV_FETCHMETH_PVN;
+    return gv_fetchmeth_internal(stash, NULL, name, len, level, flags);
+}
+
 /*
 =for apidoc gv_fetchmeth_autoload
 
@@ -844,14 +904,14 @@ Perl_gv_fetchmeth_pv_autoload(pTHX_ HV *stash, const char *name, I32 level, U32
 /*
 =for apidoc gv_fetchmeth_pvn_autoload
 
-Same as gv_fetchmeth_pvn(), but looks for autoloaded subroutines too.
+Same as C<gv_fetchmeth_pvn()>, but looks for autoloaded subroutines too.
 Returns a glob for the subroutine.
 
 For an autoloaded subroutine without a GV, will create a GV even
-if C<level < 0>.  For an autoloaded subroutine without a stub, GvCV()
+if C<level < 0>.  For an autoloaded subroutine without a stub, C<GvCV()>
 of the result may be zero.
 
-Currently, the only significant value for C<flags> is SVf_UTF8.
+Currently, the only significant value for C<flags> is C<SVf_UTF8>.
 
 =cut
 */
@@ -893,7 +953,7 @@ Perl_gv_fetchmeth_pvn_autoload(pTHX_ HV *stash, const char *name, STRLEN len, I3
 
 Returns the glob which contains the subroutine to call to invoke the method
 on the C<stash>.  In fact in the presence of autoloading this may be the
-glob for "AUTOLOAD".  In this case the corresponding variable $AUTOLOAD is
+glob for "AUTOLOAD".  In this case the corresponding variable C<$AUTOLOAD> is
 already setup.
 
 The third parameter of C<gv_fetchmethod_autoload> determines whether
@@ -906,7 +966,7 @@ These functions grant C<"SUPER"> token
 as a prefix of the method name.  Note
 that if you want to keep the returned glob for a long time, you need to
 check for it being "AUTOLOAD", since at the later time the call may load a
-different subroutine due to $AUTOLOAD changing its value.  Use the glob
+different subroutine due to C<$AUTOLOAD> changing its value.  Use the glob
 created as a side effect to do this.
 
 These functions have the same side-effects as C<gv_fetchmeth> with
@@ -943,17 +1003,14 @@ Perl_gv_fetchmethod_pv_flags(pTHX_ HV *stash, const char *name, U32 flags)
     return gv_fetchmethod_pvn_flags(stash, name, strlen(name), flags);
 }
 
-/* Don't merge this yet, as it's likely to get a len parameter, and possibly
-   even a U32 hash */
 GV *
 Perl_gv_fetchmethod_pvn_flags(pTHX_ HV *stash, const char *name, const STRLEN len, U32 flags)
 {
-    dVAR;
-    const char *nend;
-    const char *nsplit = NULL;
+    const char * const origname = name;
+    const char * const name_end = name + len;
+    const char *last_separator = NULL;
     GV* gv;
     HV* ostash = stash;
-    const char * const origname = name;
     SV *const error_report = MUTABLE_SV(stash);
     const U32 autoload = flags & GV_AUTOLOAD;
     const U32 do_croak = flags & GV_CROAK;
@@ -964,49 +1021,70 @@ Perl_gv_fetchmethod_pvn_flags(pTHX_ HV *stash, const char *name, const STRLEN le
     if (SvTYPE(stash) < SVt_PVHV)
        stash = NULL;
     else {
-       /* The only way stash can become NULL later on is if nsplit is set,
+       /* The only way stash can become NULL later on is if last_separator is set,
           which in turn means that there is no need for a SVt_PVHV case
           the error reporting code.  */
     }
 
-    for (nend = name; *nend || nend != (origname + len); nend++) {
-       if (*nend == '\'') {
-           nsplit = nend;
-           name = nend + 1;
-       }
-       else if (*nend == ':' && *(nend + 1) == ':') {
-           nsplit = nend++;
-           name = nend + 1;
-       }
+    {
+        /* check if the method name is fully qualified or
+         * not, and separate the package name from the actual
+         * method name.
+         *
+         * leaves last_separator pointing to the beginning of the
+         * last package separator (either ' or ::) or 0
+         * if none was found.
+         *
+         * leaves name pointing at the beginning of the
+         * method name.
+         */
+        const char *name_cursor = name;
+        const char * const name_em1 = name_end - 1; /* name_end minus 1 */
+        for (name_cursor = name; name_cursor < name_end ; name_cursor++) {
+            if (*name_cursor == '\'') {
+                last_separator = name_cursor;
+                name = name_cursor + 1;
+            }
+            else if (name_cursor < name_em1 && *name_cursor == ':' && name_cursor[1] == ':') {
+                last_separator = name_cursor++;
+                name = name_cursor + 1;
+            }
+        }
     }
-    if (nsplit) {
-       if ((nsplit - origname) == 5 && memEQ(origname, "SUPER", 5)) {
+
+    /* did we find a separator? */
+    if (last_separator) {
+        STRLEN sep_len= last_separator - origname;
+        if ( memEQs(origname, sep_len, "SUPER")) {
            /* ->SUPER::method should really be looked up in original stash */
            stash = CopSTASH(PL_curcop);
            flags |= GV_SUPER;
            DEBUG_o( Perl_deb(aTHX_ "Treating %s as %s::%s\n",
                         origname, HvENAME_get(stash), name) );
        }
-       else if ((nsplit - origname) >= 7 &&
-                strnEQ(nsplit - 7, "::SUPER", 7)) {
+        else if ( sep_len >= 7 &&
+                strEQs(last_separator - 7, "::SUPER")) {
             /* don't autovifify if ->NoSuchStash::SUPER::method */
-           stash = gv_stashpvn(origname, nsplit - origname - 7, is_utf8);
+            stash = gv_stashpvn(origname, sep_len - 7, is_utf8);
            if (stash) flags |= GV_SUPER;
        }
        else {
             /* don't autovifify if ->NoSuchStash::method */
-            stash = gv_stashpvn(origname, nsplit - origname, is_utf8);
+            stash = gv_stashpvn(origname, sep_len, is_utf8);
        }
        ostash = stash;
     }
 
-    gv = gv_fetchmeth_pvn(stash, name, nend - name, 0, flags);
+    gv = gv_fetchmeth_pvn(stash, name, name_end - name, 0, flags);
     if (!gv) {
+       /* This is the special case that exempts Foo->import and
+          Foo->unimport from being an error even if there's no
+         import/unimport subroutine */
        if (strEQ(name,"import") || strEQ(name,"unimport"))
            gv = MUTABLE_GV(&PL_sv_yes);
        else if (autoload)
            gv = gv_autoload_pvn(
-               ostash, name, nend - name, GV_AUTOLOAD_ISMETHOD|flags
+               ostash, name, name_end - name, GV_AUTOLOAD_ISMETHOD|flags
            );
        if (!gv && do_croak) {
            /* Right now this is exclusively for the benefit of S_method_common
@@ -1022,31 +1100,31 @@ Perl_gv_fetchmethod_pvn_flags(pTHX_ HV *stash, const char *name, const STRLEN le
                                       HV_FETCH_ISEXISTS, NULL, 0)
                ) {
                    require_pv("IO/File.pm");
-                   gv = gv_fetchmeth_pvn(stash, name, nend - name, 0, flags);
+                   gv = gv_fetchmeth_pvn(stash, name, name_end - name, 0, flags);
                    if (gv)
                        return gv;
                }
                Perl_croak(aTHX_
-                          "Can't locate object method \"%"UTF8f
-                          "\" via package \"%"HEKf"\"",
-                                   UTF8fARG(is_utf8, nend - name, name),
+                          "Can't locate object method \"%" UTF8f
+                          "\" via package \"%" HEKf "\"",
+                                   UTF8fARG(is_utf8, name_end - name, name),
                                     HEKfARG(HvNAME_HEK(stash)));
            }
            else {
                 SV* packnamesv;
 
-               if (nsplit) {
-                   packnamesv = newSVpvn_flags(origname, nsplit - origname,
+               if (last_separator) {
+                   packnamesv = newSVpvn_flags(origname, last_separator - origname,
                                                     SVs_TEMP | is_utf8);
                } else {
                    packnamesv = error_report;
                }
 
                Perl_croak(aTHX_
-                          "Can't locate object method \"%"UTF8f
-                          "\" via package \"%"SVf"\""
-                          " (perhaps you forgot to load \"%"SVf"\"?)",
-                          UTF8fARG(is_utf8, nend - name, name),
+                          "Can't locate object method \"%" UTF8f
+                          "\" via package \"%" SVf "\""
+                          " (perhaps you forgot to load \"%" SVf "\"?)",
+                          UTF8fARG(is_utf8, name_end - name, name),
                            SVfARG(packnamesv), SVfARG(packnamesv));
            }
        }
@@ -1057,7 +1135,7 @@ Perl_gv_fetchmethod_pvn_flags(pTHX_ HV *stash, const char *name, const STRLEN le
            GV* stubgv;
            GV* autogv;
 
-           if (CvANON(cv) || !CvGV(cv))
+           if (CvANON(cv) || CvLEXICAL(cv))
                stubgv = gv;
            else {
                stubgv = CvGV(cv);
@@ -1098,7 +1176,6 @@ Perl_gv_autoload_pv(pTHX_ HV *stash, const char *namepv, U32 flags)
 GV*
 Perl_gv_autoload_pvn(pTHX_ HV *stash, const char *name, STRLEN len, U32 flags)
 {
-    dVAR;
     GV* gv;
     CV* cv;
     HV* varstash;
@@ -1139,8 +1216,9 @@ Perl_gv_autoload_pvn(pTHX_ HV *stash, const char *name, STRLEN len, U32 flags)
      && (GvCVGEN(gv) || GvSTASH(gv) != stash)
     )
        Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
-                        "Use of inherited AUTOLOAD for non-method %"SVf
-                        "::%"UTF8f"() is deprecated",
+                        "Use of inherited AUTOLOAD for non-method %" SVf
+                        "::%" UTF8f "() is deprecated. This will be "
+                         "fatal in Perl 5.28",
                         SVfARG(packname),
                          UTF8fARG(is_utf8, len, name));
 
@@ -1203,7 +1281,7 @@ Perl_gv_autoload_pvn(pTHX_ HV *stash, const char *name, STRLEN len, U32 flags)
      * use that, but for lack of anything better we will use the sub's
      * original package to look up $AUTOLOAD.
      */
-    varstash = GvSTASH(CvGV(cv));
+    varstash = CvNAMED(cv) ? CvSTASH(cv) : GvSTASH(CvGV(cv));
     vargv = *(GV**)hv_fetch(varstash, S_autoload, S_autolen, TRUE);
     ENTER;
 
@@ -1233,52 +1311,72 @@ Perl_gv_autoload_pvn(pTHX_ HV *stash, const char *name, STRLEN len, U32 flags)
 
 /* require_tie_mod() internal routine for requiring a module
  * that implements the logic of automatic ties like %! and %-
+ * It loads the module and then calls the _tie_it subroutine
+ * with the passed gv as an argument.
  *
  * The "gv" parameter should be the glob.
- * "varpv" holds the name of the var, used for error messages.
+ * "varname" holds the 1-char name of the var, used for error messages.
  * "namesv" holds the module name. Its refcount will be decremented.
- * "methpv" holds the method name to test for to check that things
- *   are working reasonably close to as expected.
  * "flags": if flag & 1 then save the scalar before loading.
  * For the protection of $! to work (it is set by this routine)
  * the sv slot must already be magicalized.
  */
-STATIC HV*
-S_require_tie_mod(pTHX_ GV *gv, const char *varpv, SV* namesv, const char *methpv,const U32 flags)
+STATIC void
+S_require_tie_mod(pTHX_ GV *gv, const char varname, const char * name,
+                        STRLEN len, const U32 flags)
 {
-    dVAR;
-    HV* stash = gv_stashsv(namesv, 0);
+    const SV * const target = varname == '[' ? GvSV(gv) : (SV *)GvHV(gv);
 
     PERL_ARGS_ASSERT_REQUIRE_TIE_MOD;
 
-    if (!stash || !(gv_fetchmethod_autoload(stash, methpv, FALSE))) {
-       SV *module = newSVsv(namesv);
-       char varname = *varpv; /* varpv might be clobbered by load_module,
-                                 so save it. For the moment it's always
-                                 a single char. */
+    /* If it is not tied */
+    if (!target || !SvRMAGICAL(target)
+     || !mg_find(target,
+                 varname == '[' ? PERL_MAGIC_tiedscalar : PERL_MAGIC_tied))
+    {
+      HV *stash;
+      GV **gvp;
+      dSP;
+
+      ENTER;
+
+#define HV_FETCH_TIE_FUNC (GV **)hv_fetchs(stash, "_tie_it", 0)
+
+      /* Load the module if it is not loaded.  */
+      if (!(stash = gv_stashpvn(name, len, 0))
+       || !(gvp = HV_FETCH_TIE_FUNC) || !*gvp || !GvCV(*gvp))
+      {
+       SV * const module = newSVpvn(name, len);
        const char type = varname == '[' ? '$' : '%';
-#ifdef DEBUGGING
-       dSP;
-#endif
-       ENTER;
-       SAVEFREESV(namesv);
        if ( flags & 1 )
            save_scalar(gv);
        Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, module, NULL);
        assert(sp == PL_stack_sp);
-       stash = gv_stashsv(namesv, 0);
+       stash = gv_stashpvn(name, len, 0);
        if (!stash)
-           Perl_croak(aTHX_ "panic: Can't use %c%c because %"SVf" is not available",
-                   type, varname, SVfARG(namesv));
-       else if (!gv_fetchmethod(stash, methpv))
-           Perl_croak(aTHX_ "panic: Can't use %c%c because %"SVf" does not support method %s",
-                   type, varname, SVfARG(namesv), methpv);
-       LEAVE;
+           Perl_croak(aTHX_ "panic: Can't use %c%c because %s is not available",
+                   type, varname, name);
+       else if (!(gvp = HV_FETCH_TIE_FUNC) || !*gvp || !GvCV(*gvp))
+           Perl_croak(aTHX_ "panic: Can't use %c%c because %s does not define _tie_it",
+                   type, varname, name);
+      }
+      /* Now call the tie function.  It should be in *gvp.  */
+      assert(gvp); assert(*gvp); assert(GvCV(*gvp));
+      PUSHMARK(SP);
+      XPUSHs((SV *)gv);
+      PUTBACK;
+      call_sv((SV *)*gvp, G_VOID|G_DISCARD);
+      LEAVE;
     }
-    else SvREFCNT_dec_NN(namesv);
-    return stash;
 }
 
+/* add a require_tie_mod_s - the _s suffix is similar to pvs type suffixes,
+ * IOW it means we do STR_WITH_LEN() ourselves and the user should pass in
+ * a true string WITHOUT a len.
+ */
+#define require_tie_mod_s(gv, varname, name, flags) \
+    S_require_tie_mod(aTHX_ gv, varname, STR_WITH_LEN(name), flags)
+
 /*
 =for apidoc gv_stashpv
 
@@ -1302,7 +1400,7 @@ Returns a pointer to the stash for a specified package.  The C<namelen>
 parameter indicates the length of the C<name>, in bytes.  C<flags> is passed
 to C<gv_fetchpvn_flags()>, so if set to C<GV_ADD> then the package will be
 created if it does not already exist.  If the package does not exist and
-C<flags> is 0 (or any other setting that does not create packages) then NULL
+C<flags> is 0 (or any other setting that does not create packages) then C<NULL>
 is returned.
 
 Flags may be one of:
@@ -1314,13 +1412,24 @@ Flags may be one of:
     GV_NOEXPAND
     GV_ADDMG
 
-The most important of which are probably GV_ADD and SVf_UTF8.
+The most important of which are probably C<GV_ADD> and C<SVf_UTF8>.
+
+Note, use of C<gv_stashsv> instead of C<gv_stashpvn> where possible is strongly
+recommended for performance reasons.
 
 =cut
 */
 
-HV*
-Perl_gv_stashpvn(pTHX_ const char *name, U32 namelen, I32 flags)
+/*
+gv_stashpvn_internal
+
+Perform the internal bits of gv_stashsvpvn_cached. You could think of this
+as being one half of the logic. Not to be called except from gv_stashsvpvn_cached().
+
+*/
+
+PERL_STATIC_INLINE HV*
+S_gv_stashpvn_internal(pTHX_ const char *name, U32 namelen, I32 flags)
 {
     char smallbuf[128];
     char *tmpbuf;
@@ -1328,7 +1437,7 @@ Perl_gv_stashpvn(pTHX_ const char *name, U32 namelen, I32 flags)
     GV *tmpgv;
     U32 tmplen = namelen + 2;
 
-    PERL_ARGS_ASSERT_GV_STASHPVN;
+    PERL_ARGS_ASSERT_GV_STASHPVN_INTERNAL;
 
     if (tmplen <= sizeof smallbuf)
        tmpbuf = smallbuf;
@@ -1340,7 +1449,7 @@ Perl_gv_stashpvn(pTHX_ const char *name, U32 namelen, I32 flags)
     tmpgv = gv_fetchpvn_flags(tmpbuf, tmplen, flags, SVt_PVHV);
     if (tmpbuf != smallbuf)
        Safefree(tmpbuf);
-    if (!tmpgv)
+    if (!tmpgv || !isGV_with_GP(tmpgv))
        return NULL;
     stash = GvHV(tmpgv);
     if (!(flags & ~GV_NOADD_MASK) && !stash) return NULL;
@@ -1358,9 +1467,74 @@ Perl_gv_stashpvn(pTHX_ const char *name, U32 namelen, I32 flags)
 }
 
 /*
+gv_stashsvpvn_cached
+
+Returns a pointer to the stash for a specified package, possibly
+cached.  Implements both C<gv_stashpvn> and C<gv_stashsv>.
+
+Requires one of either namesv or namepv to be non-null.
+
+See C<L</gv_stashpvn>> for details on "flags".
+
+Note the sv interface is strongly preferred for performance reasons.
+
+*/
+
+#define PERL_ARGS_ASSERT_GV_STASHSVPVN_CACHED \
+    assert(namesv || name)
+
+PERL_STATIC_INLINE HV*
+S_gv_stashsvpvn_cached(pTHX_ SV *namesv, const char *name, U32 namelen, I32 flags)
+{
+    HV* stash;
+    HE* he;
+
+    PERL_ARGS_ASSERT_GV_STASHSVPVN_CACHED;
+
+    he = (HE *)hv_common(
+        PL_stashcache, namesv, name, namelen,
+        (flags & SVf_UTF8) ? HVhek_UTF8 : 0, 0, NULL, 0
+    );
+
+    if (he) return INT2PTR(HV*,SvIVX(HeVAL(he)));
+    else if (flags & GV_CACHE_ONLY) return NULL;
+
+    if (namesv) {
+        if (SvOK(namesv)) { /* prevent double uninit warning */
+            STRLEN len;
+            name = SvPV_const(namesv, len);
+            namelen = len;
+            flags |= SvUTF8(namesv);
+        } else {
+            name = ""; namelen = 0;
+        }
+    }
+    stash = gv_stashpvn_internal(name, namelen, flags);
+
+    if (stash && namelen) {
+        SV* const ref = newSViv(PTR2IV(stash));
+        (void)hv_store(PL_stashcache, name,
+            (flags & SVf_UTF8) ? -(I32)namelen : (I32)namelen, ref, 0);
+    }
+
+    return stash;
+}
+
+HV*
+Perl_gv_stashpvn(pTHX_ const char *name, U32 namelen, I32 flags)
+{
+    PERL_ARGS_ASSERT_GV_STASHPVN;
+    return gv_stashsvpvn_cached(NULL, name, namelen, flags);
+}
+
+/*
 =for apidoc gv_stashsv
 
-Returns a pointer to the stash for a specified package.  See C<gv_stashpvn>.
+Returns a pointer to the stash for a specified package.  See
+C<L</gv_stashpvn>>.
+
+Note this interface is strongly preferred over C<gv_stashpvn> for performance
+reasons.
 
 =cut
 */
@@ -1368,12 +1542,8 @@ Returns a pointer to the stash for a specified package.  See C<gv_stashpvn>.
 HV*
 Perl_gv_stashsv(pTHX_ SV *sv, I32 flags)
 {
-    STRLEN len;
-    const char * const ptr = SvPV_const(sv,len);
-
     PERL_ARGS_ASSERT_GV_STASHSV;
-
-    return gv_stashpvn(ptr, len, flags | SvUTF8(sv));
+    return gv_stashsvpvn_cached(sv, NULL, 0, flags);
 }
 
 
@@ -1422,7 +1592,10 @@ S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv, const char **name,
 
     PERL_ARGS_ASSERT_PARSE_GV_STASH_NAME;
     
-    if (full_len > 2 && **name == '*' && isIDFIRST_lazy_if(*name + 1, is_utf8)) {
+    if (   full_len > 2
+        && **name == '*'
+        && isIDFIRST_lazy_if_safe(*name + 1, name_end, is_utf8))
+    {
         /* accidental stringify on a GV? */
         (*name)++;
     }
@@ -1470,8 +1643,8 @@ S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv, const char **name,
                     *stash = GvHV(*gv) = newHV();
                     if (!HvNAME_get(*stash)) {
                         if (GvSTASH(*gv) == PL_defstash && *len == 6
-                            && strnEQ(*name, "CORE", 4))
-                            hv_name_set(*stash, "CORE", 4, 0);
+                            && strEQs(*name, "CORE"))
+                            hv_name_sets(*stash, "CORE", 0);
                         else
                             hv_name_set(
                                 *stash, nambeg, name_cursor-nambeg, is_utf8
@@ -1490,8 +1663,15 @@ S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv, const char **name,
                 name_cursor++;
             *name = name_cursor+1;
             if (*name == name_end) {
-                if (!*gv)
-                    *gv = MUTABLE_GV(*hv_fetchs(PL_defstash, "main::", TRUE));
+                if (!*gv) {
+                   *gv = MUTABLE_GV(*hv_fetchs(PL_defstash, "main::", TRUE));
+                   if (SvTYPE(*gv) != SVt_PVGV) {
+                       gv_init_pvn(*gv, PL_defstash, "main::", 6,
+                                   GV_ADDMULTI);
+                       GvHV(*gv) =
+                           MUTABLE_HV(SvREFCNT_inc_simple(PL_defstash));
+                   }
+               }
                 return TRUE;
             }
         }
@@ -1507,7 +1687,7 @@ S_gv_is_in_main(pTHX_ const char *name, STRLEN len, const U32 is_utf8)
     PERL_ARGS_ASSERT_GV_IS_IN_MAIN;
     
     /* If it's an alphanumeric variable */
-    if ( len && isIDFIRST_lazy_if(name, is_utf8) ) {
+    if ( len && isIDFIRST_lazy_if_safe(name, name + len, is_utf8) ) {
         /* Some "normal" variables are always in main::,
          * like INC or STDOUT.
          */
@@ -1597,14 +1777,14 @@ S_find_default_stash(pTHX_ HV **stash, const char *name, STRLEN len,
                     /* diag_listed_as: Variable "%s" is not imported%s */
                     Perl_ck_warner_d(
                         aTHX_ packWARN(WARN_MISC),
-                        "Variable \"%c%"UTF8f"\" is not imported",
+                        "Variable \"%c%" UTF8f "\" is not imported",
                         sv_type == SVt_PVAV ? '@' :
                         sv_type == SVt_PVHV ? '%' : '$',
                         UTF8fARG(is_utf8, len, name));
                     if (GvCVu(*gvp))
                         Perl_ck_warner_d(
                             aTHX_ packWARN(WARN_MISC),
-                            "\t(Did you mean &%"UTF8f" instead?)\n",
+                            "\t(Did you mean &%" UTF8f " instead?)\n",
                             UTF8fARG(is_utf8, len, name)
                         );
                     *stash = NULL;
@@ -1619,17 +1799,19 @@ S_find_default_stash(pTHX_ HV **stash, const char *name, STRLEN len,
 
     if (!*stash) {
         if (add && !PL_in_clean_all) {
-            SV * const err = Perl_mess(aTHX_
-                 "Global symbol \"%s%"UTF8f
-                 "\" requires explicit package name",
+            GV *gv;
+            qerror(Perl_mess(aTHX_
+                 "Global symbol \"%s%" UTF8f
+                 "\" requires explicit package name (did you forget to "
+                 "declare \"my %s%" UTF8f "\"?)",
                  (sv_type == SVt_PV ? "$"
                   : sv_type == SVt_PVAV ? "@"
                   : sv_type == SVt_PVHV ? "%"
-                  : ""), UTF8fARG(is_utf8, len, name));
-            GV *gv;
-            if (is_utf8)
-                SvUTF8_on(err);
-            qerror(err);
+                  : ""), UTF8fARG(is_utf8, len, name),
+                 (sv_type == SVt_PV ? "$"
+                  : sv_type == SVt_PVAV ? "@"
+                  : sv_type == SVt_PVHV ? "%"
+                  : ""), UTF8fARG(is_utf8, len, name)));
             /* To maintain the output of errors after the strict exception
              * above, and to keep compat with older releases, rather than
              * placing the variables in the pad, we place
@@ -1652,20 +1834,25 @@ S_find_default_stash(pTHX_ HV **stash, const char *name, STRLEN len,
     return TRUE;
 }
 
+/* gv_magicalize only turns on the SVf_READONLY flag, not SVf_PROTECT.  So
+   redefine SvREADONLY_on for that purpose.  We don’t use it later on in
+   this file.  */
+#undef SvREADONLY_on
+#define SvREADONLY_on(sv) (SvFLAGS(sv) |= SVf_READONLY)
+
 /* gv_magicalize() is called by gv_fetchpvn_flags when creating
  * a new GV.
  * Note that it does not insert the GV into the stash prior to
  * magicalization, which some variables require need in order
  * to work (like $[, %+, %-, %!), so callers must take care of
- * that beforehand.
+ * that.
  * 
- * The return value has a specific meaning for gv_fetchpvn_flags:
- * If it returns true, and the gv is empty, it indicates that its
- * refcount should be decreased.
+ * It returns true if the gv did turn out to be magical one; i.e.,
+ * if gv_magicalize actually did something.
  */
 PERL_STATIC_INLINE bool
 S_gv_magicalize(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len,
-               bool addmg, const svtype sv_type)
+                      const svtype sv_type)
 {
     SSize_t paren;
 
@@ -1676,21 +1863,31 @@ S_gv_magicalize(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len,
           and VERSION. All the others apply only to the main stash or to
           CORE (which is checked right after this). */
        if (len) {
-           const char * const name2 = name + 1;
            switch (*name) {
            case 'E':
-               if (strnEQ(name2, "XPORT", 5))
+                if (
+                    len >= 6 && name[1] == 'X' &&
+                    (memEQs(name, len, "EXPORT")
+                    ||memEQs(name, len, "EXPORT_OK")
+                    ||memEQs(name, len, "EXPORT_FAIL")
+                    ||memEQs(name, len, "EXPORT_TAGS"))
+                )
                    GvMULTI_on(gv);
                break;
            case 'I':
-               if (strEQ(name2, "SA"))
+                if (memEQs(name, len, "ISA"))
                    gv_magicalize_isa(gv);
                break;
            case 'V':
-               if (strEQ(name2, "ERSION"))
+                if (memEQs(name, len, "VERSION"))
                    GvMULTI_on(gv);
                break;
            case 'a':
+                if (stash == PL_debstash && memEQs(name, len, "args")) {
+                   GvMULTI_on(gv_AVadd(gv));
+                   break;
+                }
+                /* FALLTHROUGH */
            case 'b':
                if (len == 1 && sv_type == SVt_PV)
                    GvMULTI_on(gv);
@@ -1698,13 +1895,13 @@ S_gv_magicalize(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len,
            default:
                goto try_core;
            }
-           return addmg;
+           goto ret;
        }
       try_core:
        if (len > 1 /* shortest is uc */ && HvNAMELEN_get(stash) == 4) {
          /* Avoid null warning: */
          const char * const stashname = HvNAME(stash); assert(stashname);
-         if (strnEQ(stashname, "CORE", 4))
+         if (strEQs(stashname, "CORE"))
            S_maybe_add_coresub(aTHX_ 0, gv, name, len);
        }
     }
@@ -1725,27 +1922,32 @@ S_gv_magicalize(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len,
        } else
 #endif
        {
-           const char * const name2 = name + 1;
            switch (*name) {
            case 'A':
-               if (strEQ(name2, "RGV")) {
+                if (memEQs(name, len, "ARGV")) {
                    IoFLAGS(GvIOn(gv)) |= IOf_ARGV|IOf_START;
                }
-               else if (strEQ(name2, "RGVOUT")) {
+                else if (memEQs(name, len, "ARGVOUT")) {
                    GvMULTI_on(gv);
                }
                break;
            case 'E':
-               if (strnEQ(name2, "XPORT", 5))
+                if (
+                    len >= 6 && name[1] == 'X' &&
+                    (memEQs(name, len, "EXPORT")
+                    ||memEQs(name, len, "EXPORT_OK")
+                    ||memEQs(name, len, "EXPORT_FAIL")
+                    ||memEQs(name, len, "EXPORT_TAGS"))
+                )
                    GvMULTI_on(gv);
                break;
            case 'I':
-               if (strEQ(name2, "SA")) {
+                if (memEQs(name, len, "ISA")) {
                    gv_magicalize_isa(gv);
                }
                break;
            case 'S':
-               if (strEQ(name2, "IG")) {
+                if (memEQs(name, len, "SIG")) {
                    HV *hv;
                    I32 i;
                    if (!PL_psig_name) {
@@ -1776,60 +1978,80 @@ S_gv_magicalize(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len,
                }
                break;
            case 'V':
-               if (strEQ(name2, "ERSION"))
+                if (memEQs(name, len, "VERSION"))
                    GvMULTI_on(gv);
                break;
             case '\003':        /* $^CHILD_ERROR_NATIVE */
-               if (strEQ(name2, "HILD_ERROR_NATIVE"))
+                if (memEQs(name, len, "\003HILD_ERROR_NATIVE"))
                    goto magicalize;
+                                /* @{^CAPTURE} %{^CAPTURE} */
+                if (memEQs(name, len, "\003APTURE")) {
+                    AV* const av = GvAVn(gv);
+                    UV uv= *name;
+
+                    sv_magic(MUTABLE_SV(av), (SV*)uv, PERL_MAGIC_regdata, NULL, 0);
+                    SvREADONLY_on(av);
+
+                    if (sv_type == SVt_PVHV || sv_type == SVt_PVGV)
+                        require_tie_mod_s(gv, '-', "Tie::Hash::NamedCapture",0);
+
+                } else          /* %{^CAPTURE_ALL} */
+                if (memEQs(name, len, "\003APTURE_ALL")) {
+                    if (sv_type == SVt_PVHV || sv_type == SVt_PVGV)
+                        require_tie_mod_s(gv, '+', "Tie::Hash::NamedCapture",0);
+                }
                break;
            case '\005':        /* $^ENCODING */
-               if (strEQ(name2, "NCODING"))
+                if (memEQs(name, len, "\005NCODING"))
                    goto magicalize;
                break;
            case '\007':        /* $^GLOBAL_PHASE */
-               if (strEQ(name2, "LOBAL_PHASE"))
+                if (memEQs(name, len, "\007LOBAL_PHASE"))
                    goto ro_magicalize;
                break;
            case '\014':        /* $^LAST_FH */
-               if (strEQ(name2, "AST_FH"))
+                if (memEQs(name, len, "\014AST_FH"))
                    goto ro_magicalize;
                break;
             case '\015':        /* $^MATCH */
-                if (strEQ(name2, "ATCH")) {
+                if (memEQs(name, len, "\015ATCH")) {
                     paren = RX_BUFF_IDX_CARET_FULLMATCH;
                     goto storeparen;
                 }
                 break;
            case '\017':        /* $^OPEN */
-               if (strEQ(name2, "PEN"))
+                if (memEQs(name, len, "\017PEN"))
                    goto magicalize;
                break;
            case '\020':        /* $^PREMATCH  $^POSTMATCH */
-                if (strEQ(name2, "REMATCH")) {
+                if (memEQs(name, len, "\020REMATCH")) {
                     paren = RX_BUFF_IDX_CARET_PREMATCH;
                     goto storeparen;
                 }
-               if (strEQ(name2, "OSTMATCH")) {
+                if (memEQs(name, len, "\020OSTMATCH")) {
                     paren = RX_BUFF_IDX_CARET_POSTMATCH;
                     goto storeparen;
                 }
                break;
            case '\024':        /* ${^TAINT} */
-               if (strEQ(name2, "AINT"))
+                if (memEQs(name, len, "\024AINT"))
                    goto ro_magicalize;
                break;
            case '\025':        /* ${^UNICODE}, ${^UTF8LOCALE} */
-               if (strEQ(name2, "NICODE"))
+                if (memEQs(name, len, "\025NICODE"))
                    goto ro_magicalize;
-               if (strEQ(name2, "TF8LOCALE"))
+                if (memEQs(name, len, "\025TF8LOCALE"))
                    goto ro_magicalize;
-               if (strEQ(name2, "TF8CACHE"))
+                if (memEQs(name, len, "\025TF8CACHE"))
                    goto magicalize;
                break;
            case '\027':        /* $^WARNING_BITS */
-               if (strEQ(name2, "ARNING_BITS"))
+                if (memEQs(name, len, "\027ARNING_BITS"))
+                   goto magicalize;
+#ifdef WIN32
+                else if (memEQs(name, len, "\027IN32_SLOPPY_STAT"))
                    goto magicalize;
+#endif
                break;
            case '1':
            case '2':
@@ -1843,13 +2065,11 @@ S_gv_magicalize(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len,
            {
                /* Ensures that we have an all-digit variable, ${"1foo"} fails
                   this test  */
-               /* This snippet is taken from is_gv_magical */
-               const char *end = name + len;
-               while (--end > name) {
-                   if (!isDIGIT(*end))
-                        return addmg;
-               }
-                paren = strtoul(name, NULL, 10);
+                UV uv;
+                if (!grok_atoUV(name, &uv, NULL) || uv > I32_MAX)
+                    goto ret;
+                /* XXX why are we using a SSize_t? */
+                paren = (SSize_t)(I32)uv;
                 goto storeparen;
            }
            }
@@ -1916,41 +2136,38 @@ S_gv_magicalize(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len,
 
            sv_magic(GvSVn(gv), MUTABLE_SV(gv), PERL_MAGIC_sv, name, len);
 
-            /* magicalization must be done before require_tie_mod is called */
+            /* magicalization must be done before require_tie_mod_s is called */
            if (sv_type == SVt_PVHV || sv_type == SVt_PVGV)
-           {
-               require_tie_mod(gv, "!", newSVpvs("Errno"), "TIEHASH", 1);
-                addmg = FALSE;
-           }
+                require_tie_mod_s(gv, '!', "Errno", 1);
 
            break;
-       case '-':               /* $- */
-       case '+':               /* $+ */
-       GvMULTI_on(gv); /* no used once warnings here */
-        {
-            AV* const av = GvAVn(gv);
-           SV* const avc = (*name == '+') ? MUTABLE_SV(av) : NULL;
-
-           sv_magic(MUTABLE_SV(av), avc, PERL_MAGIC_regdata, NULL, 0);
-            sv_magic(GvSVn(gv), MUTABLE_SV(gv), PERL_MAGIC_sv, name, len);
-            if (avc)
-                SvREADONLY_on(GvSVn(gv));
-            SvREADONLY_on(av);
-
-            if (sv_type == SVt_PVHV || sv_type == SVt_PVGV)
-           {
-                require_tie_mod(gv, name, newSVpvs("Tie::Hash::NamedCapture"), "TIEHASH", 0);
-                addmg = FALSE;
-           }
+       case '-':               /* $-, %-, @- */
+       case '+':               /* $+, %+, @+ */
+            GvMULTI_on(gv); /* no used once warnings here */
+            {   /* $- $+ */
+                sv_magic(GvSVn(gv), MUTABLE_SV(gv), PERL_MAGIC_sv, name, len);
+                if (*name == '+')
+                    SvREADONLY_on(GvSVn(gv));
+            }
+            {   /* %- %+ */
+                if (sv_type == SVt_PVHV || sv_type == SVt_PVGV)
+                    require_tie_mod_s(gv, *name, "Tie::Hash::NamedCapture",0);
+            }
+            {   /* @- @+ */
+                AV* const av = GvAVn(gv);
+                const UV uv = (UV)*name;
 
+                sv_magic(MUTABLE_SV(av), (SV*)uv, PERL_MAGIC_regdata, NULL, 0);
+                SvREADONLY_on(av);
+            }
             break;
-       }
        case '*':               /* $* */
        case '#':               /* $# */
            if (sv_type == SVt_PV)
-               /* diag_listed_as: $* is no longer supported */
+               /* diag_listed_as: $* is no longer supported. Its use will be fatal in Perl 5.30 */
                Perl_ck_warner_d(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX),
-                                "$%c is no longer supported", *name);
+                                "$%c is no longer supported. Its use "
+                                 "will be fatal in Perl 5.30", *name);
            break;
        case '\010':    /* $^H */
            {
@@ -1961,8 +2178,7 @@ S_gv_magicalize(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len,
        case '[':               /* $[ */
            if ((sv_type == SVt_PV || sv_type == SVt_PVGV)
             && FEATURE_ARYBASE_IS_ENABLED) {
-               require_tie_mod(gv,name,newSVpvs("arybase"),"FETCH",0);
-                addmg = FALSE;
+                require_tie_mod_s(gv,'[',"arybase",0);
            }
            else goto magicalize;
             break;
@@ -2030,9 +2246,19 @@ S_gv_magicalize(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len,
        }
     }
 
-    return addmg;
+   ret:
+    /* Return true if we actually did something.  */
+    return GvAV(gv) || GvHV(gv) || GvIO(gv) || GvCV(gv)
+        || ( GvSV(gv) && (
+                           SvOK(GvSV(gv)) || SvMAGICAL(GvSV(gv))
+                         )
+           );
 }
 
+/* If we do ever start using this later on in the file, we need to make
+   sure we don’t accidentally use the wrong definition.  */
+#undef SvREADONLY_on
+
 /* This function is called when the stash already holds the GV of the magic
  * variable we're looking for, but we need to check that it has the correct
  * kind of magic.  For example, if someone first uses $! and then %!, the
@@ -2046,21 +2272,22 @@ S_maybe_multimagic_gv(pTHX_ GV *gv, const char *name, const svtype sv_type)
 
     if (sv_type == SVt_PVHV || sv_type == SVt_PVGV) {
         if (*name == '!')
-            require_tie_mod(gv, "!", newSVpvs("Errno"), "TIEHASH", 1);
+            require_tie_mod_s(gv, '!', "Errno", 1);
         else if (*name == '-' || *name == '+')
-            require_tie_mod(gv, name, newSVpvs("Tie::Hash::NamedCapture"), "TIEHASH", 0);
+            require_tie_mod_s(gv, *name, "Tie::Hash::NamedCapture", 0);
     } else if (sv_type == SVt_PV) {
         if (*name == '*' || *name == '#') {
-            /* diag_listed_as: $* is no longer supported */
+            /* diag_listed_as: $# is no longer supported. Its use will be fatal in Perl 5.30 */
             Perl_ck_warner_d(aTHX_ packWARN2(WARN_DEPRECATED,
                                              WARN_SYNTAX),
-                             "$%c is no longer supported", *name);
+                             "$%c is no longer supported. Its use "
+                             "will be fatal in Perl 5.30", *name);
         }
     }
     if (sv_type==SVt_PV || sv_type==SVt_PVGV) {
       switch (*name) {
       case '[':
-          require_tie_mod(gv,name,newSVpvs("arybase"),"FETCH",0);
+          require_tie_mod_s(gv,'[',"arybase",0);
           break;
 #ifdef PERL_SAWAMPERSAND
       case '`':
@@ -2084,7 +2311,6 @@ GV *
 Perl_gv_fetchpvn_flags(pTHX_ const char *nambeg, STRLEN full_len, I32 flags,
                       const svtype sv_type)
 {
-    dVAR;
     const char *name = nambeg;
     GV *gv = NULL;
     GV**gvp;
@@ -2152,7 +2378,7 @@ Perl_gv_fetchpvn_flags(pTHX_ const char *nambeg, STRLEN full_len, I32 flags,
                 maybe_multimagic_gv(gv, name, sv_type);
            }
            else if (len == 3 && sv_type == SVt_PVAV
-                 && strnEQ(name, "ISA", 3)
+                 && strEQs(name, "ISA")
                  && (!GvAV(gv) || !SvSMAGICAL(GvAV(gv))))
                gv_magicalize_isa(gv);
        }
@@ -2183,40 +2409,33 @@ Perl_gv_fetchpvn_flags(pTHX_ const char *nambeg, STRLEN full_len, I32 flags,
 
     if (add & GV_ADDWARN)
        Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
-               "Had to create %"UTF8f" unexpectedly",
+               "Had to create %" UTF8f " unexpectedly",
                 UTF8fARG(is_utf8, name_end-nambeg, nambeg));
     gv_init_pvn(gv, stash, name, len, (add & GV_ADDMULTI)|is_utf8);
 
-    if ( isIDFIRST_lazy_if(name, is_utf8) && !ckWARN(WARN_ONCE) )
+    if (   full_len != 0
+        && isIDFIRST_lazy_if_safe(name, name + full_len, is_utf8)
+        && !ckWARN(WARN_ONCE) )
+    {
         GvMULTI_on(gv) ;
-
-    /* First, store the gv in the symtab if we're adding magic,
-     * but only for non-empty GVs
-     */
-#define GvEMPTY(gv)      !(GvAV(gv) || GvHV(gv) || GvIO(gv) \
-                        || GvCV(gv) || (GvSV(gv) && SvOK(GvSV(gv))))
-    
-    if ( addmg && !GvEMPTY(gv) ) {
-        (void)hv_store(stash,name,len,(SV *)gv,0);
     }
 
     /* set up magic where warranted */
-    if ( gv_magicalize(gv, stash, name, len, addmg, sv_type) ) {
+    if ( gv_magicalize(gv, stash, name, len, sv_type) ) {
         /* See 23496c6 */
-        if (GvEMPTY(gv)) {
-            if ( GvSV(gv) && SvMAGICAL(GvSV(gv)) ) {
-                /* The GV was and still is "empty", except that now
-                 * it has the magic flags turned on, so we want it
+        if (addmg) {
+                /* gv_magicalize magicalised this gv, so we want it
                  * stored in the symtab.
+                 * Effectively the caller is asking, ‘Does this gv exist?’ 
+                 * And we respond, ‘Er, *now* it does!’
                  */
                 (void)hv_store(stash,name,len,(SV *)gv,0);
-            }
-            else {
-                /* Most likely the temporary GV created above */
+        }
+    }
+    else if (addmg) {
+                /* The temporary GV created above */
                 SvREFCNT_dec_NN(gv);
                 gv = NULL;
-            }
-        }
     }
     
     if (gv) gv_init_svtype(gv, faking_it ? SVt_PVCV : sv_type);
@@ -2262,15 +2481,14 @@ Perl_gv_efullname4(pTHX_ SV *sv, const GV *gv, const char *prefix, bool keepmain
 void
 Perl_gv_check(pTHX_ HV *stash)
 {
-    dVAR;
     I32 i;
 
     PERL_ARGS_ASSERT_GV_CHECK;
 
-    if (!HvARRAY(stash))
+    if (!SvOOK(stash))
        return;
 
-    assert(SvOOK(stash));
+    assert(HvARRAY(stash));
 
     for (i = 0; i <= (I32) HvMAX(stash); i++) {
         const HE *entry;
@@ -2279,7 +2497,10 @@ Perl_gv_check(pTHX_ HV *stash)
        for (entry = HvARRAY(stash)[i]; entry; entry = HeNEXT(entry)) {
             GV *gv;
             HV *hv;
-           if (HeKEY(entry)[HeKLEN(entry)-1] == ':' &&
+           STRLEN keylen = HeKLEN(entry);
+            const char * const key = HeKEY(entry);
+
+           if (keylen >= 2 && key[keylen-2] == ':'  && key[keylen-1] == ':' &&
                (gv = MUTABLE_GV(HeVAL(entry))) && isGV(gv) && (hv = GvHV(gv)))
            {
                if (hv != PL_defstash && hv != stash
@@ -2288,8 +2509,12 @@ Perl_gv_check(pTHX_ HV *stash)
                 )
                     gv_check(hv);              /* nested package */
            }
-            else if ( *HeKEY(entry) != '_'
-                        && isIDFIRST_lazy_if(HeKEY(entry), HeUTF8(entry)) ) {
+            else if (   HeKLEN(entry) != 0
+                     && *HeKEY(entry) != '_'
+                     && isIDFIRST_lazy_if_safe(HeKEY(entry),
+                                               HeKEY(entry) + HeKLEN(entry),
+                                               HeUTF8(entry)) )
+            {
                 const char *file;
                gv = MUTABLE_GV(HeVAL(entry));
                if (SvTYPE(gv) != SVt_PVGV || GvMULTI(gv))
@@ -2303,7 +2528,7 @@ Perl_gv_check(pTHX_ HV *stash)
                    = gv_fetchfile_flags(file, HEK_LEN(GvFILE_HEK(gv)), 0);
 #endif
                Perl_warner(aTHX_ packWARN(WARN_ONCE),
-                       "Name \"%"HEKf"::%"HEKf
+                       "Name \"%" HEKf "::%" HEKf
                        "\" used only once: possible typo",
                             HEKfARG(HvNAME_HEK(stash)),
                             HEKfARG(GvNAME_HEK(gv)));
@@ -2316,11 +2541,10 @@ Perl_gv_check(pTHX_ HV *stash)
 GV *
 Perl_newGVgen_flags(pTHX_ const char *pack, U32 flags)
 {
-    dVAR;
     PERL_ARGS_ASSERT_NEWGVGEN_FLAGS;
     assert(!(flags & ~SVf_UTF8));
 
-    return gv_fetchpv(Perl_form(aTHX_ "%"UTF8f"::_GEN_%ld",
+    return gv_fetchpv(Perl_form(aTHX_ "%" UTF8f "::_GEN_%ld",
                                 UTF8fARG(flags, strlen(pack), pack),
                                 (long)PL_gensym++),
                       GV_ADD, SVt_PVGV);
@@ -2331,7 +2555,6 @@ Perl_newGVgen_flags(pTHX_ const char *pack, U32 flags)
 GP*
 Perl_gp_ref(pTHX_ GP *gp)
 {
-    dVAR;
     if (!gp)
        return NULL;
     gp->gp_refcnt++;
@@ -2351,7 +2574,6 @@ Perl_gp_ref(pTHX_ GP *gp)
 void
 Perl_gp_free(pTHX_ GV *gv)
 {
-    dVAR;
     GP* gp;
     int attempts = 100;
 
@@ -2400,11 +2622,24 @@ Perl_gp_free(pTHX_ GV *gv)
          Somehow gp->gp_hv can end up pointing at freed garbage.  */
       if (hv && SvTYPE(hv) == SVt_PVHV) {
         const HEK *hvname_hek = HvNAME_HEK(hv);
-        DEBUG_o(Perl_deb(aTHX_ "gp_free clearing PL_stashcache for '%"HEKf"'\n", hvname_hek));
-        if (PL_stashcache && hvname_hek)
+        if (PL_stashcache && hvname_hek) {
+           DEBUG_o(Perl_deb(aTHX_
+                          "gp_free clearing PL_stashcache for '%" HEKf "'\n",
+                           HEKfARG(hvname_hek)));
            (void)hv_deletehek(PL_stashcache, hvname_hek, G_DISCARD);
+        }
        SvREFCNT_dec(hv);
       }
+      if (io && SvREFCNT(io) == 1 && IoIFP(io)
+            && (IoTYPE(io) == IoTYPE_WRONLY ||
+                IoTYPE(io) == IoTYPE_RDWR   ||
+                IoTYPE(io) == IoTYPE_APPEND)
+            && ckWARN_d(WARN_IO)
+            && IoIFP(io) != PerlIO_stdin()
+            && IoIFP(io) != PerlIO_stdout()
+            && IoIFP(io) != PerlIO_stderr()
+            && !(IoFLAGS(io) & IOf_FAKE_DIRP))
+       io_close(io, gv, FALSE, TRUE);
       SvREFCNT_dec(io);
       SvREFCNT_dec(cv);
       SvREFCNT_dec(form);
@@ -2465,7 +2700,6 @@ Perl_magic_freeovrld(pTHX_ SV *sv, MAGIC *mg)
 int
 Perl_Gv_AMupdate(pTHX_ HV *stash, bool destructing)
 {
-  dVAR;
   MAGIC* const mg = mg_find((const SV *)stash, PERL_MAGIC_overload_table);
   AMT amt;
   const struct mro_meta* stash_meta = HvMROMETA(stash);
@@ -2545,18 +2779,21 @@ Perl_Gv_AMupdate(pTHX_ HV *stash, bool destructing)
           numifying instead of C's "+0". */
        gv = Perl_gv_fetchmeth_pvn(aTHX_ stash, cooky, l, -1, 0);
         cv = 0;
-        if (gv && (cv = GvCV(gv))) {
-           if(GvNAMELEN(CvGV(cv)) == 3 && strEQ(GvNAME(CvGV(cv)), "nil")){
-             const char * const hvname = HvNAME_get(GvSTASH(CvGV(cv)));
-             if (hvname && HEK_LEN(HvNAME_HEK(GvSTASH(CvGV(cv)))) == 8
-              && strEQ(hvname, "overload")) {
+        if (gv && (cv = GvCV(gv)) && CvHASGV(cv)) {
+            const HEK * const gvhek =
+                CvNAMED(cv) ? CvNAME_HEK(cv) : GvNAME_HEK(CvGV(cv));
+            const HEK * const stashek =
+                HvNAME_HEK(CvNAMED(cv) ? CvSTASH(cv) : GvSTASH(CvGV(cv)));
+            if (HEK_LEN(gvhek) == 3 && strEQ(HEK_KEY(gvhek), "nil")
+             && stashek && HEK_LEN(stashek) == 8
+             && strEQ(HEK_KEY(stashek), "overload")) {
                /* This is a hack to support autoloading..., while
                   knowing *which* methods were declared as overloaded. */
                /* GvSV contains the name of the method. */
                GV *ngv = NULL;
                SV *gvsv = GvSV(gv);
 
-               DEBUG_o( Perl_deb(aTHX_ "Resolving method \"%"SVf256\
+               DEBUG_o( Perl_deb(aTHX_ "Resolving method \"%" SVf256\
                        "\" for overloaded \"%s\" in package \"%.256s\"\n",
                             (void*)GvSV(gv), cp, HvNAME(stash)) );
                if (!gvsv || !SvPOK(gvsv)
@@ -2571,9 +2808,9 @@ Perl_Gv_AMupdate(pTHX_ HV *stash, bool destructing)
                                                     ? gvsv
                                                     : newSVpvs_flags("???", SVs_TEMP);
                        /* diag_listed_as: Can't resolve method "%s" overloading "%s" in package "%s" */
-                       Perl_croak(aTHX_ "%s method \"%"SVf256
+                       Perl_croak(aTHX_ "%s method \"%" SVf256
                                    "\" overloading \"%s\" "\
-                                   "in package \"%"HEKf256"\"",
+                                   "in package \"%" HEKf256 "\"",
                                   (GvCVGEN(gv) ? "Stub found while resolving"
                                    : "Can't resolve"),
                                   SVfARG(name), cp,
@@ -2583,7 +2820,6 @@ Perl_Gv_AMupdate(pTHX_ HV *stash, bool destructing)
                    }
                }
                cv = GvCV(gv = ngv);
-             }
            }
            DEBUG_o( Perl_deb(aTHX_ "Overloading \"%s\" in package \"%.256s\" via \"%.256s::%.256s\"\n",
                         cp, HvNAME_get(stash), HvNAME_get(GvSTASH(CvGV(cv))),
@@ -2633,7 +2869,6 @@ Perl_Gv_AMupdate(pTHX_ HV *stash, bool destructing)
 CV*
 Perl_gv_handler(pTHX_ HV *stash, I32 id)
 {
-    dVAR;
     MAGIC *mg;
     AMT *amtp;
     U32 newgen;
@@ -2685,7 +2920,6 @@ Perl_gv_handler(pTHX_ HV *stash, I32 id)
 
 bool
 Perl_try_amagic_un(pTHX_ int method, int flags) {
-    dVAR;
     dSP;
     SV* tmpsv;
     SV* const arg = TOPs;
@@ -2693,7 +2927,9 @@ Perl_try_amagic_un(pTHX_ int method, int flags) {
     SvGETMAGIC(arg);
 
     if (SvAMAGIC(arg) && (tmpsv = amagic_call(arg, &PL_sv_undef, method,
-                                             AMGf_noright | AMGf_unary))) {
+                                             AMGf_noright | AMGf_unary
+                                           | (flags & AMGf_numarg))))
+    {
        if (flags & AMGf_set) {
            SETs(tmpsv);
        }
@@ -2728,7 +2964,6 @@ Perl_try_amagic_un(pTHX_ int method, int flags) {
 
 bool
 Perl_try_amagic_bin(pTHX_ int method, int flags) {
-    dVAR;
     dSP;
     SV* const left = TOPm1s;
     SV* const right = TOPs;
@@ -2739,7 +2974,8 @@ Perl_try_amagic_bin(pTHX_ int method, int flags) {
 
     if (SvAMAGIC(left) || SvAMAGIC(right)) {
        SV * const tmpsv = amagic_call(left, right, method,
-                   ((flags & AMGf_assign) && opASSIGN ? AMGf_assign: 0));
+                   ((flags & AMGf_assign) && opASSIGN ? AMGf_assign: 0)
+                 | (flags & AMGf_numarg));
        if (tmpsv) {
            if (flags & AMGf_set) {
                (void)POPs;
@@ -2970,7 +3206,7 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
         case regexp_amg:
             /* FAIL safe */
             return NULL;       /* Delegate operation to standard mechanisms. */
-            break;
+
         case to_sv_amg:
         case to_av_amg:
         case to_hv_amg:
@@ -2978,7 +3214,7 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
         case to_cv_amg:
             /* FAIL safe */
             return left;       /* Delegate operation to standard mechanisms. */
-            break;
+
         default:
           goto not_found;
         }
@@ -3045,7 +3281,6 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
         case to_cv_amg:
             /* FAIL safe */
             return left;       /* Delegate operation to standard mechanisms. */
-            break;
       }
       if (ocvp && (cv=ocvp[nomethod_amg])) { /* Call report method */
        notfound = 1; lr = -1;
@@ -3061,7 +3296,7 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
        SV *msg;
        if (off==-1) off=method;
        msg = sv_2mortal(Perl_newSVpvf(aTHX_
-                     "Operation \"%s\": no method found,%sargument %s%"SVf"%s%"SVf,
+                     "Operation \"%s\": no method found,%sargument %s%" SVf "%s%" SVf,
                      AMG_id2name(method + assignshift),
                      (flags & AMGf_unary ? " " : "\n\tleft "),
                      SvAMAGIC(left)?
@@ -3079,9 +3314,9 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
                        SVfARG(sv_2mortal(newSVhek(HvNAME_HEK(SvSTASH(SvRV(right)))))):
                        SVfARG(&PL_sv_no)));
         if (use_default_op) {
-         DEBUG_o( Perl_deb(aTHX_ "%"SVf, SVfARG(msg)) );
+         DEBUG_o( Perl_deb(aTHX_ "%" SVf, SVfARG(msg)) );
        } else {
-         Perl_croak(aTHX_ "%"SVf, SVfARG(msg));
+         Perl_croak(aTHX_ "%" SVf, SVfARG(msg));
        }
        return NULL;
       }
@@ -3119,6 +3354,9 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
     case band_amg:
     case bor_amg:
     case bxor_amg:
+    case sband_amg:
+    case sbor_amg:
+    case sbxor_amg:
       if (assign)
         force_scalar = 1;
       break;
@@ -3149,7 +3387,7 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
 #ifdef DEBUGGING
   if (!notfound) {
     DEBUG_o(Perl_deb(aTHX_
-                    "Overloaded operator \"%s\"%s%s%s:\n\tmethod%s found%s in package %"SVf"%s\n",
+                    "Overloaded operator \"%s\"%s%s%s:\n\tmethod%s found%s in package %" SVf "%s\n",
                     AMG_id2name(off),
                     method+assignshift==off? "" :
                     " (initially \"",
@@ -3206,7 +3444,7 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
     SV* res;
     const bool oldcatch = CATCH_GET;
     I32 oldmark, nret;
-    int gimme = force_scalar ? G_SCALAR : GIMME_V;
+    U8 gimme = force_scalar ? G_SCALAR : GIMME_V;
 
     CATCH_SET(TRUE);
     Zero(&myop, 1, BINOP);
@@ -3245,6 +3483,10 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
       PUSHs(newSVpvn_flags(AMG_id2name(method + assignshift),
                           AMG_id2namelen(method + assignshift), SVs_TEMP));
     }
+    else if (flags & AMGf_numarg)
+      PUSHs(&PL_sv_undef);
+    if (flags & AMGf_numarg)
+      PUSHs(&PL_sv_yes);
     PUSHs(MUTABLE_SV(cv));
     PUTBACK;
     oldmark = TOPMARK;
@@ -3332,7 +3574,7 @@ Perl_gv_name_set(pTHX_ GV *gv, const char *name, U32 len, U32 flags)
     PERL_ARGS_ASSERT_GV_NAME_SET;
 
     if (len > I32_MAX)
-       Perl_croak(aTHX_ "panic: gv name too long (%"UVuf")", (UV) len);
+       Perl_croak(aTHX_ "panic: gv name too long (%" UVuf ")", (UV) len);
 
     if (!(flags & GV_ADD) && GvNAME_HEK(gv)) {
        unshare_hek(GvNAME_HEK(gv));
@@ -3400,7 +3642,7 @@ Perl_gv_try_downgrade(pTHX_ GV *gv)
        (void)hv_deletehek(stash, gvnhek, G_DISCARD);
     } else if (GvMULTI(gv) && cv && SvREFCNT(cv) == 1 &&
            !SvOBJECT(cv) && !SvMAGICAL(cv) && !SvREADONLY(cv) &&
-           CvSTASH(cv) == stash && CvGV(cv) == gv &&
+           CvSTASH(cv) == stash && !CvNAMED(cv) && CvGV(cv) == gv &&
            CvCONST(cv) && !CvMETHOD(cv) && !CvLVALUE(cv) && !CvUNIQUE(cv) &&
            !CvNODEBUG(cv) && !CvCLONE(cv) && !CvCLONED(cv) && !CvANON(cv) &&
            (namehek = GvNAME_HEK(gv)) &&
@@ -3412,6 +3654,8 @@ Perl_gv_try_downgrade(pTHX_ GV *gv)
        sv_clear((SV*)gv);
        SvREFCNT(gv) = 1;
        SvFLAGS(gv) = SVt_IV|SVf_ROK|SVprv_PCS_IMPORTED * imported;
+
+        /* See also: 'SET_SVANY_FOR_BODYLESS_IV' in sv.c */
        SvANY(gv) = (XPVGV*)((char*)&(gv->sv_u.svu_iv) -
                                STRUCT_OFFSET(XPVIV, xiv_iv));
        SvRV_set(gv, value);
@@ -3446,11 +3690,5 @@ core_xsub(pTHX_ CV* cv)
 }
 
 /*
- * Local variables:
- * c-indentation-style: bsd
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
  * ex: set ts=8 sts=4 sw=4 et:
  */