+XS(XS_Scope__Upper_unwind); /* prototype to pass -Wmissing-prototypes */
+
+XS(XS_Scope__Upper_unwind) {
+#ifdef dVAR
+ dVAR; dXSARGS;
+#else
+ dXSARGS;
+#endif
+ I32 cxix;
+ su_ud_unwind *ud;
+ SV *level;
+ if (!items)
+ Perl_croak(aTHX_ "Usage: Scope::Upper::unwind(..., level)");
+ PERL_UNUSED_VAR(cv); /* -W */
+ PERL_UNUSED_VAR(ax); /* -Wall */
+ level = ST(items - 1);
+ cxix = SvOK(level) ? SvIV(level) : 0;
+ if (cxix < 0)
+ cxix = 0;
+ else if (cxix > cxstack_ix)
+ cxix = cxstack_ix;
+ cxix = cxstack_ix - cxix;
+ do {
+ PERL_CONTEXT *cx = cxstack + cxix;
+ switch (CxTYPE(cx)) {
+ case CXt_SUB:
+ case CXt_EVAL:
+ case CXt_FORMAT:
+ /* pp_entersub will try to sanitize the stack - screw that, we're insane */
+ if (GIMME_V == G_SCALAR)
+ PL_stack_sp = PL_stack_base + TOPMARK + 1;
+ Newx(ud, 1, su_ud_unwind);
+ ud->cxix = cxix;
+ ud->items = items;
+ SAVEDESTRUCTOR_X(su_unwind, ud);
+ return;
+ default:
+ break;
+ }
+ } while (--cxix >= 0);
+ croak("Can't return outside a subroutine");
+}
+