# 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
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);
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));
}
}
STATIC void su_call(pTHX_ void *ud_) {
su_ud_reap *ud = (su_ud_reap *) ud_;
-#if SU_HAS_PERL(5, 10, 0)
+#if SU_HAS_PERL(5, 9, 5)
+ PERL_CONTEXT saved_cx;
I32 dieing = PL_op->op_type == OP_DIE;
+ I32 cxix;
#endif
dSP;
- SU_D(PerlIO_printf(Perl_debug_log, "%p: @@@ call at %d (save is %d)\n",
- ud, PL_scopestack_ix, PL_savestack_ix));
+ 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);
+ });
+
ENTER;
SAVETMPS;
PUSHMARK(SP);
PUTBACK;
- /* If cxstack_ix isn't incremented there, the eval context will be overwritten
- * when the new sub scope will be created in call_sv. */
+ /* If the recently popped context isn't saved there, it will be overwritten by
+ * the sub scope from call_sv, although it's still needed in our caller. */
-#if SU_HAS_PERL(5, 10, 0)
- if (dieing)
+#if SU_HAS_PERL(5, 9, 5)
+ if (dieing) {
if (cxstack_ix < cxstack_max)
- ++cxstack_ix;
+ cxix = cxstack_ix + 1;
else
- cxstack_ix = Perl_cxinc(aTHX);
+ cxix = Perl_cxinc(aTHX);
+ saved_cx = cxstack[cxix];
+ }
#endif
call_sv(ud->cb, G_VOID);
-#if SU_HAS_PERL(5, 10, 0)
- if (dieing && cxstack_ix > 0)
- --cxstack_ix;
+#if SU_HAS_PERL(5, 9, 5)
+ if (dieing)
+ cxstack[cxix] = saved_cx;
#endif
- SPAGAIN;
PUTBACK;
FREETMPS;
STATIC void su_reap(pTHX_ void *ud) {
#define su_reap(U) su_reap(aTHX_ (U))
- SU_D(PerlIO_printf(Perl_debug_log, "%p: === reap at %d (save is %d)\n",
- ud, PL_scopestack_ix, PL_savestack_ix));
+ SU_D({
+ PerlIO_printf(Perl_debug_log,
+ "%p: === reap\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
+ ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
+ });
+
SAVEDESTRUCTOR_X(su_call, ud);
- SU_D(PerlIO_printf(Perl_debug_log, "%p: savestack is now at %d, base at %d\n",
- ud, PL_savestack_ix,
- PL_scopestack[PL_scopestack_ix]));
}
/* ... Localize & localize array/hash element .............................. */
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;
}
}
SU_D({
- SV *z = newSV_type(t);
- PerlIO_printf(Perl_debug_log, "%p: === localize a %s at %d (save is %d)\n",
- ud, sv_reftype(z, 0),
- PL_scopestack_ix, PL_savestack_ix);
+ SV *z = newSV(0);
+ SvUPGRADE(z, t);
+ PerlIO_printf(Perl_debug_log, "%p: === localize a %s\n",ud, sv_reftype(z, 0));
+ PerlIO_printf(Perl_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);
});
break;
default:
gv = (GV *) save_scalar(gv);
-maybe_deref:
if (deref) /* val != NULL */
val = SvRV(val);
break;
}
- SU_D(PerlIO_printf(Perl_debug_log, "%p: savestack is now at %d, base at %d\n",
- ud, PL_savestack_ix,
- PL_scopestack[PL_scopestack_ix]));
-
-assign:
if (val)
SvSetMagicSV((SV *) gv, val);
I32 depth, base, mark, *origin;
depth = SU_UD_DEPTH(ud);
- SU_D(PerlIO_printf(Perl_debug_log, "%p: --- pop %s at %d from %d to %d [%d]\n",
- ud, SU_CXNAME,
- PL_scopestack_ix, PL_savestack_ix,
- PL_scopestack[PL_scopestack_ix],
- depth));
+ SU_D({
+ PerlIO_printf(Perl_debug_log, "%p: --- pop a %s\n", ud, SU_CXNAME);
+ 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]);
+ });
origin = SU_UD_ORIGIN(ud);
mark = origin[depth];
base = origin[depth - 1];
- SU_D(PerlIO_printf(Perl_debug_log, "%p: clean from %d down to %d\n",
- ud, mark, base));
+ SU_D(PerlIO_printf(Perl_debug_log,
+ "%p: original scope was %*c top=%2d base=%2d\n",
+ ud, 20, ' ', mark, base));
if (base < mark) {
+ SU_D(PerlIO_printf(Perl_debug_log, "%p: clear leftovers\n", ud));
PL_savestack_ix = mark;
leave_scope(base);
}
PL_savestack_ix = base;
- if (--depth > 0) {
- SU_UD_DEPTH(ud) = depth;
- SU_D(PerlIO_printf(Perl_debug_log, "%p: save new destructor at %d [%d]\n",
- ud, PL_savestack_ix, depth));
+
+ 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));
+
SAVEDESTRUCTOR_X(su_pop, ud);
- SU_D(PerlIO_printf(Perl_debug_log, "%p: pop end at at %d [%d]\n",
- ud, PL_savestack_ix, depth));
} else {
SU_UD_HANDLER(ud)(aTHX_ ud);
}
+
+ SU_D(PerlIO_printf(Perl_debug_log,
+ "%p: --- end pop: cur_top=%2d == cur_base=%2d\n",
+ ud, PL_savestack_ix, PL_scopestack[PL_scopestack_ix]));
}
/* --- 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;
- I32 cur, last, step;
- LEAVE;
+ LEAVE_with_name("sub");
if (cxix >= cxstack_ix) {
SU_UD_HANDLER(ud)(aTHX_ ud);
for (i = cxstack_ix; i > cxix; --i) {
PERL_CONTEXT *cx = cxstack + i;
switch (CxTYPE(cx)) {
+#if SU_HAS_PERL(5, 10, 0)
+ case CXt_BLOCK:
+ SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is block\n", ud, i));
+ /* Given and when blocks are actually followed by a simple block, so skip
+ * it if needed. */
+ if (cxix > 0) { /* Implies i > 0 */
+ PERL_CONTEXT *next = cx - 1;
+ if (CxTYPE(next) == CXt_GIVEN || CxTYPE(next) == CXt_WHEN)
+ --cxix;
+ }
+ depth++;
+ break;
+#endif
#if SU_HAS_PERL(5, 11, 0)
case CXt_LOOP_FOR:
case CXt_LOOP_PLAIN:
depth += 2;
break;
default:
- SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is normal\n", ud, i));
+ SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is other\n", ud, i));
depth++;
break;
}
}
origin[depth] = PL_savestack_ix;
- SU_D({
- PerlIO_printf(Perl_debug_log, "%p: d=%d s=%d x=%d c=%d o=%d\n", ud,
- depth, 0, PL_scopestack_ix - 1, PL_savestack_ix, origin[depth]);
- for (i = depth - 1; i >= 0; --i) {
- I32 x = PL_scopestack_ix - depth + i;
- PerlIO_printf(Perl_debug_log, "%p: d=%d s=%d x=%d c=%d o=%d\n", ud,
- i, depth - i, x, PL_scopestack[x], origin[i]);
- }
- });
-
SU_UD_ORIGIN(ud) = origin;
SU_UD_DEPTH(ud) = depth;
- SU_D(PerlIO_printf(Perl_debug_log, "%p: set original destructor at %d [%d]\n",
- ud, PL_savestack_ix, depth));
+ SU_D(PerlIO_printf(Perl_debug_log,
+ "%p: set original destructor at depth=%2d scope_ix=%2d save_ix=%2d\n",
+ ud, depth, PL_scopestack_ix - 1, PL_savestack_ix));
SAVEDESTRUCTOR_X(su_pop, ud);
+ SU_D({
+ for (i = 0; i <= depth; ++i) {
+ I32 j = PL_scopestack_ix - i;
+ PerlIO_printf(Perl_debug_log,
+ "%p: depth=%2d scope_ix=%2d saved_floor=%2d new_floor=%2d\n",
+ ud, i, j, origin[depth - i],
+ i == 0 ? PL_savestack_ix : PL_scopestack[j]);
+ }
+ });
+
done:
- ENTER;
+ ENTER_with_name("sub");
return depth;
}
SV **savesp = MY_CXT.savesp;
I32 mark;
+ PERL_UNUSED_VAR(ud_);
+
if (savesp)
PL_stack_sp = savesp;
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; \
+ (C) -= i + 1; \
+ break; \
+ } \
+ } else \
+ break; \
} while (++i <= SU_SKIP_DB_MAX); \
} STMT_END
STMT_START { \
if (items > A) { \
SV *csv = ST(B); \
- if (SvOK(csv)) \
- cxix = SvIV(csv); \
+ 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_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 */
XS(XS_Scope__Upper_unwind) {
HV *stash;
MY_CXT_INIT;
stash = gv_stashpv(__PACKAGE__, 1);
- newCONSTSUB(stash, "TOP", newSViv(0));
+ newCONSTSUB(stash, "TOP", newSViv(0));
+ newCONSTSUB(stash, "SU_THREADSAFE", newSVuv(SU_THREADSAFE));
newXSproto("Scope::Upper::unwind", XS_Scope__Upper_unwind, file, NULL);
}
+#if SU_THREADSAFE
+
void
CLONE(...)
PROTOTYPE: DISABLE
CODE:
-#if SU_THREADSAFE
- MY_CXT_CLONE;
+ PERL_UNUSED_VAR(items);
+ {
+ MY_CXT_CLONE;
+ }
+
#endif /* SU_THREADSAFE */
SV *
XSRETURN_UNDEF;
void
-CALLER(...)
+SCOPE(...)
PROTOTYPE: ;$
PREINIT:
- I32 cxix, caller = 0;
+ I32 cxix, level;
PPCODE:
- if (items) {
- SV *csv = ST(0);
- if (SvOK(csv))
- caller = SvIV(csv);
- if (caller < 0)
- caller = 0;
+ SU_GET_LEVEL(0, 0);
+ cxix = cxstack_ix;
+ 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)) {
continue;
case CXt_EVAL:
case CXt_FORMAT:
- --caller;
- if (caller < 0)
+ if (--level < 0)
goto done;
break;
}