sv_upgrade((SV*)gv, SVt_PVGV);
if (SvLEN(gv))
Safefree(SvPVX(gv));
- Newz(602,gp, 1, GP);
+ Newz(602, gp, 1, GP);
GvGP(gv) = gp_ref(gp);
- GvREFCNT(gv) = 1;
GvSV(gv) = NEWSV(72,0);
GvLINE(gv) = curcop->cop_line;
GvFILEGV(gv) = curcop->cop_filegv;
I32 level;
{
AV* av;
- GV* topgv = NULL;
+ GV* topgv;
GV* gv;
GV** gvp;
HV* lastchance;
if ((level > 100) || (level < -100))
croak("Recursive inheritance detected");
- gvp = (GV**)hv_fetch(stash, name, len, (level >= 0));
-
DEBUG_o( deb("Looking for method %s in package %s\n",name,HvNAME(stash)) );
- if (!gvp) goto recurse;
-
- topgv = *gvp;
- if (SvTYPE(topgv) != SVt_PVGV)
- gv_init(topgv, stash, name, len, TRUE);
- if (cv = GvCV(topgv)) {
- if (CvXSUB(cv) || CvROOT(cv) || CvGV(cv)) { /* Not deleted, possibly autoloaded. */
- if (GvCVGEN(topgv) >= sub_generation)
- return topgv; /* valid cached inheritance */
- if (!GvCVGEN(topgv)) { /* not an inheritance cache */
+ gvp = (GV**)hv_fetch(stash, name, len, (level >= 0));
+ if (!gvp)
+ topgv = Nullgv;
+ else {
+ topgv = *gvp;
+ if (SvTYPE(topgv) != SVt_PVGV)
+ gv_init(topgv, stash, name, len, TRUE);
+ if (cv = GvCV(topgv)) {
+ /* If genuine method or valid cache entry, use it */
+ if (!GvCVGEN(topgv) || GvCVGEN(topgv) >= sub_generation)
return topgv;
- }
+ /* Stale cached entry: junk it */
+ SvREFCNT_dec(cv);
+ GvCV(topgv) = cv = Nullcv;
+ GvCVGEN(topgv) = 0;
}
- /* stale cached entry, just junk it */
- SvREFCNT_dec(cv);
- GvCV(topgv) = cv = 0;
- GvCVGEN(topgv) = 0;
}
- /* Now cv = 0, and there is no cv in topgv. */
- recurse:
gvp = (GV**)hv_fetch(stash,"ISA",3,FALSE);
if (gvp && (gv = *gvp) != (GV*)&sv_undef && (av = GvAV(gv))) {
SV** svp = AvARRAY(av);
SvPVX(sv), HvNAME(stash));
continue;
}
- gv = gv_fetchmeth(basestash, name, len, level + (level >= 0 ? 1 : -1));
- if (gv && topgv) {
- GvCV(topgv) = GvCV(gv); /* cache the CV */
- GvCVGEN(topgv) = sub_generation; /* valid for now */
- SvREFCNT_inc(GvCV(gv));
- return gv;
- } else if (gv) return gv;
+ gv = gv_fetchmeth(basestash, name, len,
+ (level >= 0) ? level + 1 : level - 1);
+ if (gv)
+ goto gotcha;
}
}
- if ((level == 0) || (level == -1)) { /* topgv is present. */
+ if (level == 0 || level == -1) {
if (lastchance = gv_stashpvn("UNIVERSAL", 9, FALSE)) {
- if (gv = gv_fetchmeth(lastchance, name, len, level + (level >= 0 ? 1 : -1))) {
- GvCV(topgv) = GvCV(gv); /* cache the CV */
- GvCVGEN(topgv) = sub_generation; /* valid for now */
- SvREFCNT_inc(GvCV(gv));
+ if (gv = gv_fetchmeth(lastchance, name, len,
+ (level >= 0) ? level + 1 : level - 1)) {
+ gotcha:
+ /* Use topgv for cache only if it has no synonyms */
+ if (topgv && GvREFCNT(topgv) == 1) {
+ if (cv = GvCV(topgv))
+ SvREFCNT_dec(cv);
+ GvCV(topgv) = (CV*)SvREFCNT_inc(GvCV(gv));
+ GvCVGEN(topgv) = sub_generation;
+ }
return gv;
}
}
}
if (!gv) {
- CV* cv;
-
if (strEQ(name,"import"))
gv = (GV*)&sv_yes;
- else if (strNE(name, "AUTOLOAD")) {
- if (gv = gv_fetchmeth(stash, "AUTOLOAD", 8, 0)) {
- /* One more chance... */
- SV *tmpstr = sv_2mortal(newSVpv(HvNAME(stash),0));
- sv_catpvn(tmpstr,"::", 2);
- sv_catpvn(tmpstr, name, nend - name);
- cv = GvCV(gv);
- sv_setsv(GvSV(CvGV(cv)), tmpstr);
- SvTAINTED_off(GvSV(CvGV(cv)));
- }
- }
+ else
+ gv = gv_autoload(stash, name, nend - name);
}
+
+ return gv;
+}
+
+GV*
+gv_autoload(stash, name, len)
+HV* stash;
+char* name;
+STRLEN len;
+{
+ static char autoload[] = "AUTOLOAD";
+ static STRLEN autolen = 8;
+ GV* gv;
+ CV* cv;
+ HV* varstash;
+ GV* vargv;
+ SV* varsv;
+
+ if (len == autolen && strnEQ(name, autoload, autolen))
+ return Nullgv;
+ if (!(gv = gv_fetchmeth(stash, autoload, autolen, 0)))
+ return Nullgv;
+ cv = GvCV(gv);
+
+ /*
+ * Given &FOO::AUTOLOAD, set $FOO::AUTOLOAD to desired function name.
+ * The subroutine's original name may not be "AUTOLOAD", so we don't
+ * use that, but for lack of anything better we will use the sub's
+ * original package to look up $AUTOLOAD.
+ */
+ varstash = GvSTASH(CvGV(cv));
+ vargv = *(GV**)hv_fetch(varstash, autoload, autolen, TRUE);
+ if (!isGV(vargv))
+ gv_init(vargv, varstash, autoload, autolen, FALSE);
+ varsv = GvSV(vargv);
+ sv_setpv(varsv, HvNAME(stash));
+ sv_catpvn(varsv, "::", 2);
+ sv_catpvn(varsv, name, len);
+ SvTAINTED_off(varsv);
return gv;
}
case '\017':
case '\t':
case '\020':
+ case '\023':
case '\024':
case '\027':
if (len > 1)
break;
case ']':
if (len == 1) {
- SV *sv;
- sv = GvSV(gv);
+ SV *sv = GvSV(gv);
sv_upgrade(sv, SVt_PVNV);
sv_setpv(sv, patchlevel);
+ (void)sv_2nv(sv);
+ SvREADONLY_on(sv);
}
break;
}
GP* gp;
{
gp->gp_refcnt++;
+ if (gp->gp_cv) {
+ if (gp->gp_cvgen) {
+ /* multi-named GPs cannot be used for method cache */
+ SvREFCNT_dec(gp->gp_cv);
+ gp->gp_cv = Nullcv;
+ gp->gp_cvgen = 0;
+ }
+ else {
+ /* Adding a new name to a subroutine invalidates method cache */
+ sub_generation++;
+ }
+ }
return gp;
-
}
void
warn("Attempt to free unreferenced glob pointers");
return;
}
+ if (gp->gp_cv) {
+ /* Deleting the name of a subroutine invalidates method cache */
+ sub_generation++;
+ }
if (--gp->gp_refcnt > 0) {
if (gp->gp_egv == gv)
gp->gp_egv = 0;
AMT *amtp=mg ? (AMT*)mg->mg_ptr: NULL;
AMT amt;
- if (mg && (amtp=((AMT*)(mg->mg_ptr)))->was_ok_am == amagic_generation &&
- amtp->was_ok_sub == sub_generation)
+ if (mg && amtp->was_ok_am == amagic_generation
+ && amtp->was_ok_sub == sub_generation)
return AMT_AMAGIC(amtp);
if (amtp && AMT_AMAGIC(amtp)) { /* Have table. */
int i;
if ( cp = (char *)AMG_names[0] ) {
/* Try to find via inheritance. */
- gv = gv_fetchmeth(stash, "()", 2, 0); /* A cooky: "()". */
+ gv = gv_fetchmeth(stash, "()", 2, -1); /* A cookie: "()". */
if (gv) sv = GvSV(gv);
- if (!sv) /* Empty */;
+ if (!gv) goto no_table;
else if (SvTRUE(sv)) amt.fallback=AMGfallYES;
else if (SvOK(sv)) amt.fallback=AMGfallNEVER;
}
cv = 0;
cp = (char *)AMG_names[i];
- *buf = '('; /* A cooky: "(". */
+ *buf = '('; /* A cookie: "(". */
strcpy(buf + 1, cp);
DEBUG_o( deb("Checking overloading of `%s' in package `%.256s'\n",
cp, HvNAME(stash)) );
}
}
/* Here we have no table: */
+ no_table:
AMT_AMAGIC_off(&amt);
sv_magic((SV*)stash, 0, 'c', (char*)&amt, sizeof(AMTS));
return FALSE;
} else if (cvp && (cv=cvp[nomethod_amg])) {
notfound = 1; lr = 1;
} else {
- if (off==-1) off=method;
- sprintf(buf, "Operation `%s': no method found,\n\tleft argument %s%.256s,\n\tright argument %s%.256s",
+ if (off==-1) off=method;
+ sprintf(buf,
+ "Operation `%s': no method found,%sargument %s%.256s%s%.256s",
AMG_names[method + assignshift],
+ (flags & AMGf_unary ? " " : "\n\tleft "),
SvAMAGIC(left)?
"in overloaded package ":
"has no overloaded magic",
HvNAME(SvSTASH(SvRV(left))):
"",
SvAMAGIC(right)?
- "in overloaded package ":
- "has no overloaded magic",
+ ",\n\tright argument in overloaded package ":
+ (flags & AMGf_unary
+ ? ""
+ : ",\n\tright argument has no overloaded magic"),
SvAMAGIC(right)?
HvNAME(SvSTASH(SvRV(right))):
"");
}
}
if (!notfound) {
- DEBUG_o( deb("Overloaded operator `%s'%s%s%s:\n\tmethod%s found%s in package %.256s%s\n",
+ DEBUG_o( deb(
+ "Overloaded operator `%s'%s%s%s:\n\tmethod%s found%s in package %.256s%s\n",
AMG_names[off],
method+assignshift==off? "" :
" (initially `",