X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2Fautovivification.git;a=blobdiff_plain;f=autovivification.xs;h=d92b0b7b01bb92d6a94d7cc92f545ca2b79a609c;hp=62162de1c331793406b464b65a8e342b160f2e62;hb=0c93e9f08676e6d77f7381a87e15c6dcc898683a;hpb=6bc99454a8284978b14854642fac0123c77bac45 diff --git a/autovivification.xs b/autovivification.xs index 62162de..d92b0b7 100644 --- a/autovivification.xs +++ b/autovivification.xs @@ -75,6 +75,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 ................................................... */ @@ -134,11 +172,11 @@ START_MY_CXT #if A_WORKAROUND_REQUIRE_PROPAGATION typedef struct { - ptable *tbl; + ptable *tbl; #if A_HAS_PERL(5, 13, 2) CLONE_PARAMS *params; #else - CLONE_PARAMS params; + CLONE_PARAMS params; #endif } a_ptable_clone_ud; @@ -172,8 +210,6 @@ STATIC void a_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) { #endif /* A_WORKAROUND_REQUIRE_PROPAGATION */ -#include "reap.h" - STATIC void a_thread_cleanup(pTHX_ void *ud) { dMY_CXT; @@ -183,6 +219,29 @@ STATIC void a_thread_cleanup(pTHX_ void *ud) { ptable_seen_free(MY_CXT.seen); } +STATIC int a_endav_free(pTHX_ SV *sv, MAGIC *mg) { + SAVEDESTRUCTOR_X(a_thread_cleanup, NULL); + + return 0; +} + +STATIC MGVTBL a_endav_vtbl = { + 0, + 0, + 0, + 0, + a_endav_free +#if MGf_COPY + , 0 +#endif +#if MGf_DUP + , 0 +#endif +#if MGf_LOCAL + , 0 +#endif +}; + #endif /* A_THREADSAFE */ #if A_WORKAROUND_REQUIRE_PROPAGATION @@ -234,19 +293,19 @@ get_enclosing_cv: STATIC SV *a_tag(pTHX_ UV bits) { #define a_tag(B) a_tag(aTHX_ (B)) a_hint_t *h; -#if A_THREADSAFE - dMY_CXT; -#endif h = PerlMemShared_malloc(sizeof *h); h->bits = bits; h->require_tag = a_require_tag(); #if A_THREADSAFE - /* We only need for the key to be an unique tag for looking up the value later. - * Allocated memory provides convenient unique identifiers, so that's why we - * use the hint as the key itself. */ - ptable_hints_store(MY_CXT.tbl, h, h); + { + dMY_CXT; + /* We only need for the key to be an unique tag for looking up the value later + * Allocated memory provides convenient unique identifiers, so that's why we + * use the hint as the key itself. */ + ptable_hints_store(MY_CXT.tbl, h, h); + } #endif /* A_THREADSAFE */ return newSViv(PTR2IV(h)); @@ -255,16 +314,16 @@ STATIC SV *a_tag(pTHX_ UV bits) { STATIC UV a_detag(pTHX_ const SV *hint) { #define a_detag(H) a_detag(aTHX_ (H)) a_hint_t *h; -#if A_THREADSAFE - dMY_CXT; -#endif if (!(hint && SvIOK(hint))) return 0; h = INT2PTR(a_hint_t *, SvIVX(hint)); #if A_THREADSAFE - h = ptable_fetch(MY_CXT.tbl, h); + { + dMY_CXT; + h = ptable_fetch(MY_CXT.tbl, h); + } #endif /* A_THREADSAFE */ if (a_require_tag() != h->require_tag) @@ -320,7 +379,7 @@ STATIC UV a_hint(pTHX) { 0, a_hash); #else - SV **val = hv_fetch(GvHV(PL_hintgv), __PACKAGE__, __PACKAGE_LEN__, a_hash); + SV **val = hv_fetch(GvHV(PL_hintgv), __PACKAGE__, __PACKAGE_LEN__, 0); if (!val) return 0; hint = *val; @@ -331,9 +390,9 @@ STATIC UV a_hint(pTHX) { /* ... op => info map ...................................................... */ typedef struct { - OP *(*old_pp)(pTHX); - UV flags; - void *next; + OP *(*old_pp)(pTHX); + void *next; + UV flags; } a_op_info; #define PTABLE_NAME ptable_map @@ -586,7 +645,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 +682,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 +732,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 +752,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 @@ -942,11 +1001,22 @@ STATIC void a_peep_rec(pTHX_ OP *o, ptable *seen) { const a_op_info *oi = NULL; UV flags = 0; +#if !A_HAS_RPEEP if (ptable_fetch(seen, o)) break; ptable_seen_store(seen, o, o); +#endif switch (o->op_type) { +#if A_HAS_RPEEP + case OP_NEXTSTATE: + case OP_DBSTATE: + case OP_STUB: + if (ptable_fetch(seen, o)) + return; + ptable_seen_store(seen, o, o); + break; +#endif case OP_PADSV: if (o->op_ppaddr != a_pp_deref) { oi = a_map_fetch(o); @@ -1062,36 +1132,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; @@ -1117,36 +1174,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; @@ -1210,6 +1254,7 @@ PREINIT: ptable *t; #endif ptable *s; + GV *gv; PPCODE: { dMY_CXT; @@ -1233,7 +1278,23 @@ PPCODE: #endif MY_CXT.seen = s; } - reap(3, a_thread_cleanup, NULL); + gv = gv_fetchpv(__PACKAGE__ "::_THREAD_CLEANUP", 0, SVt_PVCV); + if (gv) { + CV *cv = GvCV(gv); + if (!PL_endav) + PL_endav = newAV(); + SvREFCNT_inc(cv); + if (!av_store(PL_endav, av_len(PL_endav) + 1, (SV *) cv)) + SvREFCNT_dec(cv); + sv_magicext((SV *) PL_endav, NULL, PERL_MAGIC_ext, &a_endav_vtbl, NULL, 0); + } + XSRETURN(0); + +void +_THREAD_CLEANUP(...) +PROTOTYPE: DISABLE +PPCODE: + a_thread_cleanup(aTHX_ NULL); XSRETURN(0); #endif /* A_THREADSAFE */