+#endif
+
+/* ... Trampoline ops ...................................................... */
+
+/* NewOp() isn't public in perl 5.8.0. */
+#define VMG_RESET_RMG_NEEDS_TRAMPOLINE (VMG_UVAR && (VMG_THREADSAFE || !VMG_HAS_PERL(5, 8, 1)))
+
+#define VMG_NEEDS_TRAMPOLINE VMG_RESET_RMG_NEEDS_TRAMPOLINE
+
+#if VMG_NEEDS_TRAMPOLINE
+
+typedef struct {
+ OP temp;
+ SVOP target;
+} vmg_trampoline;
+
+STATIC void vmg_trampoline_init(vmg_trampoline *t, OP *(*cb)(pTHX)) {
+ t->temp.op_type = OP_STUB;
+ t->temp.op_ppaddr = 0;
+ t->temp.op_next = (OP *) &t->target;
+ t->temp.op_flags = 0;
+ t->temp.op_private = 0;
+
+ t->target.op_type = OP_STUB;
+ t->target.op_ppaddr = cb;
+ t->target.op_next = NULL;
+ t->target.op_flags = 0;
+ t->target.op_private = 0;
+ t->target.op_sv = NULL;
+}
+
+STATIC OP *vmg_trampoline_bump(pTHX_ vmg_trampoline *t, SV *sv, OP *o) {
+#define vmg_trampoline_bump(T, S, O) vmg_trampoline_bump(aTHX_ (T), (S), (O))
+ t->temp = *o;
+ t->temp.op_next = (OP *) &t->target;
+
+ t->target.op_sv = sv;
+ t->target.op_next = o->op_next;
+
+ return &t->temp;
+}
+
+#endif /* VMG_NEEDS_TRAMPOLINE */
+
+/* ... Safe version of call_sv() ........................................... */
+
+STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, int (*cleanup)(pTHX_ void *), void *ud) {
+#define vmg_call_sv(S, F, C, U) vmg_call_sv(aTHX_ (S), (F), (C), (U))
+ I32 ret, cxix, in_eval = 0;
+ PERL_CONTEXT saved_cx;
+ SV *old_err = NULL;
+
+ if (SvTRUE(ERRSV)) {
+ old_err = ERRSV;
+ ERRSV = newSV(0);
+ }
+
+ if (cxstack_ix < cxstack_max) {
+ cxix = cxstack_ix + 1;
+ in_eval = CxTYPE(cxstack + cxix) == CXt_EVAL;
+ } else {
+ cxix = Perl_cxinc(aTHX);
+ }
+ /* The last popped context will be reused by call_sv(), but our callers may
+ * still need its previous value. Back it up so that it isn't clobbered. */
+ saved_cx = cxstack[cxix];
+
+ ret = call_sv(sv, flags | G_EVAL);
+
+ cxstack[cxix] = saved_cx;
+
+ if (SvTRUE(ERRSV)) {
+ if (old_err) {
+ sv_setsv(old_err, ERRSV);
+ SvREFCNT_dec(ERRSV);
+ ERRSV = old_err;
+ }
+ if (IN_PERL_COMPILETIME) {
+ if (!PL_in_eval) {
+ if (PL_errors)
+ sv_catsv(PL_errors, ERRSV);
+ else
+ Perl_warn(aTHX_ "%s", SvPV_nolen(ERRSV));
+ SvCUR_set(ERRSV, 0);
+ }
+#if VMG_HAS_PERL(5, 10, 0) || defined(PL_parser)
+ if (PL_parser)
+ ++PL_parser->error_count;
+#elif defined(PL_error_count)
+ ++PL_error_count;
+#else
+ ++PL_Ierror_count;
+#endif
+ } else if (!in_eval) {
+ if (!cleanup || cleanup(aTHX_ ud))
+ croak(NULL);
+ }
+ } else {
+ if (old_err) {
+ SvREFCNT_dec(ERRSV);
+ ERRSV = old_err;
+ }
+ }
+
+ return ret;
+}