}
sv = sv_newmortal();
- mg_copy((SV*)av, sv, 0, key);
- PL_av_fetch_sv = sv;
- return &PL_av_fetch_sv;
+ sv_upgrade(sv, SVt_PVLV);
+ mg_copy((SV*)av, sv, 0, key);
+ LvTYPE(sv) = 't';
+ LvTARG(sv) = sv; /* fake (SV**) */
+ return &(LvTARG(sv));
}
}
Perl_dump_indent(aTHX_ level, file, " TARGOFF = %"IVdf"\n", (IV)LvTARGOFF(sv));
Perl_dump_indent(aTHX_ level, file, " TARGLEN = %"IVdf"\n", (IV)LvTARGLEN(sv));
Perl_dump_indent(aTHX_ level, file, " TARG = 0x%"UVxf"\n", PTR2UV(LvTARG(sv)));
- /* XXX level+1 ??? */
- do_sv_dump(level, file, LvTARG(sv), nest+1, maxnest, dumpops, pvlim);
+ if (LvTYPE(sv) != 't' && LvTYPE(sv) != 'T')
+ do_sv_dump(level+1, file, LvTARG(sv), nest+1, maxnest,
+ dumpops, pvlim);
break;
case SVt_PVAV:
Perl_dump_indent(aTHX_ level, file, " ARRAY = 0x%"UVxf, PTR2UV(AvARRAY(sv)));
s |CV* |cv_clone2 |CV *proto|CV *outside
#endif
pd |CV* |find_runcv |U32 *db_seqp
+p |void |free_tied_hv_pool
#ifdef PERL_CORE
#define find_runcv Perl_find_runcv
#endif
+#ifdef PERL_CORE
+#define free_tied_hv_pool Perl_free_tied_hv_pool
+#endif
#define ck_anoncode Perl_ck_anoncode
#define ck_bitop Perl_ck_bitop
#define ck_concat Perl_ck_concat
#ifdef PERL_CORE
#define find_runcv(a) Perl_find_runcv(aTHX_ a)
#endif
+#ifdef PERL_CORE
+#define free_tied_hv_pool() Perl_free_tied_hv_pool(aTHX)
+#endif
#define ck_anoncode(a) Perl_ck_anoncode(aTHX_ a)
#define ck_bitop(a) Perl_ck_bitop(aTHX_ a)
#define ck_concat(a) Perl_ck_concat(aTHX_ a)
#define PL_Sv (vTHX->TSv)
#define PL_Xpv (vTHX->TXpv)
-#define PL_av_fetch_sv (vTHX->Tav_fetch_sv)
#define PL_bodytarget (vTHX->Tbodytarget)
#define PL_bostr (vTHX->Tbostr)
#define PL_chopset (vTHX->Tchopset)
#define PL_firstgv (vTHX->Tfirstgv)
#define PL_formtarget (vTHX->Tformtarget)
#define PL_hv_fetch_ent_mh (vTHX->Thv_fetch_ent_mh)
-#define PL_hv_fetch_sv (vTHX->Thv_fetch_sv)
#define PL_in_eval (vTHX->Tin_eval)
#define PL_last_in_gv (vTHX->Tlast_in_gv)
#define PL_lastgotoprobe (vTHX->Tlastgotoprobe)
#define PL_TSv PL_Sv
#define PL_TXpv PL_Xpv
-#define PL_Tav_fetch_sv PL_av_fetch_sv
#define PL_Tbodytarget PL_bodytarget
#define PL_Tbostr PL_bostr
#define PL_Tchopset PL_chopset
#define PL_Tfirstgv PL_firstgv
#define PL_Tformtarget PL_formtarget
#define PL_Thv_fetch_ent_mh PL_hv_fetch_ent_mh
-#define PL_Thv_fetch_sv PL_hv_fetch_sv
#define PL_Tin_eval PL_in_eval
#define PL_Tlast_in_gv PL_last_in_gv
#define PL_Tlastgotoprobe PL_lastgotoprobe
%dump = (
'SCALAR' => 'dump_scalar',
+ 'LVALUE' => 'dump_scalar',
'ARRAY' => 'dump_array',
'HASH' => 'dump_hash',
'REF' => 'dump_ref',
return hek;
}
+/* free the pool of temporary HE/HEK pairs retunrned by hv_fetch_ent
+ * for tied hashes */
+
+void
+Perl_free_tied_hv_pool(pTHX)
+{
+ HE *ohe;
+ HE *he = PL_hv_fetch_ent_mh;
+ while (he) {
+ Safefree(HeKEY_hek(he));
+ ohe = he;
+ he = HeNEXT(he);
+ del_HE(ohe);
+ }
+}
+
#if defined(USE_ITHREADS)
HE *
Perl_he_dup(pTHX_ HE *e, bool shared, CLONE_PARAMS* param)
ptr_table_store(PL_ptr_table, e, ret);
HeNEXT(ret) = he_dup(HeNEXT(e),shared, param);
- if (HeKLEN(e) == HEf_SVKEY)
+ if (HeKLEN(e) == HEf_SVKEY) {
+ char *k;
+ New(54, k, HEK_BASESIZE + sizeof(SV*), char);
+ HeKEY_hek(ret) = (HEK*)k;
HeKEY_sv(ret) = SvREFCNT_inc(sv_dup(HeKEY_sv(e), param));
+ }
else if (shared)
HeKEY_hek(ret) = share_hek_flags(HeKEY(e), HeKLEN(e), HeHASH(e),
HeKFLAGS(e));
*/
if (mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv)) {
sv = sv_newmortal();
+ sv_upgrade(sv, SVt_PVLV);
mg_copy((SV*)hv, sv, key, klen);
if (flags & HVhek_FREEKEY)
Safefree(key);
- PL_hv_fetch_sv = sv;
- return &PL_hv_fetch_sv;
+ LvTYPE(sv) = 't';
+ LvTARG(sv) = sv; /* fake (SV**) */
+ return &(LvTARG(sv));
}
#ifdef ENV_IS_CASELESS
else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
if (SvRMAGICAL(hv)) {
if (mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv)) {
sv = sv_newmortal();
- keysv = sv_2mortal(newSVsv(keysv));
+ keysv = newSVsv(keysv);
mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
- if (!HeKEY_hek(&PL_hv_fetch_ent_mh)) {
+ /* grab a fake HE/HEK pair from the pool or make a new one */
+ entry = PL_hv_fetch_ent_mh;
+ if (entry)
+ PL_hv_fetch_ent_mh = HeNEXT(entry);
+ else {
char *k;
+ entry = new_HE();
New(54, k, HEK_BASESIZE + sizeof(SV*), char);
- HeKEY_hek(&PL_hv_fetch_ent_mh) = (HEK*)k;
+ HeKEY_hek(entry) = (HEK*)k;
}
- HeSVKEY_set(&PL_hv_fetch_ent_mh, keysv);
- HeVAL(&PL_hv_fetch_ent_mh) = sv;
- return &PL_hv_fetch_ent_mh;
- }
+ HeNEXT(entry) = Nullhe;
+ HeSVKEY_set(entry, keysv);
+ HeVAL(entry) = sv;
+ sv_upgrade(sv, SVt_PVLV);
+ LvTYPE(sv) = 'T';
+ LvTARG(sv) = (SV*)entry; /* so we can free entry when freeing sv */
+ return entry;
+ }
#ifdef ENV_IS_CASELESS
else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
U32 i;
if (PL_reg_curpm)
Safefree(PL_reg_curpm);
Safefree(PL_reg_poscache);
- Safefree(HeKEY_hek(&PL_hv_fetch_ent_mh));
+ free_tied_hv_pool();
Safefree(PL_op_mask);
Safefree(PL_psig_ptr);
Safefree(PL_psig_name);
#define PL_Sv (*Perl_TSv_ptr(aTHX))
#undef PL_Xpv
#define PL_Xpv (*Perl_TXpv_ptr(aTHX))
-#undef PL_av_fetch_sv
-#define PL_av_fetch_sv (*Perl_Tav_fetch_sv_ptr(aTHX))
#undef PL_bodytarget
#define PL_bodytarget (*Perl_Tbodytarget_ptr(aTHX))
#undef PL_bostr
#define PL_formtarget (*Perl_Tformtarget_ptr(aTHX))
#undef PL_hv_fetch_ent_mh
#define PL_hv_fetch_ent_mh (*Perl_Thv_fetch_ent_mh_ptr(aTHX))
-#undef PL_hv_fetch_sv
-#define PL_hv_fetch_sv (*Perl_Thv_fetch_sv_ptr(aTHX))
#undef PL_in_eval
#define PL_in_eval (*Perl_Tin_eval_ptr(aTHX))
#undef PL_last_in_gv
STATIC CV* S_cv_clone2(pTHX_ CV *proto, CV *outside);
#endif
PERL_CALLCONV CV* Perl_find_runcv(pTHX_ U32 *db_seqp);
+PERL_CALLCONV void Perl_free_tied_hv_pool(pTHX);
s = "REF";
else
s = "SCALAR"; break;
- case SVt_PVLV: s = "LVALUE"; break;
+ case SVt_PVLV: s = SvROK(sv) ? "REF":"LVALUE"; break;
case SVt_PVAV: s = "ARRAY"; break;
case SVt_PVHV: s = "HASH"; break;
case SVt_PVCV: s = "CODE"; break;
av_undef((AV*)sv);
break;
case SVt_PVLV:
- SvREFCNT_dec(LvTARG(sv));
+ if (LvTYPE(sv) == 'T') { /* for tie: return HE to pool */
+ SvREFCNT_dec(HeKEY_sv((HE*)LvTARG(sv)));
+ HeNEXT((HE*)LvTARG(sv)) = PL_hv_fetch_ent_mh;
+ PL_hv_fetch_ent_mh = (HE*)LvTARG(sv);
+ }
+ else if (LvTYPE(sv) != 't') /* unless tie: unrefcnted fake SV** */
+ SvREFCNT_dec(LvTARG(sv));
goto freescalar;
case SVt_PVGV:
gp_free((GV*)sv);
return "REF";
else
return "SCALAR";
- case SVt_PVLV: return "LVALUE";
+ case SVt_PVLV: return SvROK(sv) ? "REF" : "LVALUE";
case SVt_PVAV: return "ARRAY";
case SVt_PVHV: return "HASH";
case SVt_PVCV: return "CODE";
Perl_rvpv_dup(aTHX_ dstr, sstr, param);
LvTARGOFF(dstr) = LvTARGOFF(sstr); /* XXX sometimes holds PMOP* when DEBUGGING */
LvTARGLEN(dstr) = LvTARGLEN(sstr);
- LvTARG(dstr) = sv_dup_inc(LvTARG(sstr), param);
+ if (LvTYPE(sstr) == 't') /* for tie: unrefcnted fake (SV**) */
+ LvTARG(dstr) = dstr;
+ else if (LvTYPE(sstr) == 'T') /* for tie: fake HE */
+ LvTARG(dstr) = (SV*)he_dup((HE*)LvTARG(sstr), 0, param);
+ else
+ LvTARG(dstr) = sv_dup_inc(LvTARG(sstr), param);
LvTYPE(dstr) = LvTYPE(sstr);
break;
case SVt_PVGV:
PL_protect = proto_perl->Tprotect;
#endif
PL_errors = sv_dup_inc(proto_perl->Terrors, param);
- PL_av_fetch_sv = Nullsv;
- PL_hv_fetch_sv = Nullsv;
- Zero(&PL_hv_fetch_ent_mh, 1, HE); /* XXX */
+ PL_hv_fetch_ent_mh = Nullhe;
PL_modcount = proto_perl->Tmodcount;
PL_lastgotoprobe = Nullop;
PL_dumpindent = proto_perl->Tdumpindent;
STRLEN xlv_targoff;
STRLEN xlv_targlen;
SV* xlv_targ;
- char xlv_type;
+ char xlv_type; /* k=keys .=pos x=substr v=vec /=join/re
+ * y=alem/helem/iter t=tie T=tied HE */
};
struct xpvgv {
print $a;
EXPECT
Tied variable freed while still in use at - line 6.
+########
+
+# [20020716.007] - nested FETCHES
+
+sub F1::TIEARRAY { bless [], 'F1' }
+sub F1::FETCH { 1 }
+my @f1;
+tie @f1, 'F1';
+
+sub F2::TIEARRAY { bless [2], 'F2' }
+sub F2::FETCH { my $self = shift; my $x = $f1[3]; $self }
+my @f2;
+tie @f2, 'F2';
+
+print $f2[4][0],"\n";
+
+sub F3::TIEHASH { bless [], 'F3' }
+sub F3::FETCH { 1 }
+my %f3;
+tie %f3, 'F3';
+
+sub F4::TIEHASH { bless [3], 'F4' }
+sub F4::FETCH { my $self = shift; my $x = $f3{3}; $self }
+my %f4;
+tie %f4, 'F4';
+
+print $f4{'foo'}[0],"\n";
+
+EXPECT
+2
+3
PERLVARI(Terrors, SV *, Nullsv) /* outstanding queued errors */
/* statics "owned" by various functions */
-PERLVAR(Tav_fetch_sv, SV *) /* owned by av_fetch() */
-PERLVAR(Thv_fetch_sv, SV *) /* owned by hv_fetch() */
-PERLVAR(Thv_fetch_ent_mh, HE) /* owned by hv_fetch_ent() */
+PERLVAR(Thv_fetch_ent_mh, HE*) /* owned by hv_fetch_ent() */
PERLVAR(Tmodcount, I32) /* how much mod()ification in assignment? */