+/* --- Unwind stack -------------------------------------------------------- */
+
+typedef struct {
+ I32 cxix;
+ I32 items;
+} su_ud_unwind;
+
+STATIC void su_unwind(pTHX_ void *ud_) {
+ su_ud_unwind *ud = (su_ud_unwind *) ud_;
+ OP fakeop;
+ I32 cxix = ud->cxix;
+ I32 items = ud->items - 1;
+ I32 gimme, mark;
+
+ if (cxstack_ix > cxix)
+ dounwind(cxix);
+
+ /* Hide the level */
+ if (items >= 0)
+ PL_stack_sp--;
+
+ mark = PL_markstack[cxstack[cxix].blk_oldmarksp];
+
+ gimme = GIMME_V;
+ if (gimme == G_SCALAR) {
+ *PL_markstack_ptr = PL_stack_sp - PL_stack_base;
+ PL_stack_sp += items;
+ } else {
+ *PL_markstack_ptr = PL_stack_sp - PL_stack_base - items;
+ }
+
+ SU_D({
+ PerlIO_printf(Perl_debug_log,
+ "%p: cx=%d gimme=%s items=%d sp=%d oldmark=%d mark=%d\n",
+ ud, cxix,
+ gimme == G_VOID ? "void" : gimme == G_ARRAY ? "list" : "scalar",
+ items, PL_stack_sp - PL_stack_base, *PL_markstack_ptr, mark);
+ });
+
+ PL_op = PL_ppaddr[OP_RETURN](aTHX);
+ *PL_markstack_ptr = mark;
+
+ fakeop.op_next = PL_op;
+ PL_op = &fakeop;
+
+ Safefree(ud);
+}
+
+/* --- XS ------------------------------------------------------------------ */
+
+#define SU_GET_LEVEL(A) \
+ STMT_START { \
+ if (items > A) { \
+ SV *lsv = ST(A); \
+ if (SvOK(lsv)) \
+ level = SvIV(lsv); \
+ if (level < 0) \
+ XSRETURN(0); \
+ } \
+ if (level > cxstack_ix) \
+ level = cxstack_ix; \
+ } STMT_END
+
+#define SU_GET_CONTEXT(A, B) \
+ STMT_START { \
+ if (items > A) { \
+ SV *lsv = ST(B); \
+ if (SvOK(lsv)) \
+ level = SvIV(lsv); \
+ if (level < 0) \
+ level = 0; \
+ else if (level > cxix) \
+ level = cxix; \
+ } \
+ } STMT_END