X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=autovivification.xs;h=554056c1c53a024050d703df2f08cb0346b2093f;hb=048a0f61d8110a79e17aa1792b6ba1ed38d40e35;hp=ddc4dd768d9fa8d9066e002c94c19556a4933122;hpb=0cd4c2a91f46cbca31aca9a100adbcbb7aa51894;p=perl%2Fmodules%2Fautovivification.git diff --git a/autovivification.xs b/autovivification.xs index ddc4dd7..554056c 100644 --- a/autovivification.xs +++ b/autovivification.xs @@ -32,7 +32,8 @@ /* Only used in op flags */ #define A_HINT_ROOT 256 -#define A_HINT_DEREF 512 +#define A_HINT_SECOND 512 +#define A_HINT_DEREF 1024 #define XSH_HINTS_TYPE_UV 1 @@ -61,6 +62,10 @@ # define A_HAS_MULTIDEREF XSH_HAS_PERL(5, 21, 7) #endif +#ifndef A_HAS_SCALARKEYS_OPT +# define A_HAS_SCALARKEYS_OPT XSH_HAS_PERL(5, 27, 3) +#endif + /* ... Our vivify_ref() .................................................... */ /* Perl_vivify_ref() is not exported, so we have to reimplement it. */ @@ -233,17 +238,18 @@ static void a_map_store_root(pTHX_ const OP *root, OP *(*old_pp)(pTHX), UV flags return; } -static void a_map_update_flags_topdown(const OP *root, UV flags) { +static void a_map_update_flags_topdown(const OP *root, UV mask, UV flags) { a_op_info *oi; const OP *o = root; XSH_LOCK(&a_op_map_mutex); - flags &= ~A_HINT_ROOT; + mask |= A_HINT_ROOT; + flags &= ~mask; do { if ((oi = ptable_fetch(a_op_map, o))) - oi->flags = (oi->flags & A_HINT_ROOT) | flags; + oi->flags = (oi->flags & mask) | flags; if (!(o->op_flags & OPf_KIDS)) break; o = a_map_descend(o); @@ -254,8 +260,6 @@ static void a_map_update_flags_topdown(const OP *root, UV flags) { return; } -#define a_map_cancel(R) a_map_update_flags_topdown((R), 0) - static void a_map_update_flags_bottomup(const OP *o, UV flags, UV rflags) { a_op_info *oi; @@ -408,6 +412,29 @@ static OP *a_pp_rv2hv(pTHX) { return oi->old_pp(aTHX); } +#if A_HAS_SCALARKEYS_OPT + +static OP *a_pp_rv2hv_dokeys(pTHX) { + dA_MAP_THX; + const a_op_info *oi; + dSP; + + oi = a_map_fetch(PL_op); + + if (oi->flags & A_HINT_KEYS) { + if (a_undef(TOPs)) { + dTARGET; + (void) POPs; + PUSHi(0); + RETURN; + } + } + + return oi->old_pp(aTHX); +} + +#endif + /* ... pp_deref (aelem,helem,rv2sv,padsv) .................................. */ static void a_cannot_vivify(pTHX_ UV flags) { @@ -1017,11 +1044,24 @@ static OP *a_ck_root(pTHX_ OP *o) { if (hint & A_HINT_DO) { if (enabled) { - a_map_update_flags_topdown(o, hint | A_HINT_DEREF); +#if A_HAS_SCALARKEYS_OPT + if ((enabled == A_HINT_KEYS) && (o->op_flags & OPf_KIDS)) { + OP *kid = cUNOPo->op_first; + if (kid->op_type == OP_RV2HV) { + dA_MAP_THX; + const a_op_info *koi = a_map_fetch(kid); + a_map_store(kid, koi ? koi->old_pp : kid->op_ppaddr, NULL, + hint | A_HINT_SECOND); + if (!koi) + kid->op_ppaddr = a_pp_rv2hv; + } + } +#endif + a_map_update_flags_topdown(o, A_HINT_SECOND, hint | A_HINT_DEREF); a_map_store_root(o, o->op_ppaddr, hint); o->op_ppaddr = new_pp; } else { - a_map_cancel(o); + a_map_update_flags_topdown(o, 0, 0); } } else a_map_delete(o); @@ -1072,16 +1112,34 @@ static void xsh_peep_rec(pTHX_ OP *o, ptable *seen) { o->op_ppaddr = oi->old_pp; break; case OP_RV2AV: - case OP_RV2HV: - if ( o->op_ppaddr != a_pp_rv2av - && o->op_ppaddr != a_pp_rv2hv - && o->op_ppaddr != a_pp_rv2hv_simple) + if (o->op_ppaddr != a_pp_rv2av) break; oi = a_map_fetch(o); if (!oi) break; if (!(oi->flags & A_HINT_DEREF)) - o->op_ppaddr = oi->old_pp; + o->op_ppaddr = oi->old_pp; + break; + case OP_RV2HV: + if (o->op_ppaddr != a_pp_rv2hv && o->op_ppaddr != a_pp_rv2hv_simple) + break; + oi = a_map_fetch(o); + if (!oi) + break; + if (!(oi->flags & A_HINT_DEREF)) { + o->op_ppaddr = oi->old_pp; + break; + } +#if A_HAS_SCALARKEYS_OPT + flags = oi->flags; + if ((flags & A_HINT_KEYS) && (flags & A_HINT_SECOND)) { + U8 want = o->op_flags & OPf_WANT; + if (want == OPf_WANT_VOID || want == OPf_WANT_SCALAR) + o->op_ppaddr = a_pp_rv2hv_dokeys; + else if (oi->old_pp == a_pp_rv2hv || oi->old_pp == a_pp_rv2hv_simple) + o->op_ppaddr = oi->old_pp; + } +#endif break; #if A_HAS_MULTIDEREF case OP_MULTIDEREF: