X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2Fautovivification.git;a=blobdiff_plain;f=autovivification.xs;h=5844328eae64768d4a9390e258dc45b102d686c4;hp=14189ce31e6c6c0ab63c9e9faa0823acbe51b735;hb=c058978f900652b3e9e4a40bfb1fb745270d75be;hpb=0180a2a0145e8f56b355b156b66ad1c188dc7214 diff --git a/autovivification.xs b/autovivification.xs index 14189ce..5844328 100644 --- a/autovivification.xs +++ b/autovivification.xs @@ -6,8 +6,44 @@ #include "perl.h" #include "XSUB.h" -#define __PACKAGE__ "autovivification" -#define __PACKAGE_LEN__ (sizeof(__PACKAGE__)-1) +/* --- XS helpers ---------------------------------------------------------- */ + +#define XSH_PACKAGE "autovivification" + +#include "xsh/caps.h" +#include "xsh/util.h" +#include "xsh/ops.h" +#include "xsh/peep.h" + +/* ... Lexical hints ....................................................... */ + +/* Used both for hints and op flags */ +#define A_HINT_STRICT 1 +#define A_HINT_WARN 2 +#define A_HINT_FETCH 4 +#define A_HINT_STORE 8 +#define A_HINT_EXISTS 16 +#define A_HINT_DELETE 32 +#define A_HINT_NOTIFY (A_HINT_STRICT|A_HINT_WARN) +#define A_HINT_DO (A_HINT_FETCH|A_HINT_STORE|A_HINT_EXISTS|A_HINT_DELETE) +#define A_HINT_MASK (A_HINT_NOTIFY|A_HINT_DO) + +/* Only used in op flags */ +#define A_HINT_ROOT 64 +#define A_HINT_DEREF 128 + +#define XSH_HINTS_TYPE_UV 1 + +#include "xsh/hints.h" + +#define a_hint() xsh_hints_detag(xsh_hints_fetch()) + +/* ... Thread-local storage ................................................ */ + +#define XSH_THREADS_COMPILE_TIME_PROTECTION 1 +#define XSH_THREADS_USER_CONTEXT 0 + +#include "xsh/threads.h" /* --- Compatibility wrappers ---------------------------------------------- */ @@ -19,32 +55,8 @@ # define HvNAMELEN_get(H) strlen(HvNAME_get(H)) #endif -#define A_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S)))))) - -#ifndef A_WORKAROUND_REQUIRE_PROPAGATION -# define A_WORKAROUND_REQUIRE_PROPAGATION !A_HAS_PERL(5, 10, 1) -#endif - -#ifndef A_HAS_RPEEP -# define A_HAS_RPEEP A_HAS_PERL(5, 13, 5) -#endif - #ifndef A_HAS_MULTIDEREF -# define A_HAS_MULTIDEREF A_HAS_PERL(5, 21, 7) -#endif - -#ifndef OpSIBLING -# ifdef OP_SIBLING -# define OpSIBLING(O) OP_SIBLING(O) -# else -# define OpSIBLING(O) ((O)->op_sibling) -# endif -#endif - -#ifdef DEBUGGING -# define A_ASSERT(C) assert(C) -#else -# define A_ASSERT(C) +# define A_HAS_MULTIDEREF XSH_HAS_PERL(5, 21, 7) #endif /* ... Our vivify_ref() .................................................... */ @@ -90,439 +102,7 @@ static SV *a_vivify_ref(pTHX_ SV *sv, int to_hash) { #endif /* A_HAS_MULTIDEREF */ -/* ... Thread safety and multiplicity ...................................... */ - -/* Always safe when the workaround isn't needed */ -#if !A_WORKAROUND_REQUIRE_PROPAGATION -# undef A_FORKSAFE -# define A_FORKSAFE 1 -/* Otherwise, safe unless Makefile.PL says it's Win32 */ -#elif !defined(A_FORKSAFE) -# define A_FORKSAFE 1 -#endif - -#ifndef A_MULTIPLICITY -# if defined(MULTIPLICITY) -# define A_MULTIPLICITY 1 -# else -# define A_MULTIPLICITY 0 -# endif -#endif -#if A_MULTIPLICITY -# ifndef PERL_IMPLICIT_CONTEXT -# error MULTIPLICITY builds must set PERL_IMPLICIT_CONTEXT -# endif -#endif - -#ifndef tTHX -# define tTHX PerlInterpreter* -#endif - -#if A_MULTIPLICITY && defined(USE_ITHREADS) && defined(dMY_CXT) && defined(MY_CXT) && defined(START_MY_CXT) && defined(MY_CXT_INIT) && (defined(MY_CXT_CLONE) || defined(dMY_CXT_SV)) -# define A_THREADSAFE 1 -# ifndef MY_CXT_CLONE -# define MY_CXT_CLONE \ - dMY_CXT_SV; \ - my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \ - Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \ - sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) -# endif -#else -# define A_THREADSAFE 0 -# undef dMY_CXT -# define dMY_CXT dNOOP -# undef MY_CXT -# define MY_CXT a_globaldata -# undef START_MY_CXT -# define START_MY_CXT static my_cxt_t MY_CXT; -# undef MY_CXT_INIT -# define MY_CXT_INIT NOOP -# undef MY_CXT_CLONE -# define MY_CXT_CLONE NOOP -#endif - -#if A_THREADSAFE -/* We must use preexistent global mutexes or we will never be able to destroy - * them. */ -# if A_HAS_PERL(5, 9, 3) -# define A_LOADED_LOCK MUTEX_LOCK(&PL_my_ctx_mutex) -# define A_LOADED_UNLOCK MUTEX_UNLOCK(&PL_my_ctx_mutex) -# else -# define A_LOADED_LOCK OP_REFCNT_LOCK -# define A_LOADED_UNLOCK OP_REFCNT_UNLOCK -# endif -#else -# define A_LOADED_LOCK NOOP -# define A_LOADED_UNLOCK NOOP -#endif - -#if defined(OP_CHECK_MUTEX_LOCK) && defined(OP_CHECK_MUTEX_UNLOCK) -# define A_CHECK_LOCK OP_CHECK_MUTEX_LOCK -# define A_CHECK_UNLOCK OP_CHECK_MUTEX_UNLOCK -#elif A_HAS_PERL(5, 9, 3) -# define A_CHECK_LOCK OP_REFCNT_LOCK -# define A_CHECK_UNLOCK OP_REFCNT_UNLOCK -#else -/* Before perl 5.9.3, a_ck_*() calls are already protected by the A_LOADED - * mutex, which falls back to the OP_REFCNT mutex. Make sure we don't lock it - * twice. */ -# define A_CHECK_LOCK NOOP -# define A_CHECK_UNLOCK NOOP -#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_LOCK; - if (!*old_ck_p) { - *old_ck_p = PL_check[type]; - PL_check[type] = new_ck; - } - A_CHECK_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_LOCK; - if (*old_ck_p) { - PL_check[type] = *old_ck_p; - *old_ck_p = 0; - } - A_CHECK_UNLOCK; -} - -/* --- Helpers ------------------------------------------------------------- */ - -/* ... Check if the module is loaded ....................................... */ - -static I32 a_loaded = 0; - -#if A_THREADSAFE - -#define PTABLE_NAME ptable_loaded -#define PTABLE_NEED_DELETE 1 -#define PTABLE_NEED_WALK 0 - -#include "ptable.h" - -#define ptable_loaded_store(T, K, V) ptable_loaded_store(aPTBLMS_ (T), (K), (V)) -#define ptable_loaded_delete(T, K) ptable_loaded_delete(aPTBLMS_ (T), (K)) -#define ptable_loaded_free(T) ptable_loaded_free(aPTBLMS_ (T)) - -static ptable *a_loaded_cxts = NULL; - -static int a_is_loaded(pTHX_ void *cxt) { -#define a_is_loaded(C) a_is_loaded(aTHX_ (C)) - int res = 0; - - A_LOADED_LOCK; - if (a_loaded_cxts && ptable_fetch(a_loaded_cxts, cxt)) - res = 1; - A_LOADED_UNLOCK; - - return res; -} - -static int a_set_loaded_locked(pTHX_ void *cxt) { -#define a_set_loaded_locked(C) a_set_loaded_locked(aTHX_ (C)) - int global_setup = 0; - - if (a_loaded <= 0) { - A_ASSERT(a_loaded == 0); - A_ASSERT(!a_loaded_cxts); - a_loaded_cxts = ptable_new(); - global_setup = 1; - } - ++a_loaded; - A_ASSERT(a_loaded_cxts); - ptable_loaded_store(a_loaded_cxts, cxt, cxt); - - return global_setup; -} - -static int a_clear_loaded_locked(pTHX_ void *cxt) { -#define a_clear_loaded_locked(C) a_clear_loaded_locked(aTHX_ (C)) - int global_teardown = 0; - - if (a_loaded > 1) { - A_ASSERT(a_loaded_cxts); - ptable_loaded_delete(a_loaded_cxts, cxt); - --a_loaded; - } else if (a_loaded_cxts) { - A_ASSERT(a_loaded == 1); - ptable_loaded_free(a_loaded_cxts); - a_loaded_cxts = NULL; - a_loaded = 0; - global_teardown = 1; - } - - return global_teardown; -} - -#else - -#define a_is_loaded(C) (a_loaded > 0) -#define a_set_loaded_locked(C) ((a_loaded++ <= 0) ? 1 : 0) -#define a_clear_loaded_locked(C) ((--a_loaded <= 0) ? 1 : 0) - -#endif - -/* ... Thread-safe hints ................................................... */ - -#if A_WORKAROUND_REQUIRE_PROPAGATION - -typedef struct { - U32 bits; - IV require_tag; -} a_hint_t; - -#define A_HINT_FREE(H) PerlMemShared_free(H) - -#if A_THREADSAFE - -#define PTABLE_NAME ptable_hints -#define PTABLE_VAL_FREE(V) A_HINT_FREE(V) -#define PTABLE_NEED_DELETE 0 -#define PTABLE_NEED_WALK 1 - -#define pPTBL pTHX -#define pPTBL_ pTHX_ -#define aPTBL aTHX -#define aPTBL_ aTHX_ - -#include "ptable.h" - -#define ptable_hints_store(T, K, V) ptable_hints_store(aTHX_ (T), (K), (V)) -#define ptable_hints_free(T) ptable_hints_free(aTHX_ (T)) - -#endif /* A_THREADSAFE */ - -#endif /* A_WORKAROUND_REQUIRE_PROPAGATION */ - -#define PTABLE_NAME ptable_seen -#define PTABLE_NEED_DELETE 0 -#define PTABLE_NEED_WALK 0 - -#include "ptable.h" - -/* PerlMemShared_free() needs the [ap]PTBLMS_? default values */ -#define ptable_seen_store(T, K, V) ptable_seen_store(aPTBLMS_ (T), (K), (V)) -#define ptable_seen_clear(T) ptable_seen_clear(aPTBLMS_ (T)) -#define ptable_seen_free(T) ptable_seen_free(aPTBLMS_ (T)) - -#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION - -typedef struct { - peep_t old_peep; /* This is actually the rpeep past 5.13.5 */ - ptable *seen; /* It really is a ptable_seen */ -#if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION - ptable *tbl; /* It really is a ptable_hints */ - tTHX owner; -#endif /* A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION */ -} my_cxt_t; - -START_MY_CXT - -#if A_WORKAROUND_REQUIRE_PROPAGATION - -#if A_THREADSAFE - -typedef struct { - ptable *tbl; -#if A_HAS_PERL(5, 13, 2) - CLONE_PARAMS *params; -#else - CLONE_PARAMS params; -#endif -} a_ptable_clone_ud; - -#if A_HAS_PERL(5, 13, 2) -# define a_ptable_clone_ud_init(U, T, O) \ - (U).tbl = (T); \ - (U).params = Perl_clone_params_new((O), aTHX) -# define a_ptable_clone_ud_deinit(U) Perl_clone_params_del((U).params) -# define a_dup_inc(S, U) SvREFCNT_inc(sv_dup((S), (U)->params)) -#else -# define a_ptable_clone_ud_init(U, T, O) \ - (U).tbl = (T); \ - (U).params.stashes = newAV(); \ - (U).params.flags = 0; \ - (U).params.proto_perl = (O) -# define a_ptable_clone_ud_deinit(U) SvREFCNT_dec((U).params.stashes) -# define a_dup_inc(S, U) SvREFCNT_inc(sv_dup((S), &((U)->params))) -#endif - -static void a_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) { - a_ptable_clone_ud *ud = ud_; - a_hint_t *h1 = ent->val; - a_hint_t *h2; - - h2 = PerlMemShared_malloc(sizeof *h2); - h2->bits = h1->bits; - h2->require_tag = PTR2IV(a_dup_inc(INT2PTR(SV *, h1->require_tag), ud)); - - ptable_hints_store(ud->tbl, ent->key, h2); -} - -#endif /* A_THREADSAFE */ - -static IV a_require_tag(pTHX) { -#define a_require_tag() a_require_tag(aTHX) - const CV *cv, *outside; - - cv = PL_compcv; - - if (!cv) { - /* If for some reason the pragma is operational at run-time, try to discover - * the current cv in use. */ - const PERL_SI *si; - - 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; - - switch (CxTYPE(cx)) { - case CXt_SUB: - case CXt_FORMAT: - /* The propagation workaround is only needed up to 5.10.0 and at that - * time format and sub contexts were still identical. And even later the - * cv members offsets should have been kept the same. */ - cv = cx->blk_sub.cv; - goto get_enclosing_cv; - case CXt_EVAL: - cv = cx->blk_eval.cv; - goto get_enclosing_cv; - default: - break; - } - } - } - - cv = PL_main_cv; - } - -get_enclosing_cv: - for (outside = CvOUTSIDE(cv); outside; outside = CvOUTSIDE(cv)) - cv = outside; - - return PTR2IV(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; - - if (!MY_CXT.tbl) - return newSViv(0); -#endif /* A_THREADSAFE */ - - 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); -#endif /* A_THREADSAFE */ - - return newSViv(PTR2IV(h)); -} - -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; - - if (!MY_CXT.tbl) - return 0; -#endif /* A_THREADSAFE */ - - if (!(hint && SvIOK(hint))) - return 0; - - h = INT2PTR(a_hint_t *, SvIVX(hint)); -#if A_THREADSAFE - h = ptable_fetch(MY_CXT.tbl, h); -#endif /* A_THREADSAFE */ - - if (a_require_tag() != h->require_tag) - return 0; - - return h->bits; -} - -#else /* A_WORKAROUND_REQUIRE_PROPAGATION */ - -#define a_tag(B) newSVuv(B) -/* 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 */ - -/* Used both for hints and op flags */ -#define A_HINT_STRICT 1 -#define A_HINT_WARN 2 -#define A_HINT_FETCH 4 -#define A_HINT_STORE 8 -#define A_HINT_EXISTS 16 -#define A_HINT_DELETE 32 -#define A_HINT_NOTIFY (A_HINT_STRICT|A_HINT_WARN) -#define A_HINT_DO (A_HINT_FETCH|A_HINT_STORE|A_HINT_EXISTS|A_HINT_DELETE) -#define A_HINT_MASK (A_HINT_NOTIFY|A_HINT_DO) - -/* Only used in op flags */ -#define A_HINT_ROOT 64 -#define A_HINT_DEREF 128 - -static VOL U32 a_hash = 0; - -static UV a_hint(pTHX) { -#define a_hint() a_hint(aTHX) - SV *hint; -#ifdef cop_hints_fetch_pvn - hint = cop_hints_fetch_pvn(PL_curcop, __PACKAGE__, __PACKAGE_LEN__, a_hash, 0); -#elif A_HAS_PERL(5, 9, 5) - hint = Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash, - NULL, - __PACKAGE__, __PACKAGE_LEN__, - 0, - a_hash); -#else - SV **val = hv_fetch(GvHV(PL_hintgv), __PACKAGE__, __PACKAGE_LEN__, 0); - if (!val) - return 0; - hint = *val; -#endif - return a_detag(hint); -} - -/* ... op => info map ...................................................... */ +/* --- op => info map ------------------------------------------------------ */ typedef struct { OP *(*old_pp)(pTHX); @@ -530,17 +110,17 @@ typedef struct { UV flags; } a_op_info; -#define PTABLE_NAME ptable_map -#define PTABLE_VAL_FREE(V) PerlMemShared_free(V) -#define PTABLE_NEED_DELETE 1 -#define PTABLE_NEED_WALK 0 +#define PTABLE_NAME ptable_map +#define PTABLE_VAL_FREE(V) PerlMemShared_free(V) +#define PTABLE_VAL_NEED_CONTEXT 0 +#define PTABLE_NEED_DELETE 1 +#define PTABLE_NEED_WALK 0 -#include "ptable.h" +#include "xsh/ptable.h" -/* PerlMemShared_free() needs the [ap]PTBLMS_? default values */ -#define ptable_map_store(T, K, V) ptable_map_store(aPTBLMS_ (T), (K), (V)) -#define ptable_map_delete(T, K) ptable_map_delete(aPTBLMS_ (T), (K)) -#define ptable_map_free(T) ptable_map_free(aPTBLMS_ (T)) +#define ptable_map_store(T, K, V) ptable_map_store(aPMS_ (T), (K), (V)) +#define ptable_map_delete(T, K) ptable_map_delete(aPMS_ (T), (K)) +#define ptable_map_free(T) ptable_map_free(aPMS_ (T)) static ptable *a_op_map = NULL; @@ -550,13 +130,10 @@ static ptable *a_op_map = NULL; static perl_mutex a_op_map_mutex; -#define A_LOCK(M) MUTEX_LOCK(M) -#define A_UNLOCK(M) MUTEX_UNLOCK(M) - static const a_op_info *a_map_fetch(const OP *o, a_op_info *oi) { const a_op_info *val; - A_LOCK(&a_op_map_mutex); + XSH_LOCK(&a_op_map_mutex); val = ptable_fetch(a_op_map, o); if (val) { @@ -564,7 +141,7 @@ static const a_op_info *a_map_fetch(const OP *o, a_op_info *oi) { val = oi; } - A_UNLOCK(&a_op_map_mutex); + XSH_UNLOCK(&a_op_map_mutex); return val; } @@ -575,15 +152,12 @@ static const a_op_info *a_map_fetch(const OP *o, a_op_info *oi) { #define dA_MAP_THX dNOOP -#define A_LOCK(M) NOOP -#define A_UNLOCK(M) NOOP - #define a_map_fetch(O) ptable_fetch(a_op_map, (O)) #endif /* !USE_ITHREADS */ -static const a_op_info *a_map_store_locked(pPTBLMS_ const OP *o, OP *(*old_pp)(pTHX), void *next, UV flags) { -#define a_map_store_locked(O, PP, N, F) a_map_store_locked(aPTBLMS_ (O), (PP), (N), (F)) +static const a_op_info *a_map_store_locked(pPMS_ const OP *o, OP *(*old_pp)(pTHX), void *next, UV flags) { +#define a_map_store_locked(O, PP, N, F) a_map_store_locked(aPMS_ (O), (PP), (N), (F)) a_op_info *oi; if (!(oi = ptable_fetch(a_op_map, o))) { @@ -598,22 +172,22 @@ static const a_op_info *a_map_store_locked(pPTBLMS_ const OP *o, OP *(*old_pp)(p return oi; } -static void a_map_store(pPTBLMS_ const OP *o, OP *(*old_pp)(pTHX), void *next, UV flags) { -#define a_map_store(O, PP, N, F) a_map_store(aPTBLMS_ (O), (PP), (N), (F)) - A_LOCK(&a_op_map_mutex); +static void a_map_store(pTHX_ const OP *o, OP *(*old_pp)(pTHX), void *next, UV flags) { +#define a_map_store(O, PP, N, F) a_map_store(aTHX_ (O), (PP), (N), (F)) + XSH_LOCK(&a_op_map_mutex); a_map_store_locked(o, old_pp, next, flags); - A_UNLOCK(&a_op_map_mutex); + XSH_UNLOCK(&a_op_map_mutex); } static void a_map_delete(pTHX_ const OP *o) { #define a_map_delete(O) a_map_delete(aTHX_ (O)) - A_LOCK(&a_op_map_mutex); + XSH_LOCK(&a_op_map_mutex); ptable_map_delete(a_op_map, o); - A_UNLOCK(&a_op_map_mutex); + XSH_UNLOCK(&a_op_map_mutex); } static const OP *a_map_descend(const OP *o) { @@ -631,13 +205,13 @@ static const OP *a_map_descend(const OP *o) { return NULL; } -static void a_map_store_root(pPTBLMS_ const OP *root, OP *(*old_pp)(pTHX), UV flags) { -#define a_map_store_root(R, PP, F) a_map_store_root(aPTBLMS_ (R), (PP), (F)) +static void a_map_store_root(pTHX_ const OP *root, OP *(*old_pp)(pTHX), UV flags) { +#define a_map_store_root(R, PP, F) a_map_store_root(aTHX_ (R), (PP), (F)) const a_op_info *roi; a_op_info *oi; const OP *o = root; - A_LOCK(&a_op_map_mutex); + XSH_LOCK(&a_op_map_mutex); roi = a_map_store_locked(o, old_pp, (OP *) root, flags | A_HINT_ROOT); @@ -652,7 +226,7 @@ static void a_map_store_root(pPTBLMS_ const OP *root, OP *(*old_pp)(pTHX), UV fl } } - A_UNLOCK(&a_op_map_mutex); + XSH_UNLOCK(&a_op_map_mutex); return; } @@ -661,7 +235,7 @@ static void a_map_update_flags_topdown(const OP *root, UV flags) { a_op_info *oi; const OP *o = root; - A_LOCK(&a_op_map_mutex); + XSH_LOCK(&a_op_map_mutex); flags &= ~A_HINT_ROOT; @@ -673,7 +247,7 @@ static void a_map_update_flags_topdown(const OP *root, UV flags) { o = a_map_descend(o); } while (o); - A_UNLOCK(&a_op_map_mutex); + XSH_UNLOCK(&a_op_map_mutex); return; } @@ -683,7 +257,7 @@ static void a_map_update_flags_topdown(const OP *root, UV flags) { static void a_map_update_flags_bottomup(const OP *o, UV flags, UV rflags) { a_op_info *oi; - A_LOCK(&a_op_map_mutex); + XSH_LOCK(&a_op_map_mutex); flags &= ~A_HINT_ROOT; rflags |= A_HINT_ROOT; @@ -695,7 +269,7 @@ static void a_map_update_flags_bottomup(const OP *o, UV flags, UV rflags) { } oi->flags = rflags; - A_UNLOCK(&a_op_map_mutex); + XSH_UNLOCK(&a_op_map_mutex); return; } @@ -925,7 +499,7 @@ static OP *a_pp_root_binop(pTHX) { static UV a_do_multideref(const OP *o, UV flags) { UV isexdel, other_flags; - A_ASSERT(o->op_type == OP_MULTIDEREF); + XSH_ASSERT(o->op_type == OP_MULTIDEREF); other_flags = flags & ~A_HINT_DO; @@ -1028,7 +602,7 @@ static OP *a_pp_multideref(pTHX) { { dA_MAP_THX; const a_op_info *oi = a_map_fetch(PL_op); - A_ASSERT(oi); + XSH_ASSERT(oi); flags = a_do_multideref(PL_op, oi->flags); if (!flags) return oi->old_pp(aTHX); @@ -1051,7 +625,7 @@ static OP *a_pp_multideref(pTHX) { goto do_AV_aelem; case MDEREF_AV_gvav_aelem: /* $pkg[...] */ sv = UNOP_AUX_item_sv(++items); - A_ASSERT(isGV_with_GP(sv)); + XSH_ASSERT(isGV_with_GP(sv)); sv = (SV *) GvAVn((GV *) sv); if (a_undef(sv)) goto ret_undef; @@ -1063,7 +637,7 @@ static OP *a_pp_multideref(pTHX) { goto do_AV_rv2av_aelem; case MDEREF_AV_gvsv_vivify_rv2av_aelem: /* $pkg->[...] */ sv = UNOP_AUX_item_sv(++items); - A_ASSERT(isGV_with_GP(sv)); + XSH_ASSERT(isGV_with_GP(sv)); sv = GvSVn((GV *) sv); if (a_undef(sv)) goto ret_undef; @@ -1081,7 +655,7 @@ do_AV_rv2av_aelem: do_AV_aelem: { SV *esv; - A_ASSERT(SvTYPE(sv) == SVt_PVAV); + XSH_ASSERT(SvTYPE(sv) == SVt_PVAV); switch (actions & MDEREF_INDEX_MASK) { case MDEREF_INDEX_none: goto finish; @@ -1093,7 +667,7 @@ do_AV_aelem: goto check_elem; case MDEREF_INDEX_gvsv: esv = UNOP_AUX_item_sv(++items); - A_ASSERT(isGV_with_GP(esv)); + XSH_ASSERT(isGV_with_GP(esv)); esv = GvSVn((GV *) esv); check_elem: if (UNLIKELY(SvROK(esv) && !SvGAMAGIC(esv) && ckWARN(WARN_MISC))) @@ -1130,7 +704,7 @@ check_elem: goto do_HV_helem; case MDEREF_HV_gvhv_helem: /* $pkg{...} */ sv = UNOP_AUX_item_sv(++items); - A_ASSERT(isGV_with_GP(sv)); + XSH_ASSERT(isGV_with_GP(sv)); sv = (SV *) GvHVn((GV *) sv); if (a_undef(sv)) goto ret_undef; @@ -1142,7 +716,7 @@ check_elem: goto do_HV_rv2hv_helem; case MDEREF_HV_gvsv_vivify_rv2hv_helem: /* $pkg->{...} */ sv = UNOP_AUX_item_sv(++items); - A_ASSERT(isGV_with_GP(sv)); + XSH_ASSERT(isGV_with_GP(sv)); sv = GvSVn((GV *) sv); if (a_undef(sv)) goto ret_undef; @@ -1160,7 +734,7 @@ do_HV_rv2hv_helem: do_HV_helem: { SV *key; - A_ASSERT(SvTYPE(sv) == SVt_PVHV); + XSH_ASSERT(SvTYPE(sv) == SVt_PVHV); switch (actions & MDEREF_INDEX_MASK) { case MDEREF_INDEX_none: goto finish; @@ -1172,7 +746,7 @@ do_HV_helem: break; case MDEREF_INDEX_gvsv: key = UNOP_AUX_item_sv(++items); - A_ASSERT(isGV_with_GP(key)); + XSH_ASSERT(isGV_with_GP(key)); key = GvSVn((GV *) key); break; } @@ -1451,34 +1025,18 @@ static OP *a_ck_root(pTHX_ OP *o) { return o; } -/* ... Our peephole optimizer .............................................. */ +/* --- Our peephole optimizer ---------------------------------------------- */ -static void a_peep_rec(pTHX_ OP *o, ptable *seen); - -static void a_peep_rec(pTHX_ OP *o, ptable *seen) { -#define a_peep_rec(O) a_peep_rec(aTHX_ (O), seen) +static void xsh_peep_rec(pTHX_ OP *o, ptable *seen) { for (; o; o = o->op_next) { dA_MAP_THX; const a_op_info *oi = NULL; UV flags = 0; -#if !A_HAS_RPEEP - if (ptable_fetch(seen, o)) + if (xsh_peep_seen(o, seen)) 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: - case OP_UNSTACK: - 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); @@ -1535,192 +1093,89 @@ static void a_peep_rec(pTHX_ OP *o, ptable *seen) { } break; #endif -#if !A_HAS_RPEEP - case OP_MAPWHILE: - case OP_GREPWHILE: - case OP_AND: - case OP_OR: - case OP_ANDASSIGN: - case OP_ORASSIGN: - case OP_COND_EXPR: - case OP_RANGE: -# if A_HAS_PERL(5, 10, 0) - case OP_ONCE: - case OP_DOR: - case OP_DORASSIGN: -# endif - a_peep_rec(cLOGOPo->op_other); - break; - case OP_ENTERLOOP: - case OP_ENTERITER: - a_peep_rec(cLOOPo->op_redoop); - a_peep_rec(cLOOPo->op_nextop); - a_peep_rec(cLOOPo->op_lastop); - break; -# if A_HAS_PERL(5, 9, 5) - case OP_SUBST: - a_peep_rec(cPMOPo->op_pmstashstartu.op_pmreplstart); - break; -# else - case OP_QR: - case OP_MATCH: - case OP_SUBST: - a_peep_rec(cPMOPo->op_pmreplstart); - break; -# endif -#endif /* !A_HAS_RPEEP */ default: + xsh_peep_maybe_recurse(o, seen); break; } } } -static void a_peep(pTHX_ OP *o) { - ptable *seen; - dMY_CXT; - - A_ASSERT(a_is_loaded(&MY_CXT)); - - MY_CXT.old_peep(aTHX_ o); - - seen = MY_CXT.seen; - if (seen) { - ptable_seen_clear(seen); - a_peep_rec(o); - ptable_seen_clear(seen); - } -} - /* --- Module setup/teardown ----------------------------------------------- */ -static void a_teardown(pTHX_ void *root) { - dMY_CXT; - - A_LOADED_LOCK; - - if (a_clear_loaded_locked(&MY_CXT)) { - 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); - - ptable_map_free(a_op_map); - a_op_map = NULL; +static void xsh_user_global_setup(pTHX) { + a_op_map = ptable_new(32); #ifdef USE_ITHREADS - MUTEX_DESTROY(&a_op_map_mutex); + MUTEX_INIT(&a_op_map_mutex); #endif - } - A_LOADED_UNLOCK; + xsh_ck_replace(OP_PADANY, a_ck_padany, &a_old_ck_padany); + xsh_ck_replace(OP_PADSV, a_ck_padsv, &a_old_ck_padsv); - if (MY_CXT.old_peep) { -#if A_HAS_RPEEP - PL_rpeepp = MY_CXT.old_peep; -#else - PL_peepp = MY_CXT.old_peep; -#endif - MY_CXT.old_peep = 0; - } + xsh_ck_replace(OP_AELEM, a_ck_deref, &a_old_ck_aelem); + xsh_ck_replace(OP_HELEM, a_ck_deref, &a_old_ck_helem); + xsh_ck_replace(OP_RV2SV, a_ck_deref, &a_old_ck_rv2sv); + + xsh_ck_replace(OP_RV2AV, a_ck_rv2xv, &a_old_ck_rv2av); + xsh_ck_replace(OP_RV2HV, a_ck_rv2xv, &a_old_ck_rv2hv); - ptable_seen_free(MY_CXT.seen); - MY_CXT.seen = NULL; + xsh_ck_replace(OP_ASLICE, a_ck_xslice, &a_old_ck_aslice); + xsh_ck_replace(OP_HSLICE, a_ck_xslice, &a_old_ck_hslice); -#if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION - ptable_hints_free(MY_CXT.tbl); - MY_CXT.tbl = NULL; -#endif /* A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION */ + xsh_ck_replace(OP_EXISTS, a_ck_root, &a_old_ck_exists); + xsh_ck_replace(OP_DELETE, a_ck_root, &a_old_ck_delete); + xsh_ck_replace(OP_KEYS, a_ck_root, &a_old_ck_keys); + xsh_ck_replace(OP_VALUES, a_ck_root, &a_old_ck_values); return; } -static void a_setup(pTHX) { -#define a_setup() a_setup(aTHX) - MY_CXT_INIT; /* Takes/release PL_my_ctx_mutex */ +static void xsh_user_local_setup(pTHX) { + HV *stash; - A_LOADED_LOCK; + stash = gv_stashpvn(XSH_PACKAGE, XSH_PACKAGE_LEN, 1); + newCONSTSUB(stash, "A_HINT_STRICT", newSVuv(A_HINT_STRICT)); + newCONSTSUB(stash, "A_HINT_WARN", newSVuv(A_HINT_WARN)); + newCONSTSUB(stash, "A_HINT_FETCH", newSVuv(A_HINT_FETCH)); + newCONSTSUB(stash, "A_HINT_STORE", newSVuv(A_HINT_STORE)); + newCONSTSUB(stash, "A_HINT_EXISTS", newSVuv(A_HINT_EXISTS)); + newCONSTSUB(stash, "A_HINT_DELETE", newSVuv(A_HINT_DELETE)); + newCONSTSUB(stash, "A_HINT_MASK", newSVuv(A_HINT_MASK)); + newCONSTSUB(stash, "A_THREADSAFE", newSVuv(XSH_THREADSAFE)); + newCONSTSUB(stash, "A_FORKSAFE", newSVuv(XSH_FORKSAFE)); - if (a_set_loaded_locked(&MY_CXT)) { - PERL_HASH(a_hash, __PACKAGE__, __PACKAGE_LEN__); - - a_op_map = ptable_new(); - -#ifdef USE_ITHREADS - MUTEX_INIT(&a_op_map_mutex); -#endif + return; +} - a_ck_replace(OP_PADANY, a_ck_padany, &a_old_ck_padany); - a_ck_replace(OP_PADSV, a_ck_padsv, &a_old_ck_padsv); +static void xsh_user_local_teardown(pTHX) { + return; +} - 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); +static void xsh_user_global_teardown(pTHX) { + xsh_ck_restore(OP_PADANY, &a_old_ck_padany); + xsh_ck_restore(OP_PADSV, &a_old_ck_padsv); - a_ck_replace(OP_RV2AV, a_ck_rv2xv, &a_old_ck_rv2av); - a_ck_replace(OP_RV2HV, a_ck_rv2xv, &a_old_ck_rv2hv); + xsh_ck_restore(OP_AELEM, &a_old_ck_aelem); + xsh_ck_restore(OP_HELEM, &a_old_ck_helem); + xsh_ck_restore(OP_RV2SV, &a_old_ck_rv2sv); - a_ck_replace(OP_ASLICE, a_ck_xslice, &a_old_ck_aslice); - a_ck_replace(OP_HSLICE, a_ck_xslice, &a_old_ck_hslice); + xsh_ck_restore(OP_RV2AV, &a_old_ck_rv2av); + xsh_ck_restore(OP_RV2HV, &a_old_ck_rv2hv); - 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); - } + xsh_ck_restore(OP_ASLICE, &a_old_ck_aslice); + xsh_ck_restore(OP_HSLICE, &a_old_ck_hslice); - A_LOADED_UNLOCK; + xsh_ck_restore(OP_EXISTS, &a_old_ck_exists); + xsh_ck_restore(OP_DELETE, &a_old_ck_delete); + xsh_ck_restore(OP_KEYS, &a_old_ck_keys); + xsh_ck_restore(OP_VALUES, &a_old_ck_values); - { - HV *stash; - - stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1); - newCONSTSUB(stash, "A_HINT_STRICT", newSVuv(A_HINT_STRICT)); - newCONSTSUB(stash, "A_HINT_WARN", newSVuv(A_HINT_WARN)); - newCONSTSUB(stash, "A_HINT_FETCH", newSVuv(A_HINT_FETCH)); - newCONSTSUB(stash, "A_HINT_STORE", newSVuv(A_HINT_STORE)); - newCONSTSUB(stash, "A_HINT_EXISTS", newSVuv(A_HINT_EXISTS)); - newCONSTSUB(stash, "A_HINT_DELETE", newSVuv(A_HINT_DELETE)); - newCONSTSUB(stash, "A_HINT_MASK", newSVuv(A_HINT_MASK)); - newCONSTSUB(stash, "A_THREADSAFE", newSVuv(A_THREADSAFE)); - newCONSTSUB(stash, "A_FORKSAFE", newSVuv(A_FORKSAFE)); - } + ptable_map_free(a_op_map); + a_op_map = NULL; -#if A_HAS_RPEEP - if (PL_rpeepp != a_peep) { - MY_CXT.old_peep = PL_rpeepp; - PL_rpeepp = a_peep; - } -#else - if (PL_peepp != a_peep) { - MY_CXT.old_peep = PL_peepp; - PL_peepp = a_peep; - } +#ifdef USE_ITHREADS + MUTEX_DESTROY(&a_op_map_mutex); #endif - else { - MY_CXT.old_peep = 0; - } - - MY_CXT.seen = ptable_new(); - -#if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION - MY_CXT.tbl = ptable_new(); - MY_CXT.owner = aTHX; -#endif /* A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION */ - - call_atexit(a_teardown, NULL); return; } @@ -1733,53 +1188,25 @@ PROTOTYPES: ENABLE BOOT: { - a_setup(); + xsh_setup(); } -#if A_THREADSAFE +#if XSH_THREADSAFE void CLONE(...) PROTOTYPE: DISABLE -PREINIT: -#if A_WORKAROUND_REQUIRE_PROPAGATION - ptable *t; -#endif PPCODE: -#if A_WORKAROUND_REQUIRE_PROPAGATION - { - a_ptable_clone_ud ud; - dMY_CXT; - t = ptable_new(); - a_ptable_clone_ud_init(ud, t, MY_CXT.owner); - ptable_walk(MY_CXT.tbl, a_ptable_clone, &ud); - a_ptable_clone_ud_deinit(ud); - } -#endif - { - MY_CXT_CLONE; -#if A_WORKAROUND_REQUIRE_PROPAGATION - MY_CXT.tbl = t; - MY_CXT.owner = aTHX; -#endif - MY_CXT.seen = ptable_new(); - { - int global_setup; - A_LOADED_LOCK; - global_setup = a_set_loaded_locked(&MY_CXT); - A_ASSERT(!global_setup); - A_LOADED_UNLOCK; - } - } + xsh_clone(); XSRETURN(0); -#endif /* A_THREADSAFE */ +#endif /* XSH_THREADSAFE */ SV * _tag(SV *hint) PROTOTYPE: $ CODE: - RETVAL = a_tag(SvOK(hint) ? SvUV(hint) : 0); + RETVAL = xsh_hints_tag(SvOK(hint) ? SvUV(hint) : 0); OUTPUT: RETVAL @@ -1789,6 +1216,6 @@ PROTOTYPE: $ CODE: if (!SvOK(tag)) XSRETURN_UNDEF; - RETVAL = newSVuv(a_detag(tag)); + RETVAL = newSVuv(xsh_hints_detag(tag)); OUTPUT: RETVAL