X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2Findirect.git;a=blobdiff_plain;f=indirect.xs;h=dedc58bb453c9003a10980dc27dda2a774dde32a;hp=00622a5c10f5b2d5b3488ed2ca40f8b600dfdffe;hb=e3609d4f5df9ec09d582f3e60b92e6e8263cd6cd;hpb=c07766a234204d78a80b6d75534e03ae3465b6f3 diff --git a/indirect.xs b/indirect.xs index 00622a5..dedc58b 100644 --- a/indirect.xs +++ b/indirect.xs @@ -62,9 +62,6 @@ #define I_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S)))))) #if I_HAS_PERL(5, 10, 0) || defined(PL_parser) -# ifndef PL_lex_inwhat -# define PL_lex_inwhat PL_parser->lex_inwhat -# endif # ifndef PL_linestr # define PL_linestr PL_parser->linestr # endif @@ -75,9 +72,6 @@ # define PL_oldbufptr PL_parser->oldbufptr # endif #else -# ifndef PL_lex_inwhat -# define PL_lex_inwhat PL_Ilex_inwhat -# endif # ifndef PL_linestr # define PL_linestr PL_Ilinestr # endif @@ -90,11 +84,16 @@ #endif #ifndef I_WORKAROUND_REQUIRE_PROPAGATION -# define I_WORKAROUND_REQUIRE_PROPAGATION !I_HAS_PERL(5, 10, 1) +# define I_WORKAROUND_REQUIRE_PROPAGATION !I_HAS_PERL(5, 12, 0) #endif /* ... Thread safety and multiplicity ...................................... */ +/* Safe unless stated otherwise in Makefile.PL */ +#ifndef I_FORKSAFE +# define I_FORKSAFE 1 +#endif + #ifndef I_MULTIPLICITY # if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT) # define I_MULTIPLICITY 1 @@ -133,21 +132,39 @@ /* ... Thread-safe hints ................................................... */ -/* If any of those are true, we need to store the hint in a global table. */ - -#if I_THREADSAFE || I_WORKAROUND_REQUIRE_PROPAGATION +#if I_WORKAROUND_REQUIRE_PROPAGATION typedef struct { - SV *code; -#if I_WORKAROUND_REQUIRE_PROPAGATION - I32 requires; -#endif + SV *code; + IV require_tag; } indirect_hint_t; -#define PTABLE_NAME ptable_hints +#define I_HINT_STRUCT 1 + +#define I_HINT_CODE(H) ((H)->code) + +#define I_HINT_FREE(H) { \ + indirect_hint_t *h = (H); \ + SvREFCNT_dec(h->code); \ + PerlMemShared_free(h); \ +} + +#else /* I_WORKAROUND_REQUIRE_PROPAGATION */ -#define PTABLE_VAL_FREE(V) \ - { indirect_hint_t *h = (V); SvREFCNT_dec(h->code); PerlMemShared_free(h); } +typedef SV indirect_hint_t; + +#define I_HINT_STRUCT 0 + +#define I_HINT_CODE(H) (H) + +#define I_HINT_FREE(H) SvREFCNT_dec(H); + +#endif /* !I_WORKAROUND_REQUIRE_PROPAGATION */ + +#if I_THREADSAFE + +#define PTABLE_NAME ptable_hints +#define PTABLE_VAL_FREE(V) I_HINT_FREE(V) #define pPTBL pTHX #define pPTBL_ pTHX_ @@ -159,16 +176,17 @@ typedef struct { #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 /* I_THREADSAFE || I_WORKAROUND_REQUIRE_PROPAGATION */ +#endif /* I_THREADSAFE */ /* Define the op->str ptable here because we need to be able to clean it during * thread cleanup. */ typedef struct { - const char *pos; - char *buf; - STRLEN len, size; - line_t line; + STRLEN pos; + STRLEN size; + STRLEN len; + char *buf; + line_t line; } indirect_op_info_t; #define PTABLE_NAME ptable @@ -188,14 +206,11 @@ typedef struct { #define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION typedef struct { -#if I_THREADSAFE || I_WORKAROUND_REQUIRE_PROPAGATION - ptable *tbl; /* It really is a ptable_hints */ -#endif - ptable *map; - const char *linestr; #if I_THREADSAFE - tTHX owner; + ptable *tbl; /* It really is a ptable_hints */ + tTHX owner; #endif + ptable *map; } my_cxt_t; START_MY_CXT @@ -228,38 +243,87 @@ STATIC SV *indirect_clone(pTHX_ SV *sv, tTHX owner) { STATIC void indirect_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) { my_cxt_t *ud = ud_; indirect_hint_t *h1 = ent->val; - indirect_hint_t *h2 = PerlMemShared_malloc(sizeof *h2); + indirect_hint_t *h2; - *h2 = *h1; + if (ud->owner == aTHX) + return; - if (ud->owner != aTHX) - h2->code = indirect_clone(h1->code, ud->owner); +#if I_HINT_STRUCT - ptable_hints_store(ud->tbl, ent->key, h2); + h2 = PerlMemShared_malloc(sizeof *h2); + h2->code = indirect_clone(h1->code, ud->owner); SvREFCNT_inc(h2->code); +#if I_WORKAROUND_REQUIRE_PROPAGATION + h2->require_tag = PTR2IV(indirect_clone(INT2PTR(SV *, h1->require_tag), + ud->owner)); +#endif + +#else /* I_HINT_STRUCT */ + + h2 = indirect_clone(h1, ud->owner); + SvREFCNT_inc(h2); + +#endif /* !I_HINT_STRUCT */ + + ptable_hints_store(ud->tbl, ent->key, h2); } -STATIC void indirect_thread_cleanup(pTHX_ void *); +#include "reap.h" STATIC void indirect_thread_cleanup(pTHX_ void *ud) { - int *level = ud; + dMY_CXT; - if (*level) { - *level = 0; - LEAVE; - SAVEDESTRUCTOR_X(indirect_thread_cleanup, level); - ENTER; - } else { - dMY_CXT; - PerlMemShared_free(level); - ptable_free(MY_CXT.map); - ptable_hints_free(MY_CXT.tbl); - } + ptable_free(MY_CXT.map); + ptable_hints_free(MY_CXT.tbl); } #endif /* I_THREADSAFE */ -#if I_THREADSAFE || I_WORKAROUND_REQUIRE_PROPAGATION +#if I_WORKAROUND_REQUIRE_PROPAGATION +STATIC IV indirect_require_tag(pTHX) { +#define indirect_require_tag() indirect_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); +} +#endif /* I_WORKAROUND_REQUIRE_PROPAGATION */ STATIC SV *indirect_tag(pTHX_ SV *value) { #define indirect_tag(V) indirect_tag(aTHX_ (V)) @@ -271,39 +335,26 @@ STATIC SV *indirect_tag(pTHX_ SV *value) { value = SvRV(value); if (SvTYPE(value) >= SVt_PVCV) { code = value; - if (CvANON(code) && !CvCLONED(code)) - CvCLONE_on(code); SvREFCNT_inc_simple_NN(code); } } +#if I_HINT_STRUCT h = PerlMemShared_malloc(sizeof *h); - h->code = code; - -#if I_WORKAROUND_REQUIRE_PROPAGATION - { - const PERL_SI *si; - I32 requires = 0; - - 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; - } - } - - h->requires = requires; - } -#endif + h->code = code; +# if I_WORKAROUND_REQUIRE_PROPAGATION + h->require_tag = indirect_require_tag(); +# endif /* I_WORKAROUND_REQUIRE_PROPAGATION */ +#else /* I_HINT_STRUCT */ + h = code; +#endif /* !I_HINT_STRUCT */ +#if I_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 /* I_THREADSAFE */ return newSViv(PTR2IV(h)); } @@ -316,97 +367,44 @@ STATIC SV *indirect_detag(pTHX_ const SV *hint) { if (!(hint && SvIOK(hint))) return NULL; - h = ptable_fetch(MY_CXT.tbl, INT2PTR(void *, SvIVX(hint))); + h = INT2PTR(indirect_hint_t *, SvIVX(hint)); +#if I_THREADSAFE + h = ptable_fetch(MY_CXT.tbl, h); +#endif /* I_THREADSAFE */ #if I_WORKAROUND_REQUIRE_PROPAGATION - { - const PERL_SI *si; - I32 requires = 0; - - 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 > h->requires) - return NULL; - } - } - } -#endif - - return h->code; -} - -#else - -STATIC SV *indirect_tag(pTHX_ SV *value) { -#define indirect_tag(V) indirect_tag(aTHX_ (V)) - UV tag = 0; - - if (SvROK(value)) { - value = SvRV(value); - SvREFCNT_inc_simple_NN(value); - tag = PTR2IV(value); - } + if (indirect_require_tag() != h->require_tag) + return NULL; +#endif /* I_WORKAROUND_REQUIRE_PROPAGATION */ - return newSViv(tag); + return I_HINT_CODE(h); } -#define indirect_detag(H) (((H) && SvIOK(H)) ? INT2PTR(SV *, SvIVX(H)) : NULL) - -#endif /* I_THREADSAFE || I_WORKAROUND_REQUIRE_PROPAGATION */ - STATIC U32 indirect_hash = 0; STATIC SV *indirect_hint(pTHX) { #define indirect_hint() indirect_hint(aTHX) - SV *hint; + SV **val; if (IN_PERL_RUNTIME) return NULL; -#if I_HAS_PERL(5, 9, 5) - hint = Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash, - NULL, - __PACKAGE__, __PACKAGE_LEN__, - 0, - indirect_hash); -#else - { - SV **val = hv_fetch(GvHV(PL_hintgv), __PACKAGE__, __PACKAGE_LEN__, - indirect_hash); - if (!val) - return 0; - hint = *val; - } -#endif - return indirect_detag(hint); + val = hv_fetch(GvHV(PL_hintgv), __PACKAGE__, __PACKAGE_LEN__, indirect_hash); + if (!val) + return NULL; + + return indirect_detag(*val); } /* ... op -> source position ............................................... */ -STATIC void indirect_map_store(pTHX_ const OP *o, const char *src, SV *sv, line_t line) { -#define indirect_map_store(O, S, N, L) indirect_map_store(aTHX_ (O), (S), (N), (L)) +STATIC void indirect_map_store(pTHX_ const OP *o, STRLEN pos, SV *sv, line_t line) { +#define indirect_map_store(O, P, N, L) indirect_map_store(aTHX_ (O), (P), (N), (L)) indirect_op_info_t *oi; const char *s; STRLEN len; dMY_CXT; - /* When lex_inwhat is set, we're in a quotelike environment (qq, qr, but not q) - * In this case the linestr has temporarly changed, but the old buffer should - * still be alive somewhere. */ - - if (!PL_lex_inwhat) { - const char *pl_linestr = SvPVX_const(PL_linestr); - if (MY_CXT.linestr != pl_linestr) { - ptable_clear(MY_CXT.map); - MY_CXT.linestr = pl_linestr; - } - } - if (!(oi = ptable_fetch(MY_CXT.map, o))) { Newx(oi, 1, indirect_op_info_t); ptable_store(MY_CXT.map, o, oi); @@ -429,18 +427,14 @@ STATIC void indirect_map_store(pTHX_ const OP *o, const char *src, SV *sv, line_ Copy(s, oi->buf, len, char); oi->len = len; - oi->pos = src; + oi->pos = pos; oi->line = line; } STATIC const indirect_op_info_t *indirect_map_fetch(pTHX_ const OP *o) { #define indirect_map_fetch(O) indirect_map_fetch(aTHX_ (O)) - const indirect_op_info_t *val; dMY_CXT; - if (MY_CXT.linestr != SvPVX_const(PL_linestr)) - return NULL; - return ptable_fetch(MY_CXT.map, o); } @@ -453,28 +447,35 @@ STATIC void indirect_map_delete(pTHX_ const OP *o) { /* --- Check functions ----------------------------------------------------- */ -STATIC const char *indirect_find(pTHX_ SV *sv, const char *s) { -#define indirect_find(N, S) indirect_find(aTHX_ (N), (S)) +STATIC int indirect_find(pTHX_ SV *sv, const char *s, STRLEN *pos) { +#define indirect_find(N, S, P) indirect_find(aTHX_ (N), (S), (P)) STRLEN len; - const char *p = NULL, *r = SvPV_const(sv, len); + const char *p, *r = SvPV_const(sv, len); if (len >= 1 && *r == '$') { ++r; --len; s = strchr(s, '$'); if (!s) - return NULL; + return 0; } - p = strstr(s, r); - while (p) { - p += len; - if (!isALNUM(*p)) + p = s; + while (1) { + p = strstr(p, r); + if (!p) + return 0; + if (!isALNUM(p[len])) break; - p = strstr(p + 1, r); + /* p points to a word that has r as prefix, skip the rest of the word */ + p += len + 1; + while (isALNUM(*p)) + ++p; } - return p; + *pos = p - SvPVX_const(PL_linestr); + + return 1; } /* ... ck_const ............................................................ */ @@ -486,10 +487,14 @@ STATIC OP *indirect_ck_const(pTHX_ OP *o) { if (indirect_hint()) { SV *sv = cSVOPo_sv; + if (SvPOK(sv) && (SvTYPE(sv) >= SVt_PV)) { - const char *s = indirect_find(sv, PL_oldbufptr); - indirect_map_store(o, s, sv, CopLINE(&PL_compiling)); - return o; + STRLEN pos; + + if (indirect_find(sv, PL_oldbufptr, &pos)) { + indirect_map_store(o, pos, sv, CopLINE(&PL_compiling)); + return o; + } } } @@ -505,8 +510,8 @@ STATIC OP *indirect_ck_rv2sv(pTHX_ OP *o) { if (indirect_hint()) { OP *op = cUNOPo->op_first; SV *sv; - const char *name = NULL, *s; - STRLEN len; + const char *name = NULL; + STRLEN pos, len; OPCODE type = (OPCODE) op->op_type; switch (type) { @@ -529,8 +534,8 @@ STATIC OP *indirect_ck_rv2sv(pTHX_ OP *o) { sv = sv_2mortal(newSVpvn("$", 1)); sv_catpvn_nomg(sv, name, len); - s = indirect_find(sv, PL_oldbufptr); - if (!s) { /* If it failed, retry without the current stash */ + if (!indirect_find(sv, PL_oldbufptr, &pos)) { + /* If it failed, retry without the current stash */ const char *stash = HvNAME_get(PL_curstash); STRLEN stashlen = HvNAMELEN_get(PL_curstash); @@ -547,13 +552,13 @@ STATIC OP *indirect_ck_rv2sv(pTHX_ OP *o) { sv_setpvn(sv, "$", 1); stashlen += 2; sv_catpvn_nomg(sv, name + stashlen, len - stashlen); - s = indirect_find(sv, PL_oldbufptr); - if (!s) + if (!indirect_find(sv, PL_oldbufptr, &pos)) goto done; } o = CALL_FPTR(indirect_old_ck_rv2sv)(aTHX_ o); - indirect_map_store(o, s, sv, CopLINE(&PL_compiling)); + + indirect_map_store(o, pos, sv, CopLINE(&PL_compiling)); return o; } @@ -581,7 +586,8 @@ STATIC OP *indirect_ck_padany(pTHX_ OP *o) { while (s < t && isSPACE(*t)) --t; sv = sv_2mortal(newSVpvn("$", 1)); sv_catpvn_nomg(sv, s, t - s + 1); - indirect_map_store(o, s, sv, CopLINE(&PL_compiling)); + indirect_map_store(o, s - SvPVX_const(PL_linestr), + sv, CopLINE(&PL_compiling)); return o; } } @@ -605,7 +611,8 @@ STATIC OP *indirect_ck_scope(pTHX_ OP *o) { o = CALL_FPTR(old_ck)(aTHX_ o); if (indirect_hint()) { - indirect_map_store(o, PL_oldbufptr, NULL, CopLINE(&PL_compiling)); + indirect_map_store(o, PL_oldbufptr - SvPVX_const(PL_linestr), + NULL, CopLINE(&PL_compiling)); return o; } @@ -623,28 +630,30 @@ STATIC OP *(*indirect_old_ck_method)(pTHX_ OP *) = 0; STATIC OP *indirect_ck_method(pTHX_ OP *o) { if (indirect_hint()) { OP *op = cUNOPo->op_first; - const indirect_op_info_t *oi = indirect_map_fetch(op); - const char *s = NULL; - line_t line; - SV *sv; - if (oi && (s = oi->pos)) { - sv = sv_2mortal(newSVpvn(oi->buf, oi->len)); - line = oi->line; /* Keep the old line so that we really point to the first */ - } else { - sv = cSVOPx_sv(op); - if (!SvPOK(sv) || (SvTYPE(sv) < SVt_PV)) + /* Indirect method call is only possible when the method is a bareword, so + * don't trip up on $obj->$meth. */ + if (op && op->op_type == OP_CONST) { + const indirect_op_info_t *oi = indirect_map_fetch(op); + STRLEN pos; + line_t line; + SV *sv; + + if (!oi) goto done; - sv = sv_mortalcopy(sv); - s = indirect_find(sv, PL_oldbufptr); - line = CopLINE(&PL_compiling); - } - o = CALL_FPTR(indirect_old_ck_method)(aTHX_ o); - /* o may now be a method_named */ + sv = sv_2mortal(newSVpvn(oi->buf, oi->len)); + pos = oi->pos; + /* Keep the old line so that we really point to the first line of the + * expression. */ + line = oi->line; - indirect_map_store(o, s, sv, line); - return o; + o = CALL_FPTR(indirect_old_ck_method)(aTHX_ o); + /* o may now be a method_named */ + + indirect_map_store(o, pos, sv, line); + return o; + } } done: @@ -654,18 +663,43 @@ done: return o; } -/* ... ck_entersub ......................................................... */ +/* ... ck_method_named ..................................................... */ -STATIC int indirect_is_indirect(const indirect_op_info_t *moi, const indirect_op_info_t *ooi) { - if (moi->pos > ooi->pos) - return 0; +/* "use foo/no foo" compiles its call to import/unimport directly to a + * method_named op. */ - if (moi->pos == ooi->pos) - return moi->len == ooi->len && !memcmp(moi->buf, ooi->buf, moi->len); +STATIC OP *(*indirect_old_ck_method_named)(pTHX_ OP *) = 0; - return 1; +STATIC OP *indirect_ck_method_named(pTHX_ OP *o) { + if (indirect_hint()) { + STRLEN pos; + line_t line; + SV *sv; + + sv = cSVOPo_sv; + if (!SvPOK(sv) || (SvTYPE(sv) < SVt_PV)) + goto done; + sv = sv_mortalcopy(sv); + + if (!indirect_find(sv, PL_oldbufptr, &pos)) + goto done; + line = CopLINE(&PL_compiling); + + o = CALL_FPTR(indirect_old_ck_method_named)(aTHX_ o); + + indirect_map_store(o, pos, sv, line); + return o; + } + +done: + o = CALL_FPTR(indirect_old_ck_method_named)(aTHX_ o); + + indirect_map_delete(o); + return o; } +/* ... ck_entersub ......................................................... */ + STATIC OP *(*indirect_old_ck_entersub)(pTHX_ OP *) = 0; STATIC OP *indirect_ck_entersub(pTHX_ OP *o) { @@ -708,14 +742,17 @@ STATIC OP *indirect_ck_entersub(pTHX_ OP *o) { goto done; moi = indirect_map_fetch(mop); - if (!(moi && moi->pos)) + if (!moi) goto done; ooi = indirect_map_fetch(oop); - if (!(ooi && ooi->pos)) + if (!ooi) goto done; - if (indirect_is_indirect(moi, ooi)) { + /* When positions are identical, the method and the object must have the + * same name. But it also means that it is an indirect call, as "foo->foo" + * results in different positions. */ + if (moi->pos <= ooi->pos) { SV *file; dSP; @@ -751,6 +788,86 @@ done: STATIC U32 indirect_initialized = 0; +STATIC void indirect_teardown(pTHX_ void *root) { + dMY_CXT; + + if (!indirect_initialized) + return; + +#if I_MULTIPLICITY + if (aTHX != root) + return; +#endif + + ptable_free(MY_CXT.map); +#if I_THREADSAFE + ptable_hints_free(MY_CXT.tbl); +#endif + + PL_check[OP_CONST] = MEMBER_TO_FPTR(indirect_old_ck_const); + indirect_old_ck_const = 0; + PL_check[OP_RV2SV] = MEMBER_TO_FPTR(indirect_old_ck_rv2sv); + indirect_old_ck_rv2sv = 0; + PL_check[OP_PADANY] = MEMBER_TO_FPTR(indirect_old_ck_padany); + indirect_old_ck_padany = 0; + PL_check[OP_SCOPE] = MEMBER_TO_FPTR(indirect_old_ck_scope); + indirect_old_ck_scope = 0; + PL_check[OP_LINESEQ] = MEMBER_TO_FPTR(indirect_old_ck_lineseq); + indirect_old_ck_lineseq = 0; + + PL_check[OP_METHOD] = MEMBER_TO_FPTR(indirect_old_ck_method); + indirect_old_ck_method = 0; + PL_check[OP_METHOD_NAMED] = MEMBER_TO_FPTR(indirect_old_ck_method_named); + indirect_old_ck_method_named = 0; + PL_check[OP_ENTERSUB] = MEMBER_TO_FPTR(indirect_old_ck_entersub); + indirect_old_ck_entersub = 0; + + indirect_initialized = 0; +} + +STATIC void indirect_setup(pTHX) { +#define indirect_setup() indirect_setup(aTHX) + if (indirect_initialized) + return; + + { + MY_CXT_INIT; +#if I_THREADSAFE + MY_CXT.tbl = ptable_new(); + MY_CXT.owner = aTHX; +#endif + MY_CXT.map = ptable_new(); + } + + indirect_old_ck_const = PL_check[OP_CONST]; + PL_check[OP_CONST] = MEMBER_TO_FPTR(indirect_ck_const); + indirect_old_ck_rv2sv = PL_check[OP_RV2SV]; + PL_check[OP_RV2SV] = MEMBER_TO_FPTR(indirect_ck_rv2sv); + indirect_old_ck_padany = PL_check[OP_PADANY]; + PL_check[OP_PADANY] = MEMBER_TO_FPTR(indirect_ck_padany); + indirect_old_ck_scope = PL_check[OP_SCOPE]; + PL_check[OP_SCOPE] = MEMBER_TO_FPTR(indirect_ck_scope); + indirect_old_ck_lineseq = PL_check[OP_LINESEQ]; + PL_check[OP_LINESEQ] = MEMBER_TO_FPTR(indirect_ck_scope); + + indirect_old_ck_method = PL_check[OP_METHOD]; + PL_check[OP_METHOD] = MEMBER_TO_FPTR(indirect_ck_method); + indirect_old_ck_method_named = PL_check[OP_METHOD_NAMED]; + PL_check[OP_METHOD_NAMED] = MEMBER_TO_FPTR(indirect_ck_method_named); + indirect_old_ck_entersub = PL_check[OP_ENTERSUB]; + PL_check[OP_ENTERSUB] = MEMBER_TO_FPTR(indirect_ck_entersub); + +#if I_MULTIPLICITY + call_atexit(indirect_teardown, aTHX); +#else + call_atexit(indirect_teardown, NULL); +#endif + + indirect_initialized = 1; +} + +STATIC U32 indirect_booted = 0; + /* --- XS ------------------------------------------------------------------ */ MODULE = indirect PACKAGE = indirect @@ -759,40 +876,17 @@ PROTOTYPES: ENABLE BOOT: { - if (!indirect_initialized++) { + if (!indirect_booted++) { HV *stash; - MY_CXT_INIT; - MY_CXT.map = ptable_new(); - MY_CXT.linestr = NULL; -#if I_THREADSAFE || I_WORKAROUND_REQUIRE_PROPAGATION - MY_CXT.tbl = ptable_new(); -#endif -#if I_THREADSAFE - MY_CXT.owner = aTHX; -#endif - PERL_HASH(indirect_hash, __PACKAGE__, __PACKAGE_LEN__); - indirect_old_ck_const = PL_check[OP_CONST]; - PL_check[OP_CONST] = MEMBER_TO_FPTR(indirect_ck_const); - indirect_old_ck_rv2sv = PL_check[OP_RV2SV]; - PL_check[OP_RV2SV] = MEMBER_TO_FPTR(indirect_ck_rv2sv); - indirect_old_ck_padany = PL_check[OP_PADANY]; - PL_check[OP_PADANY] = MEMBER_TO_FPTR(indirect_ck_padany); - indirect_old_ck_scope = PL_check[OP_SCOPE]; - PL_check[OP_SCOPE] = MEMBER_TO_FPTR(indirect_ck_scope); - indirect_old_ck_lineseq = PL_check[OP_LINESEQ]; - PL_check[OP_LINESEQ] = MEMBER_TO_FPTR(indirect_ck_scope); - - indirect_old_ck_method = PL_check[OP_METHOD]; - PL_check[OP_METHOD] = MEMBER_TO_FPTR(indirect_ck_method); - indirect_old_ck_entersub = PL_check[OP_ENTERSUB]; - PL_check[OP_ENTERSUB] = MEMBER_TO_FPTR(indirect_ck_entersub); - stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1); newCONSTSUB(stash, "I_THREADSAFE", newSVuv(I_THREADSAFE)); + newCONSTSUB(stash, "I_FORKSAFE", newSVuv(I_FORKSAFE)); } + + indirect_setup(); } #if I_THREADSAFE @@ -802,8 +896,7 @@ CLONE(...) PROTOTYPE: DISABLE PREINIT: ptable *t; - int *level; -CODE: +PPCODE: { my_cxt_t ud; dMY_CXT; @@ -813,18 +906,12 @@ CODE: } { MY_CXT_CLONE; - MY_CXT.map = ptable_new(); - MY_CXT.linestr = NULL; - MY_CXT.tbl = t; - MY_CXT.owner = aTHX; - } - { - level = PerlMemShared_malloc(sizeof *level); - *level = 1; - LEAVE; - SAVEDESTRUCTOR_X(indirect_thread_cleanup, level); - ENTER; + MY_CXT.map = ptable_new(); + MY_CXT.tbl = t; + MY_CXT.owner = aTHX; } + reap(3, indirect_thread_cleanup, NULL); + XSRETURN(0); #endif