X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Upper.xs;h=114161a4879cd4ddfe7f13162360f09ecd0ce89e;hb=70148496e0d2fce5974ae1a869f06b22bd7c119d;hp=f7698d8a3dbb282826e02aa98f528bfe8b225ba0;hpb=5736d907ca8e5e47a4c2c70564014c8b4ec4f1aa;p=perl%2Fmodules%2FScope-Upper.git diff --git a/Upper.xs b/Upper.xs index f7698d8..114161a 100644 --- a/Upper.xs +++ b/Upper.xs @@ -17,10 +17,7 @@ /* --- Compatibility ------------------------------------------------------- */ /* perl 5.23.8 onwards has a revamped context system */ -#if XSH_HAS_PERL(5, 23, 8) -# define SU_HAS_NEW_CXT -#endif - +#define SU_HAS_NEW_CXT XSH_HAS_PERL(5, 23, 8) #ifndef dVAR # define dVAR dNOOP @@ -203,27 +200,6 @@ static U8 su_op_gimme_reverse(U8 gimme) { # define NEGATIVE_INDICES_VAR "NEGATIVE_INDICES" #endif -/* CX_ARGARRAY(cx): the AV at pad[0] of the CV associated with CXt_SUB - * context cx */ - -#if XSH_HAS_PERL(5, 23, 8) -# define CX_ARGARRAY(cx) \ - ((AV*)(AvARRAY(MUTABLE_AV( \ - PadlistARRAY(CvPADLIST(cx->blk_sub.cv))[ \ - CvDEPTH(cx->blk_sub.cv)]))[0])) -/* XXX is the new def ok to use in lvalue cxt? Formerly it assigned to - * blk_sub.argarray, now to pad[0]. Does this matter? - */ -# define CX_ARGARRAY_set(cx,ary) \ - (AvARRAY(MUTABLE_AV( \ - PadlistARRAY(CvPADLIST(cx->blk_sub.cv))[ \ - CvDEPTH(cx->blk_sub.cv)]))[0] = (SV*)(ary)) -#else -# define CX_ARGARRAY(cx) (cx->blk_sub.argarray) -# define CX_ARGARRAY_set(cx,ary) (cx->blk_sub.argarray = (ary)) -#endif - - /* --- Error messages ------------------------------------------------------ */ static const char su_stack_smash[] = "Cannot target a scope outside of the current stack"; @@ -374,27 +350,39 @@ typedef struct { I32 cxix; - I32 target_depth; - CV *target; - CV *callback; CV *renamed; +#if SU_HAS_NEW_CXT + U8 *cxtypes; /* array of saved context types */ + I32 gap; /* how many contexts have temporarily CXt_NULLed out*/ + AV* argarray; /* the PL_curpad[0] of the uplevel sub */ +#else + I32 target_depth; + CV *target; PERL_SI *si; PERL_SI *old_curstackinfo; AV *old_mainstack; + OP *old_op; + bool old_catch; + bool died; +#endif COP *old_curcop; - OP *old_op; #if SU_UPLEVEL_HIJACKS_RUNOPS runops_proc_t old_runops; #endif - bool old_catch; - - bool died; } su_uplevel_ud; +#if SU_HAS_NEW_CXT +/* used to flag a context stack entry whose type has been temporarily + * set to CXt_NULL. It relies on perl not using this value for real + * CXt_NULL entries. + */ +# define CXp_SU_UPLEVEL_NULLED 0x20 +#endif + static su_uplevel_ud *su_uplevel_ud_new(pTHX) { #define su_uplevel_ud_new() su_uplevel_ud_new(aTHX) su_uplevel_ud *sud; @@ -407,6 +395,7 @@ static su_uplevel_ud *su_uplevel_ud_new(pTHX) { sud->tmp_uid_storage.used = 0; sud->tmp_uid_storage.alloc = 0; +#if !SU_HAS_NEW_CXT Newx(si, 1, PERL_SI); si->si_stack = newAV(); AvREAL_off(si->si_stack); @@ -414,17 +403,21 @@ static su_uplevel_ud *su_uplevel_ud_new(pTHX) { si->si_cxmax = -1; sud->si = si; +#endif return sud; } static void su_uplevel_ud_delete(pTHX_ su_uplevel_ud *sud) { #define su_uplevel_ud_delete(S) su_uplevel_ud_delete(aTHX_ (S)) + +#if !SU_HAS_NEW_CXT PERL_SI *si = sud->si; Safefree(si->si_cxstack); SvREFCNT_dec(si->si_stack); Safefree(si); +#endif Safefree(sud->tmp_uid_storage.map); @@ -462,7 +455,6 @@ static void xsh_user_clone(pTHX_ const xsh_user_cxt_t *old_cxt, xsh_user_cxt_t * new_cxt->uplevel_storage.top = NULL; new_cxt->uplevel_storage.root = NULL; new_cxt->uplevel_storage.count = 0; - new_cxt->uid_storage.map = NULL; new_cxt->uid_storage.used = 0; new_cxt->uid_storage.alloc = 0; @@ -537,7 +529,6 @@ static void xsh_user_clone(pTHX_ const xsh_user_cxt_t *old_cxt, xsh_user_cxt_t * # define SU_SAVE_HELEM_OR_HDELETE_SIZE SU_SAVE_HELEM_SIZE #endif - #ifndef SvCANEXISTDELETE # define SvCANEXISTDELETE(sv) \ (!SvRMAGICAL(sv) \ @@ -718,19 +709,18 @@ static void su_save_gvcv(pTHX_ GV *gv) { /* --- Actions ------------------------------------------------------------- */ typedef struct { - I32 orig_ix; /* original savestack_ix */ - I32 offset; /* how much we bumped this savestack index */ + I32 orig_ix; /* original savestack_ix */ + I32 offset; /* how much we bumped this savestack index */ } su_ud_origin_elem; typedef struct { - U8 type; - U8 private; + U8 type; + U8 private; /* spare */ - I32 depth; + I32 depth; su_ud_origin_elem *origin; } su_ud_common; - #define SU_UD_TYPE(U) (((su_ud_common *) (U))->type) #define SU_UD_PRIVATE(U) (((su_ud_common *) (U))->private) #define SU_UD_DEPTH(U) (((su_ud_common *) (U))->depth) @@ -910,24 +900,26 @@ static void su_localize(pTHX_ void *ud_) { if (SvTYPE(sv) >= SVt_PVGV) { gv = (GV *) sv; } else { - /* new perl context implementation frees savestack *before* restoring * PL_curcop. Temporarily restore it prematurely to make gv_fetch* * looks up unqualified var names in the caller's package */ -#ifdef SU_HAS_NEW_CXT +#if SU_HAS_NEW_CXT COP *old_cop = PL_curcop; - PL_curcop = CX_CUR()->blk_oldcop; + PL_curcop = CX_CUR()->blk_oldcop; #endif #ifdef gv_fetchsv 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, t); + { + STRLEN len; + const char *name = SvPV_const(sv, len); + gv = gv_fetchpvn_flags(name, len, GV_ADDMULTI, t); + } #endif -#ifdef SU_HAS_NEW_CXT - CX_CUR()->blk_oldcop = PL_curcop; + +#if SU_HAS_NEW_CXT + CX_CUR()->blk_oldcop = old_cop; #endif } @@ -997,7 +989,7 @@ static void su_uid_drop(pTHX_ void *ud_) { /* --- Pop a context back -------------------------------------------------- */ #ifdef DEBUGGING -# define SU_CXNAME(C) PL_block_type[CxTYPE(C)] +# define SU_CX_TYPENAME(T) PL_block_type[(T)] #else # if XSH_HAS_PERL(5, 23, 8) static const char *su_block_type[] = { @@ -1053,9 +1045,13 @@ static const char *su_block_type[] = { "FORMAT" }; # endif -# define SU_CXNAME(C) su_block_type[CxTYPE(C)] +# define SU_CX_TYPENAME(T) su_block_type[(T)] #endif +#define SU_CXNAME(C) SU_CX_TYPENAME(CxTYPE(C)) + +#if XSH_DEBUG + /* for debugging. These indicate how many ENTERs each context type * does before the PUSHBLOCK */ @@ -1075,7 +1071,7 @@ static const int su_cxt_enter_count[] = { # endif }; - +#endif /* XSH_DEBUG */ /* push at least 'size' slots worth of padding onto the savestack */ @@ -1090,17 +1086,13 @@ static void su_ss_push_padding(pTHX_ void *ud, I32 size) { save_alloc((size - SU_SAVE_ALLOC_SIZE)*sizeof(*PL_savestack), 0); } - static void su_pop(pTHX_ void *ud); - - /* push an su_pop destructor onto the savestack with suitable padding. * first indicates that this is the first push of a destructor */ static void su_ss_push_destructor(pTHX_ void *ud, I32 depth, bool first) { su_ud_origin_elem *origin = SU_UD_ORIGIN(ud); - I32 pad; assert(first || origin[depth+1].orig_ix == PL_savestack_ix); su_ss_push_padding(aTHX_ ud, @@ -1113,7 +1105,6 @@ static void su_ss_push_destructor(pTHX_ void *ud, I32 depth, bool first) { PL_savestack_ix <= origin[depth+1].orig_ix + origin[depth+1].offset); } - /* this is called during each leave_scope() via SAVEDESTRUCTOR_X */ static void su_pop(pTHX_ void *ud) { @@ -1174,12 +1165,11 @@ static void su_pop(pTHX_ void *ud) { XSH_D(su_debug_log("%p: end pop: ss_ix=%d\n", ud, PL_savestack_ix)); } - /* --- Initialize the stack and the action userdata ------------------------ */ static void su_init(pTHX_ void *ud, I32 cxix, I32 size) { #define su_init(U, C, S) su_init(aTHX_ (U), (C), (S)) - I32 i, depth, base; + I32 i, depth; su_ud_origin_elem *origin; I32 cur_cx_ix; I32 cur_scope_ix; @@ -1187,7 +1177,7 @@ static void su_init(pTHX_ void *ud, I32 cxix, I32 size) { XSH_D(su_debug_log("%p: ### su_init(cxix=%d, size=%d)\n", ud, cxix, size)); depth = PL_scopestack_ix - cxstack[cxix].blk_oldscopesp; -#ifdef SU_HAS_NEW_CXT +#if SU_HAS_NEW_CXT depth += (cxstack_ix - cxix); /* each context frame holds 1 scope */ #endif XSH_D(su_debug_log( @@ -1232,14 +1222,14 @@ static void su_init(pTHX_ void *ud, I32 cxix, I32 size) { * * The passed cxix argument represents the scope we wish to inject into; * we have to adjust all the savestack frame boundaries above (but not - * including) that context. + * including) that context. */ Newx(origin, depth, su_ud_origin_elem); cur_cx_ix = cxix; cur_scope_ix = cxstack[cxix].blk_oldscopesp; -#ifdef SU_HAS_NEW_CXT +#if SU_HAS_NEW_CXT XSH_D(su_debug_log("%p: cx=%-2d %-11s\n", ud, cur_cx_ix, SU_CXNAME(cxstack+cur_cx_ix))); cur_cx_ix++; @@ -1249,7 +1239,7 @@ static void su_init(pTHX_ void *ud, I32 cxix, I32 size) { I32 *ixp; I32 offset; -#ifdef SU_HAS_NEW_CXT +#if SU_HAS_NEW_CXT if ( cur_cx_ix <= cxstack_ix && cur_scope_ix == cxstack[cur_cx_ix].blk_oldscopesp @@ -1307,7 +1297,7 @@ static void su_init(pTHX_ void *ud, I32 cxix, I32 size) { origin[i].orig_ix = *ixp; *ixp += offset; -#ifdef SU_HAS_NEW_CXT +#if SU_HAS_NEW_CXT XSH_D({ if (ixp == &PL_scopestack[cur_scope_ix-1]) su_debug_log( @@ -1335,7 +1325,6 @@ static void su_init(pTHX_ void *ud, I32 cxix, I32 size) { su_ss_push_destructor(aTHX_ ud, depth-1, 1); } - /* --- Unwind stack -------------------------------------------------------- */ static void su_unwind(pTHX_ void *ud_) { @@ -1655,7 +1644,7 @@ static int su_uplevel_goto_static(const OP *o) { return 0; } -#if SU_UPLEVEL_HIJACKS_RUNOPS +#if !SU_HAS_NEW_CXT && SU_UPLEVEL_HIJACKS_RUNOPS static int su_uplevel_goto_runops(pTHX) { #define su_uplevel_goto_runops() su_uplevel_goto_runops(aTHX) @@ -1674,7 +1663,7 @@ static int su_uplevel_goto_runops(pTHX) { switch (CxTYPE(cx)) { case CXt_SUB: if (CxHASARGS(cx)) { - argarray = CX_ARGARRAY(cx); + argarray = cx->blk_sub.argarray; goto done; } break; @@ -1717,7 +1706,53 @@ done: #define su_at_underscore(C) PadARRAY(PadlistARRAY(CvPADLIST(C))[CvDEPTH(C)])[0] -static void su_uplevel_restore(pTHX_ void *sus_) { +#if SU_HAS_NEW_CXT + +static void su_uplevel_restore_new(pTHX_ void *sus_) { + su_uplevel_ud *sud = sus_; + PERL_CONTEXT *cx; + I32 i; + U8 *saved_cxtypes = sud->cxtypes; + + for (i = 0; i < sud->gap; i++) { + PERL_CONTEXT *cx = cxstack + sud->cxix + i; + XSH_D(su_debug_log("su_uplevel_restore: i=%d cxix=%d type %s => %s\n", + i, cx-cxstack, SU_CX_TYPENAME(CxTYPE(cx)), + SU_CX_TYPENAME(saved_cxtypes[i] & CXTYPEMASK))); + cx->cx_type = saved_cxtypes[i]; + } + Safefree(saved_cxtypes); + + /* renamed is a copy of callback, but they share the same CvPADLIST. + * At this point any calls to renamed should have exited so that its + * depth is back to that of of callback. At this point its safe to free + * renamed, then undo the extra ref count that was ensuring that callback + * remains alive + */ + assert(sud->renamed); + assert(sud->callback); + + CvDEPTH(sud->callback)--; + assert(CvDEPTH(sud->callback) == CvDEPTH(sud->renamed)); + if (!CvISXSUB(sud->renamed)) { + CvDEPTH(sud->renamed) = 0; + CvPADLIST(sud->renamed) = NULL; + } + SvREFCNT_dec(sud->renamed); + SvREFCNT_dec(sud->callback); + + SU_UPLEVEL_RESTORE(curcop); + + su_uplevel_storage_delete(sud); + + return; +} + +#else + +/* 5.23.7 and earlier */ + +static void su_uplevel_restore_old(pTHX_ void *sus_) { su_uplevel_ud *sud = sus_; PERL_SI *cur = sud->old_curstackinfo; PERL_SI *si = sud->si; @@ -1749,8 +1784,8 @@ static void su_uplevel_restore(pTHX_ void *sus_) { * reached without a goto() happening, and the old argarray member is * actually our fake argarray. Destroy it properly in that case. */ if (cx->blk_sub.cv == sud->renamed) { - SvREFCNT_dec(CX_ARGARRAY(cx)); - CX_ARGARRAY_set(cx, argarray); + SvREFCNT_dec(cx->blk_sub.argarray); + cx->blk_sub.argarray = argarray; } CvDEPTH(sud->callback)--; @@ -1879,6 +1914,8 @@ found_it: return; } +#endif + static CV *su_cv_clone(pTHX_ CV *proto, GV *gv) { #define su_cv_clone(P, G) su_cv_clone(aTHX_ (P), (G)) dVAR; @@ -1940,8 +1977,118 @@ static CV *su_cv_clone(pTHX_ CV *proto, GV *gv) { return cv; } -static I32 su_uplevel(pTHX_ CV *callback, I32 cxix, I32 args) { -#define su_uplevel(C, I, A) su_uplevel(aTHX_ (C), (I), (A)) +#if SU_HAS_NEW_CXT + +/* this one-shot runops "loop" is designed to be called just before + * execution of the first op following an uplevel()'s entersub. It gets a + * chance to fix up the args as seen by caller(), before immediately + * falling through to the previous runops loop. Note that pp_entersub is + * called directly by call_sv() rather than being called from a runops + * loop. + */ + +static int su_uplevel_runops_hook_entersub(pTHX) { + OP *op = PL_op; + dXSH_CXT; + su_uplevel_ud *sud = XSH_CXT.uplevel_storage.top; + + /* Create a new array containing a copy of the original sub's call args, + * then stick it in PL_curpad[0] of the current running sub so that + * thay will be seen by caller(). + */ + assert(sud); + if (sud->argarray) { + AV *av = newAV(); + AvREAL_off(av); + AvREIFY_on(av); + av_extend(av, AvMAX(sud->argarray)); + AvFILLp(av) = AvFILLp(sud->argarray); + Copy(AvARRAY(sud->argarray), AvARRAY(av), AvFILLp(av) + 1, SV *); + + /* should be referenced by PL_curpad[0] and *_ */ + assert(SvREFCNT(PL_curpad[0]) > 1); + SvREFCNT_dec(PL_curpad[0]); + + PL_curpad[0] = (SV*)av; + } + + /* undo the temporary runops hook and fall through to a real runops loop. */ + assert(sud->old_runops != su_uplevel_runops_hook_entersub); + PL_runops = sud->old_runops; + CALLRUNOPS(aTHX); + return 0; +} + +static I32 su_uplevel_new(pTHX_ CV *callback, I32 cxix, I32 args) { + su_uplevel_ud *sud; + U8 *saved_cxtypes; + I32 i, ret; + I32 gimme; + CV *base_cv = cxstack[cxix].blk_sub.cv; + dSP; + + assert(CxTYPE(&cxstack[cxix]) == CXt_SUB); + + ENTER; + + gimme = GIMME_V; + + /* At this point SP points to the top arg. + * Shuffle the args down by one, eliminating the CV slot */ + Move(SP - args + 1, SP - args, args, SV*); + SP--; + PUSHMARK(SP - args); + PUTBACK; + + sud = su_uplevel_storage_new(cxix); + + sud->cxix = cxix; + sud->callback = (CV*)SvREFCNT_inc_simple(callback); + sud->renamed = NULL; + sud->gap = cxstack_ix - cxix + 1; + sud->argarray = NULL; + + Newx(saved_cxtypes, sud->gap, U8); + sud->cxtypes = saved_cxtypes; + + SAVEDESTRUCTOR_X(su_uplevel_restore_new, sud); + SU_UPLEVEL_SAVE(curcop, cxstack[cxix].blk_oldcop); + +/* temporarily change the type of any contexts to NULL, so they're + * invisible to caller() etc. */ + for (i = 0; i < sud->gap; i++) { + PERL_CONTEXT *cx = cxstack + cxix + i; + saved_cxtypes[i] = cx->cx_type; /* save type and flags */ + XSH_D(su_debug_log("su_uplevel: i=%d cxix=%d type %-11s => %s\n", + i, cx-cxstack, SU_CX_TYPENAME(CxTYPE(cx)), SU_CX_TYPENAME(CXt_NULL))); + cx->cx_type = (CXt_NULL | CXp_SU_UPLEVEL_NULLED); + } + + /* create a copy of the callback with a doctored name (as seen by + * caller). It shares the padlist with callback */ + sud->renamed = su_cv_clone(callback, CvGV(base_cv)); + sud->old_runops = PL_runops; + + if (!CvISXSUB(sud->renamed) && CxHASARGS(&cxstack[cxix])) { + sud->argarray = (AV*)su_at_underscore(base_cv); + assert(PL_runops != su_uplevel_runops_hook_entersub); + /* set up a one-shot runops hook so that we can fake up the + * args as seen by caller() on return from pp_entersub */ + PL_runops = su_uplevel_runops_hook_entersub; + } + + CvDEPTH(callback)++; /* match what CvDEPTH(sud->renamed) is about to become */ + + ret = call_sv((SV*)sud->renamed, gimme); + + LEAVE; + + return ret; +} + +#else + +static I32 su_uplevel_old(pTHX_ CV *callback, I32 cxix, I32 args) { su_uplevel_ud *sud; const PERL_CONTEXT *cx = cxstack + cxix; PERL_SI *si; @@ -1969,7 +2116,7 @@ static I32 su_uplevel(pTHX_ CV *callback, I32 cxix, I32 args) { sud->died = 1; sud->callback = NULL; sud->renamed = NULL; - SAVEDESTRUCTOR_X(su_uplevel_restore, sud); + SAVEDESTRUCTOR_X(su_uplevel_restore_old, sud); si = sud->si; @@ -2054,7 +2201,7 @@ static I32 su_uplevel(pTHX_ CV *callback, I32 cxix, I32 args) { if ((PL_op = PL_ppaddr[OP_ENTERSUB](aTHX))) { PERL_CONTEXT *sub_cx = cxstack + cxstack_ix; - AV *argarray = CX_ARGARRAY(cx); + AV *argarray = cx->blk_sub.argarray; /* If pp_entersub() returns a non-null OP, it means that the callback is not * an XSUB. */ @@ -2074,9 +2221,9 @@ static I32 su_uplevel(pTHX_ CV *callback, I32 cxix, I32 args) { av_extend(av, AvMAX(argarray)); AvFILLp(av) = AvFILLp(argarray); Copy(AvARRAY(argarray), AvARRAY(av), AvFILLp(av) + 1, SV *); - CX_ARGARRAY_set(sub_cx, av); + sub_cx->blk_sub.argarray = av; } else { - SvREFCNT_inc_simple_void(CX_ARGARRAY(sub_cx)); + SvREFCNT_inc_simple_void(sub_cx->blk_sub.argarray); } if (su_uplevel_goto_static(CvROOT(renamed))) { @@ -2120,6 +2267,8 @@ static I32 su_uplevel(pTHX_ CV *callback, I32 cxix, I32 args) { return ret; } +#endif + /* --- Unique context ID --------------------------------------------------- */ static su_uid *su_uid_storage_fetch(pTHX_ UV depth) { @@ -2285,6 +2434,55 @@ static I32 su_context_skip_db(pTHX_ I32 cxix) { return cxix; } +#if SU_HAS_NEW_CXT + +/* convert a physical context stack index into the logical equivalent: + * one that ignores all the context frames hidden by uplevel(). + * Perl-level functions use logical args (e.g. UP takes an optional logical + * value and returns a logical value), while we use and store *real* + * values internally. + */ + +static I32 su_context_real2logical(pTHX_ I32 cxix) { +# define su_context_real2logical(C) su_context_real2logical(aTHX_ (C)) + PERL_CONTEXT *cx; + I32 i, gaps = 0; + + for (i = 0; i <= cxix; i++) { + cx = cxstack + i; + if (cx->cx_type == (CXt_NULL | CXp_SU_UPLEVEL_NULLED)) + gaps++; + } + XSH_D(su_debug_log("su_context_real2logical: %d => %d\n", cxix, cxix - gaps)); + return cxix - gaps; +} + +/* convert a logical context stack index (one that ignores all the context + * frames hidden by uplevel) into the physical equivalent + */ + +static I32 su_context_logical2real(pTHX_ I32 cxix) { +# define su_context_logical2real(C) su_context_logical2real(aTHX_ (C)) + PERL_CONTEXT *cx; + I32 i, seen = -1; + + for (i = 0; i <= cxstack_ix; i++) { + PERL_CONTEXT *cx = cxstack + i; + if (cx->cx_type != (CXt_NULL | CXp_SU_UPLEVEL_NULLED)) + seen++; + if (seen >= cxix) + break; + } + XSH_D(su_debug_log("su_context_logical2real: %d => %d\n", cxix, i)); + if (i > cxstack_ix) + i = cxstack_ix; + return i; +} + +#else +# define su_context_real2logical(C) (C) +# define su_context_logical2real(C) (C) +#endif static I32 su_context_normalize_up(pTHX_ I32 cxix) { #define su_context_normalize_up(C) su_context_normalize_up(aTHX_ (C)) @@ -2487,6 +2685,8 @@ static void xsh_user_global_teardown(pTHX) { /* --- XS ------------------------------------------------------------------ */ +/* D is real; B is logical. Returns real. */ + #define SU_GET_CONTEXT(A, B, D) \ STMT_START { \ if (items > A) { \ @@ -2498,6 +2698,7 @@ static void xsh_user_global_teardown(pTHX) { cxix = 0; \ else if (cxix > cxstack_ix) \ goto default_cx; \ + cxix = su_context_logical2real(cxix); \ } else { \ default_cx: \ cxix = (D); \ @@ -2646,7 +2847,7 @@ PROTOTYPE: PREINIT: I32 cxix; PPCODE: - cxix = su_context_here(); + cxix = su_context_real2logical(su_context_here()); EXTEND(SP, 1); mPUSHi(cxix); XSRETURN(1); @@ -2662,6 +2863,7 @@ PPCODE: --cxix; cxix = su_context_skip_db(cxix); cxix = su_context_normalize_up(cxix); + cxix = su_context_real2logical(cxix); } else { warn(su_stack_smash); } @@ -2685,6 +2887,7 @@ PPCODE: case CXt_SUB: if (PL_DBsub && cx->blk_sub.cv == GvCV(PL_DBsub)) continue; + cxix = su_context_real2logical(cxix); mPUSHi(cxix); XSRETURN(1); } @@ -2706,6 +2909,7 @@ PPCODE: default: continue; case CXt_EVAL: + cxix = su_context_real2logical(cxix); mPUSHi(cxix); XSRETURN(1); } @@ -2729,6 +2933,7 @@ PPCODE: --cxix; cxix = su_context_skip_db(cxix); cxix = su_context_normalize_up(cxix); + cxix = su_context_real2logical(cxix); } EXTEND(SP, 1); mPUSHi(cxix); @@ -2758,6 +2963,7 @@ done: if (level >= 0) warn(su_stack_smash); EXTEND(SP, 1); + cxix = su_context_real2logical(cxix); mPUSHi(cxix); XSRETURN(1); @@ -3040,7 +3246,11 @@ PPCODE: args = items - 2; } /* su_uplevel() takes care of extending the stack if needed. */ - ret = su_uplevel((CV *) code, cxix, args); +#if SU_HAS_NEW_CXT + ret = su_uplevel_new(aTHX_ (CV *) code, cxix, args); +#else + ret = su_uplevel_old(aTHX_ (CV *) code, cxix, args); +#endif XSRETURN(ret); default: break;