X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=autovivification.xs;h=a8367a0a961e07b2f0b8665f4dec351e0c92e12d;hb=212cf2f8511a55f57224f4e043d2328a1f840693;hp=688669372bcf96029dacc40cbd7b5efcee721eca;hpb=167a7d1ceb42868217cdc88690f5d565527b3d6c;p=perl%2Fmodules%2Fautovivification.git diff --git a/autovivification.xs b/autovivification.xs index 6886693..a8367a0 100644 --- a/autovivification.xs +++ b/autovivification.xs @@ -33,13 +33,10 @@ while (len > 0) \ (U) = ((U) << 8) | (B)[--len]; -STATIC SV *a_tag(pTHX_ UV bits) { -#define a_tag(B) a_tag(aTHX_ (B)) - SV *hint; +#if A_WORKAROUND_REQUIRE_PROPAGATION +STATIC UV a_require_tag(pTHX) { +#define a_require_tag() a_require_tag(aTHX) const PERL_SI *si; - UV requires = 0; - unsigned char buf[sizeof(UV) * 2]; - STRLEN len; for (si = PL_curstackinfo; si; si = si->si_prev) { I32 cxix; @@ -48,11 +45,24 @@ STATIC SV *a_tag(pTHX_ UV bits) { const PERL_CONTEXT *cx = si->si_cxstack + cxix; if (CxTYPE(cx) == CXt_EVAL && cx->blk_eval.old_op_type == OP_REQUIRE) - ++requires; + return PTR2UV(cx); } } - A_ENCODE_UV(buf, requires); + return PTR2UV(NULL); +} +#endif /* A_WORKAROUND_REQUIRE_PROPAGATION */ + +STATIC SV *a_tag(pTHX_ UV bits) { +#define a_tag(B) a_tag(aTHX_ (B)) + SV *hint; + const PERL_SI *si; + UV cxreq; + unsigned char buf[sizeof(UV) * 2]; + STRLEN len; + + cxreq = a_require_tag(); + A_ENCODE_UV(buf, cxreq); A_ENCODE_UV(buf + sizeof(UV), bits); hint = newSVpvn(buf, sizeof buf); SvREADONLY_on(hint); @@ -63,7 +73,7 @@ STATIC SV *a_tag(pTHX_ UV bits) { STATIC UV a_detag(pTHX_ const SV *hint) { #define a_detag(H) a_detag(aTHX_ (H)) const PERL_SI *si; - UV requires = 0, requires_max = 0, bits = 0; + UV cxreq = 0, bits = 0; unsigned char *buf; STRLEN len; @@ -71,21 +81,12 @@ STATIC UV a_detag(pTHX_ const SV *hint) { return 0; buf = SvPVX(hint); - A_DECODE_UV(requires_max, buf); - for (si = PL_curstackinfo; si; si = si->si_prev) { - I32 cxix; - - for (cxix = si->si_cxix; cxix >= 0; --cxix) { - const PERL_CONTEXT *cx = si->si_cxstack + cxix; - - if (CxTYPE(cx) == CXt_EVAL && cx->blk_eval.old_op_type == OP_REQUIRE - && ++requires > requires_max) - return 0; - } - } + A_DECODE_UV(cxreq, buf); + if (a_require_tag() != cxreq) + return 0; - A_DECODE_UV(bits, buf + sizeof(UV)); + A_DECODE_UV(bits, buf + sizeof(UV)); return bits; } @@ -93,7 +94,18 @@ STATIC UV a_detag(pTHX_ const SV *hint) { #else /* A_WORKAROUND_REQUIRE_PROPAGATION */ #define a_tag(B) newSVuv(B) -#define a_detag(H) (((H) && SvOK(H)) ? SvUVX(H) : 0) +/* PVs fetched from the hints chain have their SvLEN set to zero, so get the UV + * from a copy. */ +#define a_detag(H) \ + ((H) \ + ? (SvIOK(H) \ + ? SvUVX(H) \ + : (SvPOK(H) \ + ? sv_2uv(SvLEN(H) ? (H) : sv_mortalcopy(H)) \ + : 0 \ + ) \ + ) \ + : 0) #endif /* !A_WORKAROUND_REQUIRE_PROPAGATION */ @@ -409,7 +421,7 @@ STATIC OP *a_pp_rv2av(pTHX) { /* ... pp_rv2hv ............................................................ */ -STATIC OP *a_pp_rv2hv(pTHX) { +STATIC OP *a_pp_rv2hv_simple(pTHX) { a_op_info oi; UV flags; dSP; @@ -427,6 +439,29 @@ STATIC OP *a_pp_rv2hv(pTHX) { return CALL_FPTR(oi.old_pp)(aTHX); } +STATIC OP *a_pp_rv2hv(pTHX) { + a_op_info oi; + UV flags; + dSP; + + a_map_fetch(PL_op, &oi); + flags = oi.flags; + + if (flags & A_HINT_DEREF) { + if (!SvOK(TOPs)) { + SV *hv; + POPs; + hv = sv_2mortal((SV *) newHV()); + PUSHs(hv); + RETURN; + } + } else { + PL_op->op_ppaddr = oi.old_pp; + } + + return CALL_FPTR(oi.old_pp)(aTHX); +} + /* ... pp_deref (aelem,helem,rv2sv,padsv) .................................. */ STATIC OP *a_pp_deref(pTHX) { @@ -626,7 +661,7 @@ STATIC OP *a_ck_deref(pTHX_ OP *o) { case OP_HELEM: old_ck = a_old_ck_helem; if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT)) - a_recheck_rv2xv(cUNOPo->op_first, OP_RV2HV, a_pp_rv2hv); + a_recheck_rv2xv(cUNOPo->op_first, OP_RV2HV, a_pp_rv2hv_simple); break; case OP_RV2SV: old_ck = a_old_ck_rv2sv; @@ -660,7 +695,7 @@ STATIC OP *a_ck_rv2xv(pTHX_ OP *o) { switch (o->op_type) { case OP_RV2AV: old_ck = a_old_ck_rv2av; new_pp = a_pp_rv2av; break; - case OP_RV2HV: old_ck = a_old_ck_rv2hv; new_pp = a_pp_rv2hv; break; + case OP_RV2HV: old_ck = a_old_ck_rv2hv; new_pp = a_pp_rv2hv_simple; break; } o = CALL_FPTR(old_ck)(aTHX_ o); @@ -677,6 +712,40 @@ STATIC OP *a_ck_rv2xv(pTHX_ OP *o) { return o; } +/* ... ck_xslice (aslice,hslice) ........................................... */ + +/* I think those are only found at the root, but there's nothing that really + * prevent them to be inside the expression too. We only need to update the + * root so that the rest of the expression will see the right context when + * resolving. That's why we don't replace the ppaddr. */ + +STATIC OP *(*a_old_ck_aslice)(pTHX_ OP *) = 0; +STATIC OP *(*a_old_ck_hslice)(pTHX_ OP *) = 0; + +STATIC OP *a_ck_xslice(pTHX_ OP *o) { + OP * (*old_ck)(pTHX_ OP *o) = 0; + UV hint = a_hint(); + + switch (o->op_type) { + case OP_ASLICE: + old_ck = a_old_ck_aslice; + break; + case OP_HSLICE: + old_ck = a_old_ck_hslice; + if (hint & A_HINT_DO) + a_recheck_rv2xv(cUNOPo->op_first->op_sibling, OP_RV2HV, a_pp_rv2hv); + break; + } + o = CALL_FPTR(old_ck)(aTHX_ o); + + if (hint & A_HINT_DO) { + a_map_store_root(o, 0, hint); + } else + a_map_delete(o); + + return o; +} + /* ... ck_root (exists,delete,keys,values) ................................. */ /* Those ops are only found at the root of a dereferencing expression. We can @@ -768,6 +837,11 @@ BOOT: a_old_ck_rv2hv = PL_check[OP_RV2HV]; PL_check[OP_RV2HV] = MEMBER_TO_FPTR(a_ck_rv2xv); + a_old_ck_aslice = PL_check[OP_ASLICE]; + PL_check[OP_ASLICE] = MEMBER_TO_FPTR(a_ck_xslice); + a_old_ck_hslice = PL_check[OP_HSLICE]; + PL_check[OP_HSLICE] = MEMBER_TO_FPTR(a_ck_xslice); + a_old_ck_exists = PL_check[OP_EXISTS]; PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_ck_root); a_old_ck_delete = PL_check[OP_DELETE];