X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Upper.xs;h=20fa5d662013c10dc685bd656fee919a9753c3b9;hb=1e8a530156ab09a816d8afc37692d1b46032eb32;hp=4ee44e55770b5ce07bd5f68c30b1760b3e29843a;hpb=a4643c73ee1832d2493c61f7b316ebe390bfce94;p=perl%2Fmodules%2FScope-Upper.git diff --git a/Upper.xs b/Upper.xs index 4ee44e5..20fa5d6 100644 --- a/Upper.xs +++ b/Upper.xs @@ -44,16 +44,12 @@ # define SvPV_nolen_const(S) SvPV_nolen(S) #endif -#ifndef HvNAME_get -# define HvNAME_get(H) HvNAME(H) -#endif - -#ifndef ENTER_with_name -# define ENTER_with_name(N) ENTER +#ifndef SvREFCNT_inc_simple_void +# define SvREFCNT_inc_simple_void(sv) SvREFCNT_inc(sv) #endif -#ifndef LEAVE_with_name -# define LEAVE_with_name(N) LEAVE +#ifndef HvNAME_get +# define HvNAME_get(H) HvNAME(H) #endif #ifndef gv_fetchpvn_flags @@ -184,7 +180,7 @@ STATIC void su_save_adelete(pTHX_ AV *av, I32 idx) { Newx(ud, 1, su_ud_adelete); ud->av = av; ud->idx = idx; - SvREFCNT_inc(av); + SvREFCNT_inc_simple_void(av); SAVEDESTRUCTOR_X(su_adelete, ud); } @@ -287,7 +283,6 @@ STATIC void su_call(pTHX_ void *ud_) { su_ud_reap *ud = (su_ud_reap *) ud_; #if SU_HAS_PERL(5, 9, 5) PERL_CONTEXT saved_cx; - I32 dieing = PL_op->op_type == OP_DIE; I32 cxix; #endif @@ -309,20 +304,17 @@ STATIC void su_call(pTHX_ void *ud_) { * the sub scope from call_sv, although it's still needed in our caller. */ #if SU_HAS_PERL(5, 9, 5) - if (dieing) { - if (cxstack_ix < cxstack_max) - cxix = cxstack_ix + 1; - else - cxix = Perl_cxinc(aTHX); - saved_cx = cxstack[cxix]; - } + if (cxstack_ix < cxstack_max) + cxix = cxstack_ix + 1; + else + cxix = Perl_cxinc(aTHX); + saved_cx = cxstack[cxix]; #endif call_sv(ud->cb, G_VOID); #if SU_HAS_PERL(5, 9, 5) - if (dieing) - cxstack[cxix] = saved_cx; + cxstack[cxix] = saved_cx; #endif PUTBACK; @@ -360,7 +352,7 @@ STATIC void su_ud_localize_init(pTHX_ su_ud_localize *ud, SV *sv, SV *val, SV *e UV deref = 0; svtype t = SVt_NULL; - SvREFCNT_inc(sv); + SvREFCNT_inc_simple_void(sv); if (SvTYPE(sv) >= SVt_PVGV) { if (!val || !SvROK(val)) { /* local *x; or local *x = $val; */ @@ -405,6 +397,7 @@ STATIC void su_ud_localize_init(pTHX_ su_ud_localize *ud, SV *sv, SV *val, SV *e case SVt_PVCV: case SVt_PVGV: deref = 0; + default: break; } /* When deref is set, val isn't NULL */ @@ -428,11 +421,11 @@ STATIC void su_localize(pTHX_ void *ud_) { gv = (GV *) sv; } else { #ifdef gv_fetchsv - gv = gv_fetchsv(sv, GV_ADDMULTI, SVt_PVGV); + gv = gv_fetchsv(sv, GV_ADDMULTI, t); #else STRLEN len; const char *name = SvPV_const(sv, len); - gv = gv_fetchpvn_flags(name, len, GV_ADDMULTI, SVt_PVGV); + gv = gv_fetchpvn_flags(name, len, GV_ADDMULTI, t); #endif } @@ -525,11 +518,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); } @@ -539,18 +551,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)); @@ -606,6 +625,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({ @@ -618,25 +646,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_) { @@ -690,18 +702,21 @@ STATIC void su_unwind(pTHX_ void *ud_) { #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); \ + I32 skipped = 0; \ + PERL_CONTEXT *base = cxstack; \ + PERL_CONTEXT *cx = base + (C); \ + while (cx >= base && (C) > skipped && CxTYPE(cx) == CXt_BLOCK) \ + --cx, ++skipped; \ + if (cx >= base && (C) > skipped) { \ + switch (CxTYPE(cx)) { \ + case CXt_SUB: \ + if (skipped <= SU_SKIP_DB_MAX && cx->blk_sub.cv == GvCV(PL_DBsub)) \ + (C) -= skipped + 1; \ + break; \ + default: \ + break; \ + } \ + } \ } STMT_END #define SU_GET_CONTEXT(A, B) \ @@ -786,10 +801,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); }