X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=autovivification.xs;h=27f44c7ae74cbe41a260d648ff0b205aead3d468;hb=refs%2Fheads%2Fopfreehook;hp=e36b8f50dfc6f1ed7bdfec6f3c6d3a0b1df5a339;hpb=0b4ae66b743ee623cdfdb7cdbea5c84338f9e3d9;p=perl%2Fmodules%2Fautovivification.git diff --git a/autovivification.xs b/autovivification.xs index e36b8f5..27f44c7 100644 --- a/autovivification.xs +++ b/autovivification.xs @@ -29,6 +29,10 @@ # define A_HAS_RPEEP A_HAS_PERL(5, 13, 5) #endif +#ifndef A_HAS_OPFREEHOOK +# define A_HAS_OPFREEHOOK A_HAS_PERL(5, 12, 0) +#endif + /* ... Thread safety and multiplicity ...................................... */ /* Always safe when the workaround isn't needed */ @@ -75,6 +79,44 @@ # define MY_CXT_CLONE NOOP #endif +#if defined(OP_CHECK_MUTEX_LOCK) && defined(OP_CHECK_MUTEX_UNLOCK) +# define A_CHECK_MUTEX_LOCK OP_CHECK_MUTEX_LOCK +# define A_CHECK_MUTEX_UNLOCK OP_CHECK_MUTEX_UNLOCK +#else +# define A_CHECK_MUTEX_LOCK OP_REFCNT_LOCK +# define A_CHECK_MUTEX_UNLOCK OP_REFCNT_UNLOCK +#endif + +typedef OP *(*a_ck_t)(pTHX_ OP *); + +#ifdef wrap_op_checker + +# define a_ck_replace(T, NC, OCP) wrap_op_checker((T), (NC), (OCP)) + +#else + +STATIC void a_ck_replace(pTHX_ OPCODE type, a_ck_t new_ck, a_ck_t *old_ck_p) { +#define a_ck_replace(T, NC, OCP) a_ck_replace(aTHX_ (T), (NC), (OCP)) + A_CHECK_MUTEX_LOCK; + if (!*old_ck_p) { + *old_ck_p = PL_check[type]; + PL_check[type] = new_ck; + } + A_CHECK_MUTEX_UNLOCK; +} + +#endif + +STATIC void a_ck_restore(pTHX_ OPCODE type, a_ck_t *old_ck_p) { +#define a_ck_restore(T, OCP) a_ck_restore(aTHX_ (T), (OCP)) + A_CHECK_MUTEX_LOCK; + if (*old_ck_p) { + PL_check[type] = *old_ck_p; + *old_ck_p = 0; + } + A_CHECK_MUTEX_UNLOCK; +} + /* --- Helpers ------------------------------------------------------------- */ /* ... Thread-safe hints ................................................... */ @@ -586,7 +628,7 @@ STATIC OP *a_pp_rv2av(pTHX) { /* We always need to push an empty array to fool the pp_aelem() that comes * later. */ SV *av; - POPs; + (void) POPs; av = sv_2mortal((SV *) newAV()); PUSHs(av); RETURN; @@ -623,7 +665,7 @@ STATIC OP *a_pp_rv2hv(pTHX) { if (oi->flags & A_HINT_DEREF) { if (a_undef(TOPs)) { SV *hv; - POPs; + (void) POPs; hv = sv_2mortal((SV *) newHV()); PUSHs(hv); RETURN; @@ -673,7 +715,7 @@ STATIC OP *a_pp_root_unop(pTHX) { dSP; if (a_undef(TOPs)) { - POPs; + (void) POPs; /* Can only be reached by keys or values */ if (GIMME_V == G_SCALAR) { dTARGET; @@ -693,8 +735,8 @@ STATIC OP *a_pp_root_binop(pTHX) { dSP; if (a_undef(TOPm1s)) { - POPs; - POPs; + (void) POPs; + (void) POPs; if (PL_op->op_type == OP_EXISTS) RETPUSHNO; else @@ -741,10 +783,13 @@ STATIC OP *a_ck_padany(pTHX_ OP *o) { o = a_old_ck_padany(aTHX_ o); hint = a_hint(); - if (hint & A_HINT_DO) + if (hint & A_HINT_DO) { a_map_store_root(o, o->op_ppaddr, hint); - else +#if !A_HAS_OPFREEHOOK + } else { a_map_delete(o); +#endif + } return o; } @@ -760,8 +805,11 @@ STATIC OP *a_ck_padsv(pTHX_ OP *o) { if (hint & A_HINT_DO) { a_map_store_root(o, o->op_ppaddr, hint); o->op_ppaddr = a_pp_deref; - } else +#if !A_HAS_OPFREEHOOK + } else { a_map_delete(o); +#endif + } return o; } @@ -801,8 +849,11 @@ STATIC OP *a_ck_deref(pTHX_ OP *o) { if (hint & A_HINT_DO) { a_map_store_root(o, o->op_ppaddr, hint); o->op_ppaddr = a_pp_deref; - } else +#if !A_HAS_OPFREEHOOK + } else { a_map_delete(o); +#endif + } return o; } @@ -835,8 +886,11 @@ STATIC OP *a_ck_rv2xv(pTHX_ OP *o) { if (hint & A_HINT_DO && !(hint & A_HINT_STRICT)) { a_map_store_root(o, o->op_ppaddr, hint); o->op_ppaddr = new_pp; - } else +#if !A_HAS_OPFREEHOOK + } else { a_map_delete(o); +#endif + } return o; } @@ -869,8 +923,11 @@ STATIC OP *a_ck_xslice(pTHX_ OP *o) { if (hint & A_HINT_DO) { a_map_store_root(o, 0, hint); - } else +#if !A_HAS_OPFREEHOOK + } else { a_map_delete(o); +#endif + } return o; } @@ -923,8 +980,11 @@ STATIC OP *a_ck_root(pTHX_ OP *o) { } else { a_map_cancel(o); } - } else +#if !A_HAS_OPFREEHOOK + } else { a_map_delete(o); +#endif + } return o; } @@ -1040,6 +1100,21 @@ STATIC void a_peep(pTHX_ OP *o) { ptable_seen_clear(seen); } +/* ... Our op free hook (when available) ................................... */ + +#if A_HAS_OPFREEHOOK + +STATIC void (*a_old_opfreehook)(pTHX_ OP *) = 0; + +STATIC void a_opfreehook(pTHX_ OP *o) { + a_map_delete(o); + + if (a_old_opfreehook) + a_old_opfreehook(aTHX_ o); +} + +#endif + /* --- Interpreter setup/teardown ------------------------------------------ */ STATIC U32 a_initialized = 0; @@ -1062,36 +1137,23 @@ STATIC void a_teardown(pTHX_ void *root) { ptable_seen_free(MY_CXT.seen); } - PL_check[OP_PADANY] = MEMBER_TO_FPTR(a_old_ck_padany); - a_old_ck_padany = 0; - PL_check[OP_PADSV] = MEMBER_TO_FPTR(a_old_ck_padsv); - a_old_ck_padsv = 0; - - PL_check[OP_AELEM] = MEMBER_TO_FPTR(a_old_ck_aelem); - a_old_ck_aelem = 0; - PL_check[OP_HELEM] = MEMBER_TO_FPTR(a_old_ck_helem); - a_old_ck_helem = 0; - PL_check[OP_RV2SV] = MEMBER_TO_FPTR(a_old_ck_rv2sv); - a_old_ck_rv2sv = 0; - - PL_check[OP_RV2AV] = MEMBER_TO_FPTR(a_old_ck_rv2av); - a_old_ck_rv2av = 0; - PL_check[OP_RV2HV] = MEMBER_TO_FPTR(a_old_ck_rv2hv); - a_old_ck_rv2hv = 0; - - PL_check[OP_ASLICE] = MEMBER_TO_FPTR(a_old_ck_aslice); - a_old_ck_aslice = 0; - PL_check[OP_HSLICE] = MEMBER_TO_FPTR(a_old_ck_hslice); - a_old_ck_hslice = 0; - - PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_old_ck_exists); - a_old_ck_exists = 0; - PL_check[OP_DELETE] = MEMBER_TO_FPTR(a_old_ck_delete); - a_old_ck_delete = 0; - PL_check[OP_KEYS] = MEMBER_TO_FPTR(a_old_ck_keys); - a_old_ck_keys = 0; - PL_check[OP_VALUES] = MEMBER_TO_FPTR(a_old_ck_values); - a_old_ck_values = 0; + a_ck_restore(OP_PADANY, &a_old_ck_padany); + a_ck_restore(OP_PADSV, &a_old_ck_padsv); + + a_ck_restore(OP_AELEM, &a_old_ck_aelem); + a_ck_restore(OP_HELEM, &a_old_ck_helem); + a_ck_restore(OP_RV2SV, &a_old_ck_rv2sv); + + a_ck_restore(OP_RV2AV, &a_old_ck_rv2av); + a_ck_restore(OP_RV2HV, &a_old_ck_rv2hv); + + a_ck_restore(OP_ASLICE, &a_old_ck_aslice); + a_ck_restore(OP_HSLICE, &a_old_ck_hslice); + + a_ck_restore(OP_EXISTS, &a_old_ck_exists); + a_ck_restore(OP_DELETE, &a_old_ck_delete); + a_ck_restore(OP_KEYS, &a_old_ck_keys); + a_ck_restore(OP_VALUES, &a_old_ck_values); #if A_HAS_RPEEP PL_rpeepp = a_old_peep; @@ -1100,6 +1162,11 @@ STATIC void a_teardown(pTHX_ void *root) { #endif a_old_peep = 0; +#if A_HAS_OPFREEHOOK + PL_opfreehook = a_old_opfreehook; + a_old_opfreehook = 0; +#endif + a_initialized = 0; } @@ -1117,36 +1184,23 @@ STATIC void a_setup(pTHX) { MY_CXT.seen = ptable_new(); } - a_old_ck_padany = PL_check[OP_PADANY]; - PL_check[OP_PADANY] = MEMBER_TO_FPTR(a_ck_padany); - a_old_ck_padsv = PL_check[OP_PADSV]; - PL_check[OP_PADSV] = MEMBER_TO_FPTR(a_ck_padsv); - - a_old_ck_aelem = PL_check[OP_AELEM]; - PL_check[OP_AELEM] = MEMBER_TO_FPTR(a_ck_deref); - a_old_ck_helem = PL_check[OP_HELEM]; - PL_check[OP_HELEM] = MEMBER_TO_FPTR(a_ck_deref); - a_old_ck_rv2sv = PL_check[OP_RV2SV]; - PL_check[OP_RV2SV] = MEMBER_TO_FPTR(a_ck_deref); - - a_old_ck_rv2av = PL_check[OP_RV2AV]; - PL_check[OP_RV2AV] = MEMBER_TO_FPTR(a_ck_rv2xv); - 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]; - PL_check[OP_DELETE] = MEMBER_TO_FPTR(a_ck_root); - a_old_ck_keys = PL_check[OP_KEYS]; - PL_check[OP_KEYS] = MEMBER_TO_FPTR(a_ck_root); - a_old_ck_values = PL_check[OP_VALUES]; - PL_check[OP_VALUES] = MEMBER_TO_FPTR(a_ck_root); + a_ck_replace(OP_PADANY, a_ck_padany, &a_old_ck_padany); + a_ck_replace(OP_PADSV, a_ck_padsv, &a_old_ck_padsv); + + a_ck_replace(OP_AELEM, a_ck_deref, &a_old_ck_aelem); + a_ck_replace(OP_HELEM, a_ck_deref, &a_old_ck_helem); + a_ck_replace(OP_RV2SV, a_ck_deref, &a_old_ck_rv2sv); + + a_ck_replace(OP_RV2AV, a_ck_rv2xv, &a_old_ck_rv2av); + a_ck_replace(OP_RV2HV, a_ck_rv2xv, &a_old_ck_rv2hv); + + a_ck_replace(OP_ASLICE, a_ck_xslice, &a_old_ck_aslice); + a_ck_replace(OP_HSLICE, a_ck_xslice, &a_old_ck_hslice); + + a_ck_replace(OP_EXISTS, a_ck_root, &a_old_ck_exists); + a_ck_replace(OP_DELETE, a_ck_root, &a_old_ck_delete); + a_ck_replace(OP_KEYS, a_ck_root, &a_old_ck_keys); + a_ck_replace(OP_VALUES, a_ck_root, &a_old_ck_values); #if A_HAS_RPEEP a_old_peep = PL_rpeepp; @@ -1156,6 +1210,11 @@ STATIC void a_setup(pTHX) { PL_peepp = a_peep; #endif +#if A_HAS_OPFREEHOOK + a_old_opfreehook = PL_opfreehook; + PL_opfreehook = a_opfreehook; +#endif + #if A_MULTIPLICITY call_atexit(a_teardown, aTHX); #else