X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Upper.xs;h=afb1275492c19352f46c44c3ee64c1d735d1fcc9;hb=cd6c4556ac24d07bb96ec65c3c3d5cdfa1850219;hp=f89f1dc2982b15bc83324010f15b45c838915308;hpb=94447dd11718ac77b9608e0528c5d3d090e63aa1;p=perl%2Fmodules%2FScope-Upper.git diff --git a/Upper.xs b/Upper.xs index f89f1dc..afb1275 100644 --- a/Upper.xs +++ b/Upper.xs @@ -66,6 +66,50 @@ #define SU_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S)))))) +/* --- Threads and multiplicity -------------------------------------------- */ + +#ifndef NOOP +# define NOOP +#endif + +#ifndef dNOOP +# define dNOOP +#endif + +#ifndef SU_MULTIPLICITY +# if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT) +# define SU_MULTIPLICITY 1 +# else +# define SU_MULTIPLICITY 0 +# endif +#endif +#if SU_MULTIPLICITY && !defined(tTHX) +# define tTHX PerlInterpreter* +#endif + +#if SU_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 SU_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 SU_THREADSAFE 0 +# undef dMY_CXT +# define dMY_CXT dNOOP +# undef MY_CXT +# define MY_CXT su_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 + /* --- Stack manipulations ------------------------------------------------- */ #ifndef SvCANEXISTDELETE @@ -93,7 +137,6 @@ STATIC I32 su_av_key2idx(pTHX_ AV *av, I32 key) { if (SvRMAGICAL(av)) { const MAGIC * const tied_magic = mg_find((SV *) av, PERL_MAGIC_tied); if (tied_magic) { - int adjust_index = 1; SV * const * const negative_indices_glob = hv_fetch(SvSTASH(SvRV(SvTIED_obj((SV *) (av), tied_magic))), NEGATIVE_INDICES_VAR, 16, 0); @@ -204,7 +247,7 @@ STATIC void su_save_helem(pTHX_ HV *hv, SV *keysv, SV *val) { if (val) { /* local $x{$keysv} = $val; */ SvSetMagicSV(*svp, val); } else { /* local $x{$keysv}; delete $x{$keysv}; */ - hv_delete_ent(hv, keysv, G_DISCARD, HeHASH(he)); + (void)hv_delete_ent(hv, keysv, G_DISCARD, HeHASH(he)); } } @@ -252,11 +295,12 @@ STATIC void su_call(pTHX_ void *ud_) { * when the new sub scope will be created in call_sv. */ #if SU_HAS_PERL(5, 10, 0) - if (dieing) + if (dieing) { if (cxstack_ix < cxstack_max) ++cxstack_ix; else cxstack_ix = Perl_cxinc(aTHX); + } #endif call_sv(ud->cb, G_VOID); @@ -307,11 +351,9 @@ STATIC void su_localize(pTHX_ void *ud_) { if (SvTYPE(sv) >= SVt_PVGV) { gv = (GV *) sv; - if (!val) { /* local *x; */ + if (!val || !SvROK(val)) { /* local *x; or local *x = $val; */ t = SVt_PVGV; - } else if (!SvROK(val)) { /* local *x = $val; */ - goto assign; - } else { /* local *x = \$val; */ + } else { /* local *x = \$val; */ t = SvTYPE(SvRV(val)); deref = 1; } @@ -377,7 +419,6 @@ STATIC void su_localize(pTHX_ void *ud_) { break; default: gv = (GV *) save_scalar(gv); -maybe_deref: if (deref) /* val != NULL */ val = SvRV(val); break; @@ -387,7 +428,6 @@ maybe_deref: ud, PL_savestack_ix, PL_scopestack[PL_scopestack_ix])); -assign: if (val) SvSetMagicSV((SV *) gv, val); @@ -445,22 +485,21 @@ STATIC void su_pop(pTHX_ void *ud) { /* --- Initialize the stack and the action userdata ------------------------ */ -STATIC I32 su_init(pTHX_ I32 level, void *ud, I32 size) { +STATIC I32 su_init(pTHX_ I32 cxix, void *ud, I32 size) { #define su_init(L, U, S) su_init(aTHX_ (L), (U), (S)) I32 i, depth = 0, *origin; - I32 cur, last, step; LEAVE; - if (level <= 0) { + if (cxix >= cxstack_ix) { SU_UD_HANDLER(ud)(aTHX_ ud); goto done; } - SU_D(PerlIO_printf(Perl_debug_log, "%p: ### init for level %d\n", ud, level)); + SU_D(PerlIO_printf(Perl_debug_log, "%p: ### init for cx %d\n", ud, cxix)); - for (i = 0; i < level; ++i) { - PERL_CONTEXT *cx = &cxstack[cxstack_ix - i]; + for (i = cxstack_ix; i > cxix; --i) { + PERL_CONTEXT *cx = cxstack + i; switch (CxTYPE(cx)) { #if SU_HAS_PERL(5, 11, 0) case CXt_LOOP_FOR: @@ -515,21 +554,32 @@ done: return depth; } -/* --- Unwind stack -------------------------------------------------------- */ +/* --- Global data --------------------------------------------------------- */ + +#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION typedef struct { I32 cxix; I32 items; -} su_ud_unwind; + SV **savesp; + OP fakeop; +} my_cxt_t; + +START_MY_CXT + +/* --- Unwind stack -------------------------------------------------------- */ STATIC void su_unwind(pTHX_ void *ud_) { - su_ud_unwind *ud = (su_ud_unwind *) ud_; - OP fakeop; - I32 cxix = ud->cxix; - I32 items = ud->items - 1; - I32 gimme, mark; + dMY_CXT; + I32 cxix = MY_CXT.cxix; + I32 items = MY_CXT.items - 1; + SV **savesp = MY_CXT.savesp; + I32 mark; - gimme = GIMME_V; + PERL_UNUSED_VAR(ud_); + + if (savesp) + PL_stack_sp = savesp; if (cxstack_ix > cxix) dounwind(cxix); @@ -539,18 +589,13 @@ STATIC void su_unwind(pTHX_ void *ud_) { PL_stack_sp--; mark = PL_markstack[cxstack[cxix].blk_oldmarksp]; - - if (gimme == G_SCALAR) { - *PL_markstack_ptr = PL_stack_sp - PL_stack_base; - PL_stack_sp += items; - } else { - *PL_markstack_ptr = PL_stack_sp - PL_stack_base - items; - } + *PL_markstack_ptr = PL_stack_sp - PL_stack_base - items; SU_D({ + I32 gimme = GIMME_V; PerlIO_printf(Perl_debug_log, "%p: cx=%d gimme=%s items=%d sp=%d oldmark=%d mark=%d\n", - ud, cxix, + &MY_CXT, cxix, gimme == G_VOID ? "void" : gimme == G_ARRAY ? "list" : "scalar", items, PL_stack_sp - PL_stack_base, *PL_markstack_ptr, mark); }); @@ -558,51 +603,67 @@ STATIC void su_unwind(pTHX_ void *ud_) { PL_op = PL_ppaddr[OP_RETURN](aTHX); *PL_markstack_ptr = mark; - fakeop.op_next = PL_op; - PL_op = &fakeop; - - Safefree(ud); + MY_CXT.fakeop.op_next = PL_op; + PL_op = &(MY_CXT.fakeop); } /* --- XS ------------------------------------------------------------------ */ -#define SU_GET_LEVEL(A) \ - STMT_START { \ - if (items > A) { \ - SV *lsv = ST(A); \ - if (SvOK(lsv)) \ - level = SvIV(lsv); \ - if (level < 0) \ - XSRETURN(0); \ - } \ - if (level > cxstack_ix) \ - level = cxstack_ix; \ +#if SU_HAS_PERL(5, 8, 9) +# define SU_SKIP_DB_MAX 2 +#else +# define SU_SKIP_DB_MAX 3 +#endif + +/* Skip context sequences of 1 to SU_SKIP_DB_MAX (included) block contexts + * followed by a DB sub */ + +#define SU_SKIP_DB(C) \ + STMT_START { \ + I32 i = 1; \ + PERL_CONTEXT *cx = cxstack + (C); \ + do { \ + if (CxTYPE(cx) == CXt_BLOCK && (C) >= i) { \ + --cx; \ + if (CxTYPE(cx) == CXt_SUB && cx->blk_sub.cv == GvCV(PL_DBsub)) { \ + (C) -= i + 1; \ + break; \ + } \ + } else \ + break; \ + } while (++i <= SU_SKIP_DB_MAX); \ } STMT_END -#define SU_GET_CONTEXT(A, B) \ - STMT_START { \ - if (items > A) { \ - SV *lsv = ST(B); \ - if (SvOK(lsv)) \ - level = SvIV(lsv); \ - if (level < 0) \ - level = 0; \ - else if (level > cxix) \ - level = cxix; \ - } \ +#define SU_GET_CONTEXT(A, B) \ + STMT_START { \ + if (items > A) { \ + SV *csv = ST(B); \ + if (!SvOK(csv)) \ + goto default_cx; \ + cxix = SvIV(csv); \ + if (cxix < 0) \ + cxix = 0; \ + else if (cxix > cxstack_ix) \ + cxix = cxstack_ix; \ + } else { \ +default_cx: \ + cxix = cxstack_ix; \ + if (PL_DBsub) \ + SU_SKIP_DB(cxix); \ + } \ } STMT_END -#define SU_DOPOPTOCX(t) \ - STMT_START { \ - I32 i, cxix = cxstack_ix, level = 0; \ - SU_GET_CONTEXT(0, 0); \ - for (i = cxix - level; i >= 0; --i) { \ - if (CxTYPE(&cxstack[i]) == t) { \ - ST(0) = sv_2mortal(newSViv(cxix - i)); \ - XSRETURN(1); \ - } \ - } \ - XSRETURN_UNDEF; \ +#define SU_GET_LEVEL(A, B) \ + STMT_START { \ + level = 0; \ + if (items > 0) { \ + SV *lsv = ST(B); \ + if (SvOK(lsv)) { \ + level = SvIV(lsv); \ + if (level < 0) \ + level = 0; \ + } \ + } \ } STMT_END XS(XS_Scope__Upper_unwind); /* prototype to pass -Wmissing-prototypes */ @@ -613,27 +674,33 @@ XS(XS_Scope__Upper_unwind) { #else dXSARGS; #endif - I32 cxix = cxstack_ix, level = 0; - su_ud_unwind *ud; + dMY_CXT; + I32 cxix; PERL_UNUSED_VAR(cv); /* -W */ PERL_UNUSED_VAR(ax); /* -Wall */ SU_GET_CONTEXT(0, items - 1); - cxix -= level; do { PERL_CONTEXT *cx = cxstack + cxix; switch (CxTYPE(cx)) { case CXt_SUB: + if (PL_DBsub && cx->blk_sub.cv == GvCV(PL_DBsub)) + continue; case CXt_EVAL: case CXt_FORMAT: - /* pp_entersub will try to sanitize the stack - screw that, we're insane */ - if (GIMME_V == G_SCALAR) - PL_stack_sp = PL_stack_base + TOPMARK + 1; - Newx(ud, 1, su_ud_unwind); - ud->cxix = cxix; - ud->items = items; - SAVEDESTRUCTOR_X(su_unwind, ud); + MY_CXT.cxix = cxix; + MY_CXT.items = items; + /* pp_entersub will want to sanitize the stack after returning from there + * Screw that, we're insane */ + if (GIMME_V == G_SCALAR) { + MY_CXT.savesp = PL_stack_sp; + /* dXSARGS calls POPMARK, so we need to match PL_markstack_ptr[1] */ + PL_stack_sp = PL_stack_base + PL_markstack_ptr[1] + 1; + } else { + MY_CXT.savesp = NULL; + } + SAVEDESTRUCTOR_X(su_unwind, NULL); return; default: break; @@ -648,97 +715,148 @@ PROTOTYPES: ENABLE BOOT: { - HV *stash = gv_stashpv(__PACKAGE__, 1); - newCONSTSUB(stash, "HERE", newSViv(0)); + HV *stash; + MY_CXT_INIT; + stash = gv_stashpv(__PACKAGE__, 1); + newCONSTSUB(stash, "TOP", newSViv(0)); newXSproto("Scope::Upper::unwind", XS_Scope__Upper_unwind, file, NULL); } -SV * -TOP() -PROTOTYPE: +#if SU_THREADSAFE + +void +CLONE(...) +PROTOTYPE: DISABLE CODE: - RETVAL = newSViv(cxstack_ix); -OUTPUT: - RETVAL + PERL_UNUSED_VAR(items); + { + MY_CXT_CLONE; + } + +#endif /* SU_THREADSAFE */ SV * -UP(...) -PROTOTYPE: ;$ +HERE() +PROTOTYPE: PREINIT: - I32 i = 0; I32 cxix = cxstack_ix; CODE: - if (items) - i = SvIV(ST(0)); - if (++i > cxix) - i = cxix; - RETVAL = newSViv(i); + if (PL_DBsub) + SU_SKIP_DB(cxix); + RETVAL = newSViv(cxix); OUTPUT: RETVAL SV * -DOWN(...) +UP(...) PROTOTYPE: ;$ PREINIT: - I32 i = 0; + I32 cxix; CODE: - if (items) - i = SvIV(ST(0)); - if (--i < 0) - i = 0; - RETVAL = newSViv(i); + SU_GET_CONTEXT(0, 0); + if (--cxix < 0) + cxix = 0; + if (PL_DBsub) + SU_SKIP_DB(cxix); + RETVAL = newSViv(cxix); OUTPUT: RETVAL void SUB(...) PROTOTYPE: ;$ +PREINIT: + I32 cxix; PPCODE: - SU_DOPOPTOCX(CXt_SUB); + SU_GET_CONTEXT(0, 0); + for (; cxix >= 0; --cxix) { + PERL_CONTEXT *cx = cxstack + cxix; + switch (CxTYPE(cx)) { + default: + continue; + case CXt_SUB: + if (PL_DBsub && cx->blk_sub.cv == GvCV(PL_DBsub)) + continue; + ST(0) = sv_2mortal(newSViv(cxix)); + XSRETURN(1); + } + } + XSRETURN_UNDEF; void EVAL(...) PROTOTYPE: ;$ +PREINIT: + I32 cxix; PPCODE: - SU_DOPOPTOCX(CXt_EVAL); + SU_GET_CONTEXT(0, 0); + for (; cxix >= 0; --cxix) { + PERL_CONTEXT *cx = cxstack + cxix; + switch (CxTYPE(cx)) { + default: + continue; + case CXt_EVAL: + ST(0) = sv_2mortal(newSViv(cxix)); + XSRETURN(1); + } + } + XSRETURN_UNDEF; void -CALLER(...) +SCOPE(...) PROTOTYPE: ;$ PREINIT: - I32 cxix = cxstack_ix, caller = 0, level = 0; + I32 cxix, level; PPCODE: - if (items) { - SV *csv = ST(0); - if (SvOK(csv)) - caller = SvIV(csv); - } + SU_GET_LEVEL(0, 0); cxix = cxstack_ix; - while (cxix > 0) { - PERL_CONTEXT *cx = cxstack + cxix--; + if (PL_DBsub) { + SU_SKIP_DB(cxix); + while (cxix > 0) { + if (--level < 0) + break; + --cxix; + SU_SKIP_DB(cxix); + } + } else { + cxix -= level; + if (cxix < 0) + cxix = 0; + } + ST(0) = sv_2mortal(newSViv(cxix)); + XSRETURN(1); + +void +CALLER(...) +PROTOTYPE: ;$ +PREINIT: + I32 cxix, level; +PPCODE: + SU_GET_LEVEL(0, 0); + for (cxix = cxstack_ix; cxix > 0; --cxix) { + PERL_CONTEXT *cx = cxstack + cxix; switch (CxTYPE(cx)) { case CXt_SUB: + if (PL_DBsub && cx->blk_sub.cv == GvCV(PL_DBsub)) + continue; case CXt_EVAL: case CXt_FORMAT: - --caller; - if (caller < 0) + if (--level < 0) goto done; break; } - ++level; } done: - ST(0) = sv_2mortal(newSViv(level)); + ST(0) = sv_2mortal(newSViv(cxix)); XSRETURN(1); void want_at(...) PROTOTYPE: ;$ PREINIT: - I32 cxix = cxstack_ix, level = 0; + I32 cxix; PPCODE: SU_GET_CONTEXT(0, 0); - cxix -= level; while (cxix > 0) { PERL_CONTEXT *cx = cxstack + cxix--; switch (CxTYPE(cx)) { @@ -761,24 +879,24 @@ void reap(SV *hook, ...) PROTOTYPE: &;$ PREINIT: - I32 level = 0; + I32 cxix; su_ud_reap *ud; CODE: - SU_GET_LEVEL(1); + SU_GET_CONTEXT(1, 1); Newx(ud, 1, su_ud_reap); SU_UD_ORIGIN(ud) = NULL; SU_UD_HANDLER(ud) = su_reap; ud->cb = newSVsv(hook); - su_init(level, ud, 3); + su_init(cxix, ud, 3); void localize(SV *sv, SV *val, ...) PROTOTYPE: $$;$ PREINIT: - I32 level = 0; + I32 cxix; su_ud_localize *ud; CODE: - SU_GET_LEVEL(2); + SU_GET_CONTEXT(2, 2); Newx(ud, 1, su_ud_localize); SU_UD_ORIGIN(ud) = NULL; SU_UD_HANDLER(ud) = su_localize; @@ -786,16 +904,16 @@ CODE: ud->sv = sv; ud->val = newSVsv(val); ud->elem = NULL; - su_init(level, ud, 3); + su_init(cxix, ud, 3); void localize_elem(SV *sv, SV *elem, SV *val, ...) PROTOTYPE: $$$;$ PREINIT: - I32 level = 0; + I32 cxix; su_ud_localize *ud; CODE: - SU_GET_LEVEL(3); + SU_GET_CONTEXT(3, 3); Newx(ud, 1, su_ud_localize); SU_UD_ORIGIN(ud) = NULL; SU_UD_HANDLER(ud) = su_localize; @@ -804,16 +922,16 @@ CODE: ud->val = newSVsv(val); SvREFCNT_inc(elem); ud->elem = elem; - su_init(level, ud, 4); + su_init(cxix, ud, 4); void localize_delete(SV *sv, SV *elem, ...) PROTOTYPE: $$;$ PREINIT: - I32 level = 0; + I32 cxix; su_ud_localize *ud; CODE: - SU_GET_LEVEL(2); + SU_GET_CONTEXT(2, 2); Newx(ud, 1, su_ud_localize); SU_UD_ORIGIN(ud) = NULL; SU_UD_HANDLER(ud) = su_localize; @@ -822,4 +940,4 @@ CODE: ud->val = NULL; SvREFCNT_inc(elem); ud->elem = elem; - su_init(level, ud, 4); + su_init(cxix, ud, 4);