X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2FScope-Upper.git;a=blobdiff_plain;f=Upper.xs;h=0c762de1dcb947d420bd265d01231d8cec433d7e;hp=2ce8527fe2b7f8d3232a44b087418f567b6a9f76;hb=HEAD;hpb=f4167ba5f8779b2ae9174431fed29d3e0cd6411e diff --git a/Upper.xs b/Upper.xs index 2ce8527..7be4f69 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,24 +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])) -# 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,10 +353,10 @@ typedef struct { CV *callback; CV *renamed; -#ifdef 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 */ +#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; @@ -396,7 +375,7 @@ typedef struct { #endif } su_uplevel_ud; -#ifdef SU_HAS_NEW_CXT +#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. @@ -416,7 +395,7 @@ static su_uplevel_ud *su_uplevel_ud_new(pTHX) { sud->tmp_uid_storage.used = 0; sud->tmp_uid_storage.alloc = 0; - #ifndef SU_HAS_NEW_CXT +#if !SU_HAS_NEW_CXT Newx(si, 1, PERL_SI); si->si_stack = newAV(); AvREAL_off(si->si_stack); @@ -432,7 +411,7 @@ static su_uplevel_ud *su_uplevel_ud_new(pTHX) { static void su_uplevel_ud_delete(pTHX_ su_uplevel_ud *sud) { #define su_uplevel_ud_delete(S) su_uplevel_ud_delete(aTHX_ (S)) -#ifndef SU_HAS_NEW_CXT +#if !SU_HAS_NEW_CXT PERL_SI *si = sud->si; Safefree(si->si_cxstack); @@ -550,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) \ @@ -675,9 +653,9 @@ static void su_save_helem(pTHX_ HV *hv, SV *keysv, SV *val) { return; } - if (preeminent) + if (preeminent) { save_helem(hv, keysv, svp); - else { + } else { STRLEN keylen; const char * const key = SvPV_const(keysv, keylen); SAVEDELETE(hv, savepvn(key, keylen), @@ -731,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) @@ -777,7 +754,7 @@ static void su_call(pTHX_ SV *cb) { dSP; - XSH_D(su_debug_log("@@@ call scope_ix=%2d save_ix=%2d\n", + XSH_D(xsh_debug_log("@@@ call scope_ix=%2d save_ix=%2d\n", PL_scopestack_ix, PL_savestack_ix)); ENTER; @@ -831,25 +808,31 @@ typedef struct { static I32 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; - I32 size; + int take_ref = 0; + svtype t = SVt_NULL; + I32 size; SvREFCNT_inc_simple_void(sv); if (SvTYPE(sv) >= SVt_PVGV) { + if (SvFAKE(sv)) { + sv_force_normal(sv); + goto string_spec; + } + if (!val || !SvROK(val)) { /* local *x; or local *x = $val; */ t = SVt_PVGV; } else { /* local *x = \$val; */ t = SvTYPE(SvRV(val)); - deref = 1; } } else if (SvROK(sv)) { croak("Invalid %s reference as the localization target", sv_reftype(SvRV(sv), 0)); } else { STRLEN len, l; - const char *p = SvPV_const(sv, len), *s; + const char *p, *s; +string_spec: + p = SvPV_const(sv, len); for (s = p, l = len; l > 0 && isSPACE(*s); ++s, --l) { } if (!l) { l = len; @@ -865,14 +848,17 @@ static I32 su_ud_localize_init(pTHX_ su_ud_localize *ud, SV *sv, SV *val, SV *el if (t != SVt_NULL) { ++s; --l; + if (t == SVt_PV) + take_ref = 1; } else if (val) { /* t == SVt_NULL, type can't be inferred from the sigil */ if (SvROK(val) && !sv_isobject(val)) { t = SvTYPE(SvRV(val)); - deref = 1; } else { t = SvTYPE(val); + take_ref = 1; } } + SvREFCNT_dec(sv); sv = newSVpvn(s, l); } @@ -881,31 +867,31 @@ static I32 su_ud_localize_init(pTHX_ su_ud_localize *ud, SV *sv, SV *val, SV *el case SVt_PVAV: size = elem ? SU_SAVE_AELEM_OR_ADELETE_SIZE : SU_SAVE_ARY_SIZE; - deref = 0; break; case SVt_PVHV: size = elem ? SU_SAVE_HELEM_OR_HDELETE_SIZE : SU_SAVE_HASH_SIZE; - deref = 0; break; case SVt_PVGV: size = SU_SAVE_GP_SIZE; - deref = 0; break; case SVt_PVCV: size = SU_SAVE_GVCV_SIZE; - deref = 0; break; default: size = SU_SAVE_SCALAR_SIZE; break; } - /* When deref is set, val isn't NULL */ SU_UD_PRIVATE(ud) = t; ud->sv = sv; - ud->val = val ? newSVsv(deref ? SvRV(val) : val) : NULL; + if (val) { + val = newSVsv(val); + ud->val = take_ref ? newRV_noinc(val) : val; + } else { + ud->val = NULL; + } ud->elem = SvREFCNT_inc(elem); return size; @@ -923,33 +909,35 @@ 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 } XSH_D({ SV *z = newSV(0); SvUPGRADE(z, t); - su_debug_log("%p: === localize a %s\n",ud, sv_reftype(z, 0)); - su_debug_log("%p: depth=%2d scope_ix=%2d save_ix=%2d\n", - ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix); + xsh_debug_log("%p: === localize a %s\n", ud, sv_reftype(z, 0)); + xsh_debug_log("%p: depth=%2d scope_ix=%2d save_ix=%2d\n", + ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix); SvREFCNT_dec(z); }); @@ -959,15 +947,17 @@ static void su_localize(pTHX_ void *ud_) { if (elem) { su_save_aelem(GvAV(gv), elem, val); return; - } else + } else { save_ary(gv); + } break; case SVt_PVHV: if (elem) { su_save_helem(GvHV(gv), elem, val); return; - } else + } else { save_hash(gv); + } break; case SVt_PVGV: save_gp(gv, 1); /* hide previous entry in symtab */ @@ -976,7 +966,7 @@ static void su_localize(pTHX_ void *ud_) { su_save_gvcv(gv); break; default: - gv = (GV *) save_scalar(gv); + save_scalar(gv); break; } @@ -1071,6 +1061,8 @@ static const char *su_block_type[] = { #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 */ @@ -1090,44 +1082,52 @@ static const int su_cxt_enter_count[] = { # endif }; - +#endif /* XSH_DEBUG */ /* push at least 'size' slots worth of padding onto the savestack */ static void su_ss_push_padding(pTHX_ void *ud, I32 size) { +#define su_ss_push_padding(U, S) su_ss_push_padding(aTHX_ (U), (S)) if (size <= 0) return; + if (size < SU_SAVE_ALLOC_SIZE + 1) /* minimum possible SAVEt_ALLOC */ size = SU_SAVE_ALLOC_SIZE + 1; - XSH_D(su_debug_log( - "%p: push %2d padding at save_ix=%d\n", - ud, size, PL_savestack_ix)); - save_alloc((size - SU_SAVE_ALLOC_SIZE)*sizeof(*PL_savestack), 0); -} + XSH_D(xsh_debug_log( + "%p: push %2d padding at save_ix=%d\n", + ud, size, PL_savestack_ix)); -static void su_pop(pTHX_ void *ud); + save_alloc((size - SU_SAVE_ALLOC_SIZE) * sizeof(*PL_savestack), 0); + return; +} +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) { +#define su_ss_push_destructor(U, D, F) su_ss_push_destructor(aTHX_ (U), (D), (F)) 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, - (origin[depth].orig_ix + origin[depth].offset) - PL_savestack_ix); - XSH_D(su_debug_log( - "%p: push destructor at save_ix=%d depth=%d scope_ix=%d\n", - ud, PL_savestack_ix, depth, PL_scopestack_ix)); + + su_ss_push_padding(ud, + (origin[depth].orig_ix + origin[depth].offset) - PL_savestack_ix); + + XSH_D(xsh_debug_log( + "%p: push destructor at save_ix=%d depth=%d scope_ix=%d\n", + ud, PL_savestack_ix, depth, PL_scopestack_ix)); + SAVEDESTRUCTOR_X(su_pop, ud); + assert(first || - PL_savestack_ix <= origin[depth+1].orig_ix + origin[depth+1].offset); -} + PL_savestack_ix <= origin[depth+1].orig_ix + origin[depth+1].offset); + return; +} /* this is called during each leave_scope() via SAVEDESTRUCTOR_X */ @@ -1139,17 +1139,17 @@ static void su_pop(pTHX_ void *ud) { depth = SU_UD_DEPTH(ud); origin = SU_UD_ORIGIN(ud); - XSH_D(su_debug_log( "%p: ### su_pop: depth=%d\n", ud, depth)); + XSH_D(xsh_debug_log("%p: ### su_pop: depth=%d\n", ud, depth)); depth--; mark = PL_savestack_ix; base = origin[depth].orig_ix; - XSH_D(su_debug_log("%p: residual savestack frame is %d(+%d)..%d\n", - ud, base, origin[depth].offset, mark)); + XSH_D(xsh_debug_log("%p: residual savestack frame is %d(+%d)..%d\n", + ud, base, origin[depth].offset, mark)); if (base < mark) { - XSH_D(su_debug_log("%p: clear leftovers at %d..%d\n", ud, base, mark)); + XSH_D(xsh_debug_log("%p: clear leftovers at %d..%d\n", ud, base, mark)); leave_scope(base); } assert(PL_savestack_ix == base); @@ -1157,13 +1157,15 @@ static void su_pop(pTHX_ void *ud) { SU_UD_DEPTH(ud) = depth; if (depth > 0) { - su_ss_push_destructor(aTHX_ ud, depth-1, 0); + su_ss_push_destructor(ud, depth-1, 0); } else { I32 offset = origin[0].offset; /* grab value before origin is freed */ switch (SU_UD_TYPE(ud)) { case SU_UD_TYPE_REAP: { - XSH_D(su_debug_log("%p: === reap\n%p: depth=%d scope_ix=%d save_ix=%d\n", - ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix)); + XSH_D( + xsh_debug_log("%p: === reap\n%p: depth=%d scope_ix=%d save_ix=%d\n", + ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix) + ); SAVEDESTRUCTOR_X(su_call, SU_UD_REAP_CB(ud)); SU_UD_FREE(ud); break; @@ -1181,31 +1183,29 @@ static void su_pop(pTHX_ void *ud) { if (PL_savestack_ix < base + offset) { I32 gap = (base + offset) - PL_savestack_ix; assert(gap >= SU_SAVE_ALLOC_SIZE + 1); - su_ss_push_padding(aTHX_ ud, gap); + su_ss_push_padding(ud, gap); } assert(PL_savestack_ix == base + offset); } - XSH_D(su_debug_log("%p: end pop: ss_ix=%d\n", ud, PL_savestack_ix)); + XSH_D(xsh_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; su_ud_origin_elem *origin; - I32 cur_cx_ix; - I32 cur_scope_ix; + I32 i, depth; + I32 cur_cx_ix, cur_scope_ix; - XSH_D(su_debug_log("%p: ### su_init(cxix=%d, size=%d)\n", ud, cxix, size)); + XSH_D(xsh_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 + depth = PL_scopestack_ix - cxstack[cxix].blk_oldscopesp; +#if SU_HAS_NEW_CXT depth += (cxstack_ix - cxix); /* each context frame holds 1 scope */ #endif - XSH_D(su_debug_log( + XSH_D(xsh_debug_log( "%p: going down by depth=%d with scope_ix=%d save_ix=%d\n", ud, depth, PL_scopestack_ix, PL_savestack_ix)); @@ -1247,28 +1247,28 @@ 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_cx_ix = cxix; cur_scope_ix = cxstack[cxix].blk_oldscopesp; -#ifdef SU_HAS_NEW_CXT - XSH_D(su_debug_log("%p: cx=%-2d %-11s\n", - ud, cur_cx_ix, SU_CXNAME(cxstack+cur_cx_ix))); + +#if SU_HAS_NEW_CXT + XSH_D(xsh_debug_log("%p: cx=%-2d %-11s\n", + ud, cur_cx_ix, SU_CXNAME(cxstack+cur_cx_ix))); cur_cx_ix++; #endif for (i = 0; cur_scope_ix < PL_scopestack_ix; i++) { I32 *ixp; - I32 offset; + 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 - ) + if (cur_cx_ix <= cxstack_ix + && cur_scope_ix == cxstack[cur_cx_ix].blk_oldscopesp) ixp = &(cxstack[cur_cx_ix++].blk_oldsaveix); else ixp = &PL_scopestack[cur_scope_ix++]; /* an ENTER pushed after cur context */ @@ -1278,23 +1278,23 @@ static void su_init(pTHX_ void *ud, I32 cxix, I32 size) { XSH_D({ if (cur_cx_ix <= cxstack_ix) { if (cur_scope_ix == cxstack[cur_cx_ix].blk_oldscopesp) { - su_debug_log( - "%p: cx=%-2d %s\n%p: ------------------\n", - ud, cur_cx_ix, SU_CXNAME(cxstack+cur_cx_ix), ud); + xsh_debug_log("%p: cx=%-2d %s\n%p: ------------------\n", + ud, cur_cx_ix, SU_CXNAME(cxstack+cur_cx_ix), ud); cur_cx_ix++; } else if (cur_scope_ix + su_cxt_enter_count[CxTYPE(cxstack+cur_cx_ix)] == cxstack[cur_cx_ix].blk_oldscopesp) - su_debug_log("%p: ------------------\n", ud); + xsh_debug_log("%p: ------------------\n", ud); } }); + ixp = &PL_scopestack[cur_scope_ix++]; #endif - if (i == 0) + if (i == 0) { offset = size; - else { + } else { /* we have three constraints to satisfy: * 1) Each adjusted offset must be at least SU_SAVE_DESTRUCTOR_SIZE * above its unadjusted boundary, so that there is space to inject a @@ -1310,7 +1310,8 @@ static void su_init(pTHX_ void *ud, I32 cxix, I32 size) { */ I32 pad; offset = SU_SAVE_DESTRUCTOR_SIZE; /* rule 1 */ - pad = (origin[i-1].orig_ix + origin[i-1].offset) + offset - (*ixp + offset); + pad = (origin[i-1].orig_ix + origin[i-1].offset) + offset + - (*ixp + offset); if (pad > 0) { /* rule 2 */ if (pad < SU_SAVE_ALLOC_SIZE + 1) /* rule 3 */ pad = SU_SAVE_ALLOC_SIZE + 1; @@ -1318,24 +1319,24 @@ static void su_init(pTHX_ void *ud, I32 cxix, I32 size) { } } - origin[i].offset = offset; + origin[i].offset = offset; origin[i].orig_ix = *ixp; - *ixp += offset; + *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( + xsh_debug_log( "%p: ENTER origin[%d] scope[%d] savestack=%d+%d\n", ud, i, cur_scope_ix, origin[i].orig_ix, origin[i].offset); else - su_debug_log( + xsh_debug_log( "%p: cx=%-2d %-11s origin[%d] scope[%d] savestack=%d+%d\n", ud, cur_cx_ix-1, SU_CXNAME(cxstack+cur_cx_ix-1), i, cur_scope_ix, origin[i].orig_ix, origin[i].offset); }); #else - XSH_D(su_debug_log( + XSH_D(xsh_debug_log( "%p: ENTER origin[%d] scope[%d] savestack=%d+%d\n", ud, i, cur_scope_ix, origin[i].orig_ix, origin[i].offset)); #endif @@ -1347,10 +1348,9 @@ static void su_init(pTHX_ void *ud, I32 cxix, I32 size) { SU_UD_DEPTH(ud) = depth; SU_UD_ORIGIN(ud) = origin; - su_ss_push_destructor(aTHX_ ud, depth-1, 1); + su_ss_push_destructor(ud, depth-1, 1); } - /* --- Unwind stack -------------------------------------------------------- */ static void su_unwind(pTHX_ void *ud_) { @@ -1380,7 +1380,7 @@ static void su_unwind(pTHX_ void *ud_) { XSH_D({ I32 gimme = GIMME_V; - su_debug_log("%p: cx=%d gimme=%s items=%d sp=%d oldmark=%d mark=%d\n", + xsh_debug_log("%p: cx=%d gimme=%s items=%d sp=%d oldmark=%d mark=%d\n", &XSH_CXT, cxix, gimme == G_VOID ? "void" : gimme == G_ARRAY ? "list" : "scalar", items, PL_stack_sp - PL_stack_base, *PL_markstack_ptr, mark); @@ -1418,8 +1418,6 @@ static void su_yield(pTHX_ void *ud_) { U8 flags = 0; OP *next; - PERL_UNUSED_VAR(ud_); - cx = cxstack + cxix; switch (CxTYPE(cx)) { case CXt_BLOCK: { @@ -1670,7 +1668,7 @@ static int su_uplevel_goto_static(const OP *o) { return 0; } -#if !defined(SU_HAS_NEW_CXT) && 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) @@ -1689,7 +1687,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; @@ -1732,7 +1730,7 @@ done: #define su_at_underscore(C) PadARRAY(PadlistARRAY(CvPADLIST(C))[CvDEPTH(C)])[0] -#ifdef SU_HAS_NEW_CXT +#if SU_HAS_NEW_CXT static void su_uplevel_restore_new(pTHX_ void *sus_) { su_uplevel_ud *sud = sus_; @@ -1742,10 +1740,10 @@ static void su_uplevel_restore_new(pTHX_ void *sus_) { 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]; + XSH_D(xsh_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); @@ -1810,8 +1808,8 @@ static void su_uplevel_restore_old(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)--; @@ -2003,9 +2001,7 @@ static CV *su_cv_clone(pTHX_ CV *proto, GV *gv) { return cv; } - - -#ifdef SU_HAS_NEW_CXT +#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 @@ -2026,30 +2022,38 @@ static int su_uplevel_runops_hook_entersub(pTHX) { */ assert(sud); if (sud->argarray) { + I32 fill; 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 *); + fill = AvFILLp(sud->argarray); + if (fill >= 0) { + av_extend(av, fill); + Copy(AvARRAY(sud->argarray), AvARRAY(av), fill + 1, SV *); + AvFILLp(av) = fill; + } + +#if !XSH_HAS_PERL(5, 37, 10) /* should be referenced by PL_curpad[0] and *_ */ assert(SvREFCNT(PL_curpad[0]) > 1); SvREFCNT_dec(PL_curpad[0]); +#endif - PL_curpad[0] = (SV*)av; + 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) { +#define su_uplevel_new(CB, CX, A) su_uplevel_new(aTHX_ (CB), (CX), (A)) su_uplevel_ud *sud; U8 *saved_cxtypes; I32 i, ret; @@ -2065,7 +2069,7 @@ static I32 su_uplevel_new(pTHX_ CV *callback, I32 cxix, I32 args) { /* 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*); + Move(SP - args + 1, SP - args, args, SV *); SP--; PUSHMARK(SP - args); PUTBACK; @@ -2073,12 +2077,11 @@ static I32 su_uplevel_new(pTHX_ CV *callback, I32 cxix, I32 args) { sud = su_uplevel_storage_new(cxix); sud->cxix = cxix; - sud->callback = (CV*)SvREFCNT_inc_simple(callback); + 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; @@ -2090,19 +2093,18 @@ static I32 su_uplevel_new(pTHX_ CV *callback, I32 cxix, I32 args) { 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", + XSH_D(xsh_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->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); + 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 */ @@ -2111,7 +2113,7 @@ static I32 su_uplevel_new(pTHX_ CV *callback, I32 cxix, I32 args) { CvDEPTH(callback)++; /* match what CvDEPTH(sud->renamed) is about to become */ - ret = call_sv((SV*)sud->renamed, gimme); + ret = call_sv((SV *) sud->renamed, gimme); LEAVE; @@ -2121,6 +2123,7 @@ static I32 su_uplevel_new(pTHX_ CV *callback, I32 cxix, I32 args) { #else static I32 su_uplevel_old(pTHX_ CV *callback, I32 cxix, I32 args) { +#define su_uplevel_old(CB, CX, A) su_uplevel_old(aTHX_ (CB), (CX), (A)) su_uplevel_ud *sud; const PERL_CONTEXT *cx = cxstack + cxix; PERL_SI *si; @@ -2233,7 +2236,7 @@ static I32 su_uplevel_old(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. */ @@ -2253,9 +2256,9 @@ static I32 su_uplevel_old(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))) { @@ -2466,8 +2469,7 @@ static I32 su_context_skip_db(pTHX_ I32 cxix) { return cxix; } - -#ifdef SU_HAS_NEW_CXT +#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(). @@ -2486,7 +2488,9 @@ static I32 su_context_real2logical(pTHX_ I32 cxix) { 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)); + + XSH_D(xsh_debug_log("su_context_real2logical: %d => %d\n", cxix, cxix - gaps)); + return cxix - gaps; } @@ -2506,9 +2510,12 @@ static I32 su_context_logical2real(pTHX_ I32 cxix) { if (seen >= cxix) break; } - XSH_D(su_debug_log("su_context_logical2real: %d => %d\n", cxix, i)); + + XSH_D(xsh_debug_log("su_context_logical2real: %d => %d\n", cxix, i)); + if (i > cxstack_ix) i = cxstack_ix; + return i; } @@ -2517,7 +2524,6 @@ static I32 su_context_logical2real(pTHX_ I32 cxix) { # 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)) PERL_CONTEXT *cx; @@ -2848,7 +2854,9 @@ XS(XS_Scope__Upper_leave) { /* See XS_Scope__Upper_unwind */ if (GIMME_V == G_SCALAR) PL_stack_sp = PL_stack_base + PL_markstack_ptr[1] + 1; + SAVEDESTRUCTOR_X(su_yield, su_leave_name); + return; } @@ -3130,7 +3138,9 @@ PPCODE: /* warnings (9) */ { SV *mask = NULL; -#if XSH_HAS_PERL(5, 9, 4) +#if XSH_HAS_PERL(5, 37, 6) + char *old_warnings = cop->cop_warnings; +#elif XSH_HAS_PERL(5, 9, 4) STRLEN *old_warnings = cop->cop_warnings; #else SV *old_warnings = cop->cop_warnings; @@ -3163,7 +3173,9 @@ context_info_warnings_on: if (!mask) mask = su_newmortal_pvn(WARN_ALLstring, WARNsize); } else { -#if XSH_HAS_PERL(5, 9, 4) +#if XSH_HAS_PERL(5, 37, 6) + mask = su_newmortal_pvn((char *) old_warnings, RCPV_LEN(old_warnings)); +#elif XSH_HAS_PERL(5, 9, 4) mask = su_newmortal_pvn((char *) (old_warnings + 1), old_warnings[0]); #else mask = sv_mortalcopy(old_warnings); @@ -3280,10 +3292,10 @@ PPCODE: args = items - 2; } /* su_uplevel() takes care of extending the stack if needed. */ -#ifdef SU_HAS_NEW_CXT - ret = su_uplevel_new(aTHX_ (CV *) code, cxix, args); +#if SU_HAS_NEW_CXT + ret = su_uplevel_new((CV *) code, cxix, args); #else - ret = su_uplevel_old(aTHX_ (CV *) code, cxix, args); + ret = su_uplevel_old((CV *) code, cxix, args); #endif XSRETURN(ret); default: