actually, this isn't our fault, this is just generic 5.8 brokenness
[gitmo/Package-Stash-XS.git] / XS.xs
diff --git a/XS.xs b/XS.xs
index 2021e6d..ac75038 100644 (file)
--- a/XS.xs
+++ b/XS.xs
 #define GvCV_set(gv, cv) (GvCV(gv) = (CV*)(cv))
 #endif
 
+#ifndef MUTABLE_PTR
+#define MUTABLE_PTR(p) ((void *) (p))
+#endif
+
+#ifndef MUTABLE_SV
+#define MUTABLE_SV(p) ((SV *)MUTABLE_PTR(p))
+#endif
+
 #ifndef SVT_SCALAR
 #define SVT_SCALAR(svt) (svt <= SVt_PVLV)
 #endif
 } while (0)
 #define GvSetCV(g,v) do {               \
     SvREFCNT_dec(GvCV(g));              \
-    if ((GvCV_set(g, v))) {             \
+    if ((GvCV_set(g, (CV*)(v)))) {      \
         GvIMPORTED_CV_on(g);            \
         GvASSUMECV_on(g);               \
     }                                   \
@@ -324,18 +332,64 @@ static SV *_get_name(SV *self)
     return ret;
 }
 
+static void _real_gv_init(GV *gv, HV *stash, SV *name)
+{
+    char *name_pv;
+    STRLEN name_len;
+
+    name_pv = SvPV(name, name_len);
+    gv_init(gv, stash, name_pv, name_len, 1);
+
+    /* XXX: copied and pasted from gv_fetchpvn_flags and such */
+    /* ignoring the stuff for CORE:: and main:: for now, and also
+     * ignoring the GvMULTI_on bits, since we pass 1 to gv_init above */
+    switch (name_pv[0]) {
+        case 'I':
+            if (strEQ(&name_pv[1], "SA")) {
+                AV *av;
+
+                av = GvAVn(gv);
+                sv_magic(MUTABLE_SV(av), MUTABLE_SV(gv), PERL_MAGIC_isa,
+                        NULL, 0);
+            }
+            break;
+        case 'O':
+            if (strEQ(&name_pv[1], "VERLOAD")) {
+                HV *hv;
+
+                hv = GvHVn(gv);
+                hv_magic(hv, NULL, PERL_MAGIC_overload);
+            }
+            break;
+        default:
+            break;
+    }
+}
+
 static void _expand_glob(SV *self, SV *varname)
 {
-    SV *name;
+    HV *namespace;
+    HE *entry;
+    GV *glob;
 
-    name = newSVsv(_get_name(self));
-    sv_catpvs(name, "::");
-    sv_catsv(name, varname);
+    namespace = _get_namespace(self);
 
-    /* can't use gv_init here, because it screws up @ISA in a way that I
-     * can't reproduce, but that CMOP triggers */
-    gv_fetchsv(name, GV_ADD, SVt_NULL);
-    SvREFCNT_dec(name);
+    if (entry = hv_fetch_ent(namespace, varname, 0, 0)) {
+        glob = (GV*)HeVAL(entry);
+        if (isGV(glob)) {
+            croak("_expand_glob called on stash slot with expanded glob");
+        }
+        else {
+            SvREFCNT_inc(glob);
+            _real_gv_init(glob, namespace, varname);
+            if (!hv_store_ent(namespace, varname, (SV*)glob, 0)) {
+                croak("hv_store failed");
+            }
+        }
+    }
+    else {
+        croak("_expand_glob called on nonexistent stash slot");
+    }
 }
 
 static SV *_get_symbol(SV *self, varspec_t *variable, int vivify)
@@ -493,22 +547,19 @@ add_symbol(self, variable, initial=NULL, ...)
     varspec_t variable
     SV *initial
   PREINIT:
-    SV *name;
     GV *glob;
+    HV *namespace;
+    HE *entry;
   CODE:
     if (initial && !_valid_for_type(initial, variable.type))
         croak("%s is not of type %s",
               SvPV_nolen(initial), vartype_to_string(variable.type));
 
-    name = newSVsv(_get_name(self));
-    sv_catpvs(name, "::");
-    sv_catsv(name, variable.name);
-
     if (items > 2 && (PL_perldb & 0x10) && variable.type == VAR_CODE) {
         int i;
         char *filename = NULL;
         I32 first_line_num = -1, last_line_num = -1;
-        SV *dbval;
+        SV *dbval, *name;
         HV *dbsub;
 
         if ((items - 3) % 2)
@@ -544,6 +595,10 @@ add_symbol(self, variable, initial=NULL, ...)
         if (last_line_num == -1)
             last_line_num = first_line_num;
 
+        name = newSVsv(_get_name(self));
+        sv_catpvs(name, "::");
+        sv_catsv(name, variable.name);
+
         /* http://perldoc.perl.org/perldebguts.html#Debugger-Internals */
         dbsub = get_hv("DB::sub", 1);
         dbval = newSVpvf("%s:%d-%d", filename, first_line_num, last_line_num);
@@ -552,12 +607,25 @@ add_symbol(self, variable, initial=NULL, ...)
                  SvPV_nolen(name));
             SvREFCNT_dec(dbval);
         }
+
+        SvREFCNT_dec(name);
     }
 
     /* GV_ADDMULTI rather than GV_ADD because otherwise you get 'used only
      * once' warnings in some situations... i can't reproduce this, but CMOP
      * triggers it */
-    glob = gv_fetchsv(name, GV_ADDMULTI, vartype_to_svtype(variable.type));
+    namespace = _get_namespace(self);
+    entry = hv_fetch_ent(namespace, variable.name, 0, 0);
+    if (entry) {
+        glob = (GV*)HeVAL(entry);
+    }
+    else {
+        glob = (GV*)newSV(0);
+        _real_gv_init(glob, namespace, variable.name);
+        if (!hv_store_ent(namespace, variable.name, (SV*)glob, 0)) {
+            croak("hv_store failed");
+        }
+    }
 
     if (initial) {
         SV *val;
@@ -589,8 +657,6 @@ add_symbol(self, variable, initial=NULL, ...)
         }
     }
 
-    SvREFCNT_dec(name);
-
 void
 remove_glob(self, name)
     SV *self