This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #78088] [PATCH] Upgrade to threads 1.81
[perl5.git] / gv.c
diff --git a/gv.c b/gv.c
index 2d4cebc..11f82a2 100644 (file)
--- a/gv.c
+++ b/gv.c
@@ -45,7 +45,13 @@ Perl_gv_add_by_type(pTHX_ GV *gv, svtype type)
 {
     SV **where;
 
-    if (!gv || SvTYPE((const SV *)gv) != SVt_PVGV) {
+    if (
+        !gv
+     || (
+            SvTYPE((const SV *)gv) != SVt_PVGV
+         && SvTYPE((const SV *)gv) != SVt_PVLV
+        )
+    ) {
        const char *what;
        if (type == SVt_PVIO) {
            /*
@@ -121,9 +127,9 @@ Perl_gv_fetchfile_flags(pTHX_ const char *const name, const STRLEN namelen,
 #else
        sv_setpvn(GvSV(gv), name, namelen);
 #endif
-       if (PERLDB_LINE || PERLDB_SAVESRC)
-           hv_magic(GvHVn(gv_AVadd(gv)), NULL, PERL_MAGIC_dbfile);
     }
+    if ((PERLDB_LINE || PERLDB_SAVESRC) && !GvAV(gv))
+           hv_magic(GvHVn(gv_AVadd(gv)), NULL, PERL_MAGIC_dbfile);
     if (tmpbuf != smallbuf)
        Safefree(tmpbuf);
     return gv;
@@ -193,6 +199,43 @@ Perl_newGP(pTHX_ GV *const gv)
     return gp;
 }
 
+/* Assign CvGV(cv) = gv, handling weak references.
+ * See also S_anonymise_cv_maybe */
+
+void
+Perl_cvgv_set(pTHX_ CV* cv, GV* gv)
+{
+    GV * const oldgv = CvGV(cv);
+    PERL_ARGS_ASSERT_CVGV_SET;
+
+    if (oldgv == gv)
+       return;
+
+    if (oldgv) {
+       if (CvCVGV_RC(cv)) {
+           SvREFCNT_dec(oldgv);
+           CvCVGV_RC_off(cv);
+       }
+       else {
+           sv_del_backref(MUTABLE_SV(oldgv), MUTABLE_SV(cv));
+       }
+    }
+
+    SvANY(cv)->xcv_gv = gv;
+    assert(!CvCVGV_RC(cv));
+
+    if (!gv)
+       return;
+
+    if (isGV_with_GP(gv) && GvGP(gv) && (GvCV(gv) == cv || GvFORM(gv) == cv))
+       Perl_sv_add_backref(aTHX_ MUTABLE_SV(gv), MUTABLE_SV(cv));
+    else {
+       CvCVGV_RC_on(cv);
+       SvREFCNT_inc_simple_void_NN(gv);
+    }
+}
+
+
 void
 Perl_gv_init(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len, int multi)
 {
@@ -248,10 +291,20 @@ Perl_gv_init(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len, int multi)
     if (multi || doproto)              /* doproto means it _was_ mentioned */
        GvMULTI_on(gv);
     if (doproto) {                     /* Replicate part of newSUB here. */
+       CV *cv;
        ENTER;
        if (has_constant) {
+           char *name0 = NULL;
+           if (name[len])
+               /* newCONSTSUB doesn't take a len arg, so make sure we
+                * give it a \0-terminated string */
+               name0 = savepvn(name,len);
+
            /* newCONSTSUB takes ownership of the reference from us.  */
-           GvCV(gv) = newCONSTSUB(stash, name, has_constant);
+           cv = newCONSTSUB(stash, (name0 ? name0 : name), has_constant);
+           assert(GvCV(gv) == cv); /* newCONSTSUB should have set this */
+           if (name0)
+               Safefree(name0);
            /* If this reference was a copy of another, then the subroutine
               must have been "imported", by a Perl space assignment to a GV
               from a reference to CV.  */
@@ -259,16 +312,19 @@ Perl_gv_init(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len, int multi)
                GvIMPORTED_CV_on(gv);
        } else {
            (void) start_subparse(0,0); /* Create empty CV in compcv. */
-           GvCV(gv) = PL_compcv;
+           cv = PL_compcv;
+           GvCV(gv) = cv;
        }
        LEAVE;
 
         mro_method_changed_in(GvSTASH(gv)); /* sub Foo::bar($) { (shift) } sub ASDF::baz($); *ASDF::baz = \&Foo::bar */
-       CvGV(GvCV(gv)) = gv;
-       CvFILE_set_from_cop(GvCV(gv), PL_curcop);
-       CvSTASH(GvCV(gv)) = PL_curstash;
+       CvGV_set(cv, gv);
+       CvFILE_set_from_cop(cv, PL_curcop);
+       CvSTASH(cv) = PL_curstash;
+       if (PL_curstash)
+           Perl_sv_add_backref(aTHX_ MUTABLE_SV(PL_curstash), MUTABLE_SV(cv));
        if (proto) {
-           sv_usepvn_flags(MUTABLE_SV(GvCV(gv)), proto, protolen,
+           sv_usepvn_flags(MUTABLE_SV(cv), proto, protolen,
                            SV_HAS_TRAILING_NUL);
        }
     }
@@ -740,6 +796,8 @@ Perl_gv_autoload4(pTHX_ HV *stash, const char *name, STRLEN len, I32 method)
          * pass along the same data via some unused fields in the CV
          */
         CvSTASH(cv) = stash;
+       if (stash)
+           Perl_sv_add_backref(aTHX_ MUTABLE_SV(stash), MUTABLE_SV(cv));
         SvPV_set(cv, (char *)name); /* cast to lose constness warning */
         SvCUR_set(cv, len);
         return gv;
@@ -911,6 +969,46 @@ Perl_gv_fetchsv(pTHX_ SV *name, I32 flags, const svtype sv_type) {
     return gv_fetchpvn_flags(nambeg, len, flags | SvUTF8(name), sv_type);
 }
 
+STATIC void
+S_gv_magicalize_isa(pTHX_ GV *gv, const char *nambeg, I32 add)
+{
+    AV* av;
+
+    PERL_ARGS_ASSERT_GV_MAGICALIZE_ISA;
+
+    av = GvAVn(gv);
+    GvMULTI_on(gv);
+    sv_magic(MUTABLE_SV(av), MUTABLE_SV(gv), PERL_MAGIC_isa,
+            NULL, 0);
+    /* NOTE: No support for tied ISA */
+    if ((add & GV_ADDMULTI) && strEQ(nambeg,"AnyDBM_File::ISA")
+       && AvFILLp(av) == -1)
+       {
+           av_push(av, newSVpvs("NDBM_File"));
+           gv_stashpvs("NDBM_File", GV_ADD);
+           av_push(av, newSVpvs("DB_File"));
+           gv_stashpvs("DB_File", GV_ADD);
+           av_push(av, newSVpvs("GDBM_File"));
+           gv_stashpvs("GDBM_File", GV_ADD);
+           av_push(av, newSVpvs("SDBM_File"));
+           gv_stashpvs("SDBM_File", GV_ADD);
+           av_push(av, newSVpvs("ODBM_File"));
+           gv_stashpvs("ODBM_File", GV_ADD);
+       }
+}
+
+STATIC void
+S_gv_magicalize_overload(pTHX_ GV *gv)
+{
+    HV* hv;
+
+    PERL_ARGS_ASSERT_GV_MAGICALIZE_OVERLOAD;
+
+    hv = GvHVn(gv);
+    GvMULTI_on(gv);
+    hv_magic(hv, NULL, PERL_MAGIC_overload);
+}
+
 GV *
 Perl_gv_fetchpvn_flags(pTHX_ const char *nambeg, STRLEN full_len, I32 flags,
                       const svtype sv_type)
@@ -1152,7 +1250,32 @@ Perl_gv_fetchpvn_flags(pTHX_ const char *nambeg, STRLEN full_len, I32 flags,
         GvMULTI_on(gv) ;
 
     /* set up magic where warranted */
-    if (len > 1) {
+    if (stash != PL_defstash) { /* not the main stash */
+       /* We only have to check for four names here: EXPORT, ISA, OVERLOAD
+          and VERSION. All the others apply only to the main stash. */
+       if (len > 1) {
+           const char * const name2 = name + 1;
+           switch (*name) {
+           case 'E':
+               if (strnEQ(name2, "XPORT", 5))
+                   GvMULTI_on(gv);
+               break;
+           case 'I':
+               if (strEQ(name2, "SA"))
+                   gv_magicalize_isa(gv, nambeg, add);
+               break;
+           case 'O':
+               if (strEQ(name2, "VERLOAD"))
+                   gv_magicalize_overload(gv);
+               break;
+           case 'V':
+               if (strEQ(name2, "ERSION"))
+                   GvMULTI_on(gv);
+               break;
+           }
+       }
+    }
+    else if (len > 1) {
 #ifndef EBCDIC
        if (*name > 'V' ) {
            NOOP;
@@ -1179,32 +1302,12 @@ Perl_gv_fetchpvn_flags(pTHX_ const char *nambeg, STRLEN full_len, I32 flags,
                break;
            case 'I':
                if (strEQ(name2, "SA")) {
-                   AV* const av = GvAVn(gv);
-                   GvMULTI_on(gv);
-                   sv_magic(MUTABLE_SV(av), MUTABLE_SV(gv), PERL_MAGIC_isa,
-                            NULL, 0);
-                   /* NOTE: No support for tied ISA */
-                   if ((add & GV_ADDMULTI) && strEQ(nambeg,"AnyDBM_File::ISA")
-                       && AvFILLp(av) == -1)
-                       {
-                           av_push(av, newSVpvs("NDBM_File"));
-                           gv_stashpvs("NDBM_File", GV_ADD);
-                           av_push(av, newSVpvs("DB_File"));
-                           gv_stashpvs("DB_File", GV_ADD);
-                           av_push(av, newSVpvs("GDBM_File"));
-                           gv_stashpvs("GDBM_File", GV_ADD);
-                           av_push(av, newSVpvs("SDBM_File"));
-                           gv_stashpvs("SDBM_File", GV_ADD);
-                           av_push(av, newSVpvs("ODBM_File"));
-                           gv_stashpvs("ODBM_File", GV_ADD);
-                       }
+                   gv_magicalize_isa(gv, nambeg, add);
                }
                break;
            case 'O':
                if (strEQ(name2, "VERLOAD")) {
-                   HV* const hv = GvHVn(gv);
-                   GvMULTI_on(gv);
-                   hv_magic(hv, NULL, PERL_MAGIC_overload);
+                   gv_magicalize_overload(gv);
                }
                break;
            case 'S':
@@ -2491,12 +2594,22 @@ Perl_gv_try_downgrade(pTHX_ GV *gv)
     SV **gvp;
     PERL_ARGS_ASSERT_GV_TRY_DOWNGRADE;
     if (!(SvREFCNT(gv) == 1 && SvTYPE(gv) == SVt_PVGV && !SvFAKE(gv) &&
-           !SvOBJECT(gv) && !SvMAGICAL(gv) && !SvREADONLY(gv) &&
+           !SvOBJECT(gv) && !SvREADONLY(gv) &&
            isGV_with_GP(gv) && GvGP(gv) &&
            !GvINTRO(gv) && GvREFCNT(gv) == 1 &&
            !GvSV(gv) && !GvAV(gv) && !GvHV(gv) && !GvIOp(gv) && !GvFORM(gv) &&
            GvEGVx(gv) == gv && (stash = GvSTASH(gv))))
        return;
+    if (SvMAGICAL(gv)) {
+        MAGIC *mg;
+       /* only backref magic is allowed */
+       if (SvGMAGICAL(gv) || SvSMAGICAL(gv))
+           return;
+        for (mg = SvMAGIC(gv); mg; mg = mg->mg_moremagic) {
+            if (mg->mg_type != PERL_MAGIC_backref)
+                return;
+       }
+    }
     cv = GvCV(gv);
     if (!cv) {
        HEK *gvnhek = GvNAME_HEK(gv);