X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Upper.xs;h=89083850cd9209579c880f9bade1d22e89bfbb74;hb=f43a242b7a060b39234a12159de86b2bf56ff37a;hp=612ce2efb5bb4e46a6e700198861527eefcd1812;hpb=fd04ca94303855f0a62f74f7b8ed06452697f7a1;p=perl%2Fmodules%2FScope-Upper.git diff --git a/Upper.xs b/Upper.xs index 612ce2e..8908385 100644 --- a/Upper.xs +++ b/Upper.xs @@ -48,14 +48,6 @@ # define HvNAME_get(H) HvNAME(H) #endif -#ifndef ENTER_with_name -# define ENTER_with_name(N) ENTER -#endif - -#ifndef LEAVE_with_name -# define LEAVE_with_name(N) LEAVE -#endif - #ifndef gv_fetchpvn_flags # define gv_fetchpvn_flags(A, B, C, D) gv_fetchpv((A), (C), (D)) #endif @@ -296,7 +288,7 @@ STATIC void su_call(pTHX_ void *ud_) { SU_D({ PerlIO_printf(Perl_debug_log, "%p: @@@ call\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n", - ud, ud, PL_scopestack_ix, PL_savestack_ix); + ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix); }); ENTER; @@ -349,23 +341,20 @@ STATIC void su_reap(pTHX_ void *ud) { typedef struct { su_ud_common ci; - SV *sv; - SV *val; - SV *elem; + SV *sv; + SV *val; + SV *elem; + svtype type; } su_ud_localize; -STATIC void su_localize(pTHX_ void *ud_) { -#define su_localize(U) su_localize(aTHX_ (U)) - su_ud_localize *ud = (su_ud_localize *) ud_; - SV *sv = ud->sv; - SV *val = ud->val; - SV *elem = ud->elem; - GV *gv; +STATIC void su_ud_localize_init(pTHX_ su_ud_localize *ud, SV *sv, SV *val, SV *elem) { +#define su_ud_localize_init(UD, S, V, E) su_ud_localize_init(aTHX_ (UD), (S), (V), (E)) UV deref = 0; svtype t = SVt_NULL; + SvREFCNT_inc(sv); + if (SvTYPE(sv) >= SVt_PVGV) { - gv = (GV *) sv; if (!val || !SvROK(val)) { /* local *x; or local *x = $val; */ t = SVt_PVGV; } else { /* local *x = \$val; */ @@ -398,7 +387,45 @@ STATIC void su_localize(pTHX_ void *ud_) { t = SvTYPE(val); } } - gv = gv_fetchpvn_flags(s, l, GV_ADDMULTI, SVt_PVGV); + SvREFCNT_dec(sv); + sv = newSVpvn(s, l); + } + + switch (t) { + case SVt_PVAV: + case SVt_PVHV: + case SVt_PVCV: + case SVt_PVGV: + deref = 0; + break; + } + /* When deref is set, val isn't NULL */ + + ud->sv = sv; + ud->val = val ? newSVsv(deref ? SvRV(val) : val) : NULL; + ud->elem = SvREFCNT_inc(elem); + ud->type = t; +} + +STATIC void su_localize(pTHX_ void *ud_) { +#define su_localize(U) su_localize(aTHX_ (U)) + su_ud_localize *ud = (su_ud_localize *) ud_; + SV *sv = ud->sv; + SV *val = ud->val; + SV *elem = ud->elem; + svtype t = ud->type; + GV *gv; + + if (SvTYPE(sv) >= SVt_PVGV) { + gv = (GV *) sv; + } else { +#ifdef gv_fetchsv + gv = gv_fetchsv(sv, GV_ADDMULTI, SVt_PVGV); +#else + STRLEN len; + const char *name = SvPV_const(sv, len); + gv = gv_fetchpvn_flags(name, len, GV_ADDMULTI, SVt_PVGV); +#endif } SU_D({ @@ -436,8 +463,6 @@ STATIC void su_localize(pTHX_ void *ud_) { break; default: gv = (GV *) save_scalar(gv); - if (deref) /* val != NULL */ - val = SvRV(val); break; } @@ -466,12 +491,13 @@ STATIC void su_pop(pTHX_ void *ud) { I32 depth, base, mark, *origin; depth = SU_UD_DEPTH(ud); - SU_D({ - PerlIO_printf(Perl_debug_log, "%p: --- pop a %s\n", ud, SU_CXNAME); + SU_D( PerlIO_printf(Perl_debug_log, - "%p: leave scope at depth=%2d scope_ix=%2d cur_top=%2d cur_base=%2d\n", ud, - depth, PL_scopestack_ix, PL_savestack_ix, PL_scopestack[PL_scopestack_ix]); - }); + "%p: --- pop a %s\n" + "%p: leave scope at depth=%2d scope_ix=%2d cur_top=%2d cur_base=%2d\n", + ud, SU_CXNAME, + ud, depth, PL_scopestack_ix,PL_savestack_ix,PL_scopestack[PL_scopestack_ix]) + ); origin = SU_UD_ORIGIN(ud); mark = origin[depth]; @@ -479,7 +505,7 @@ STATIC void su_pop(pTHX_ void *ud) { SU_D(PerlIO_printf(Perl_debug_log, "%p: original scope was %*c top=%2d base=%2d\n", - ud, 20, ' ', mark, base)); + ud, 24, ' ', mark, base)); if (base < mark) { SU_D(PerlIO_printf(Perl_debug_log, "%p: clear leftovers\n", ud)); @@ -491,11 +517,30 @@ STATIC void su_pop(pTHX_ void *ud) { SU_UD_DEPTH(ud) = --depth; if (depth > 0) { - SU_D(PerlIO_printf(Perl_debug_log, - "%p: set new destructor at depth=%2d scope_ix=%2d save_ix=%2d\n", - ud, depth, PL_scopestack_ix, PL_savestack_ix)); + I32 i = 1; SAVEDESTRUCTOR_X(su_pop, ud); + + /* Skip depths corresponding to scopes for which leave_scope() might not be + * called. */ + while (depth > 1 && PL_scopestack_ix >= i) { + I32 j = PL_scopestack[PL_scopestack_ix - i]; + + if (j < PL_savestack_ix) + break; + + SU_D(PerlIO_printf(Perl_debug_log, + "%p: skip scope%*cat depth=%2d scope_ix=%2d new_top=%2d >= cur_base=%2d\n", + ud, 6, ' ', depth, PL_scopestack_ix - i, j, PL_savestack_ix)); + + SU_UD_DEPTH(ud) = --depth; + + ++i; + } + + SU_D(PerlIO_printf(Perl_debug_log, + "%p: set destructor at depth=%2d scope_ix=%2d save_ix=%2d\n", + ud, depth, PL_scopestack_ix, PL_savestack_ix)); } else { SU_UD_HANDLER(ud)(aTHX_ ud); } @@ -505,18 +550,25 @@ STATIC void su_pop(pTHX_ void *ud) { ud, PL_savestack_ix, PL_scopestack[PL_scopestack_ix])); } +/* --- Global data --------------------------------------------------------- */ + +#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION + +typedef struct { + int stack_placeholder; + I32 cxix; + I32 items; + SV **savesp; + OP fakeop; +} my_cxt_t; + +START_MY_CXT + /* --- Initialize the stack and the action userdata ------------------------ */ 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; - - LEAVE_with_name("sub"); - - if (cxix >= cxstack_ix) { - SU_UD_HANDLER(ud)(aTHX_ ud); - goto done; - } + I32 i, depth = 1, *origin; SU_D(PerlIO_printf(Perl_debug_log, "%p: ### init for cx %d\n", ud, cxix)); @@ -572,6 +624,15 @@ STATIC I32 su_init(pTHX_ I32 cxix, void *ud, I32 size) { "%p: set original destructor at depth=%2d scope_ix=%2d save_ix=%2d\n", ud, depth, PL_scopestack_ix - 1, PL_savestack_ix)); + /* Make sure the first destructor fires by pushing enough fake slots on the + * stack. */ + if (PL_savestack_ix + 3 <= PL_scopestack[PL_scopestack_ix - 1]) { + dMY_CXT; + do { + save_int(&MY_CXT.stack_placeholder); + } while (PL_savestack_ix + 3 <= PL_scopestack[PL_scopestack_ix - 1]); + } + SAVEDESTRUCTOR_X(su_pop, ud); SU_D({ @@ -584,25 +645,9 @@ STATIC I32 su_init(pTHX_ I32 cxix, void *ud, I32 size) { } }); -done: - ENTER_with_name("sub"); - return depth; } -/* --- Global data --------------------------------------------------------- */ - -#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION - -typedef struct { - I32 cxix; - I32 items; - SV **savesp; - OP fakeop; -} my_cxt_t; - -START_MY_CXT - /* --- Unwind stack -------------------------------------------------------- */ STATIC void su_unwind(pTHX_ void *ud_) { @@ -752,10 +797,14 @@ PROTOTYPES: ENABLE BOOT: { HV *stash; + MY_CXT_INIT; + MY_CXT.stack_placeholder = 0; + stash = gv_stashpv(__PACKAGE__, 1); newCONSTSUB(stash, "TOP", newSViv(0)); newCONSTSUB(stash, "SU_THREADSAFE", newSVuv(SU_THREADSAFE)); + newXSproto("Scope::Upper::unwind", XS_Scope__Upper_unwind, file, NULL); } @@ -931,17 +980,19 @@ localize(SV *sv, SV *val, ...) PROTOTYPE: $$;$ PREINIT: I32 cxix; + I32 size = 3; su_ud_localize *ud; CODE: SU_GET_CONTEXT(2, 2); Newx(ud, 1, su_ud_localize); SU_UD_ORIGIN(ud) = NULL; SU_UD_HANDLER(ud) = su_localize; - SvREFCNT_inc(sv); - ud->sv = sv; - ud->val = newSVsv(val); - ud->elem = NULL; - su_init(cxix, ud, 3); + su_ud_localize_init(ud, sv, val, NULL); +#if !SU_HAS_PERL(5, 8, 9) + if (ud->type >= SVt_PVGV) + size = 6; +#endif + su_init(cxix, ud, size); void localize_elem(SV *sv, SV *elem, SV *val, ...) @@ -954,11 +1005,7 @@ CODE: Newx(ud, 1, su_ud_localize); SU_UD_ORIGIN(ud) = NULL; SU_UD_HANDLER(ud) = su_localize; - SvREFCNT_inc(sv); - ud->sv = sv; - ud->val = newSVsv(val); - SvREFCNT_inc(elem); - ud->elem = elem; + su_ud_localize_init(ud, sv, val, elem); su_init(cxix, ud, 4); void @@ -966,15 +1013,16 @@ localize_delete(SV *sv, SV *elem, ...) PROTOTYPE: $$;$ PREINIT: I32 cxix; + I32 size = 4; su_ud_localize *ud; CODE: SU_GET_CONTEXT(2, 2); Newx(ud, 1, su_ud_localize); SU_UD_ORIGIN(ud) = NULL; SU_UD_HANDLER(ud) = su_localize; - SvREFCNT_inc(sv); - ud->sv = sv; - ud->val = NULL; - SvREFCNT_inc(elem); - ud->elem = elem; - su_init(cxix, ud, 4); + su_ud_localize_init(ud, sv, NULL, elem); +#if !SU_HAS_PERL(5, 8, 9) + if (ud->type >= SVt_PVGV) + size = 6; +#endif + su_init(cxix, ud, size);