# define SvREFCNT_inc_simple_void(sv) SvREFCNT_inc(sv)
#endif
+#ifndef GvCV_set
+# define GvCV_set(G, C) (GvCV(G) = (C))
+#endif
+
#ifndef HvNAME_get
# define HvNAME_get(H) HvNAME(H)
#endif
#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
typedef struct {
- char *stack_placeholder;
- I32 cxix;
- I32 items;
- SV **savesp;
- OP fakeop;
+ char *stack_placeholder;
+ I32 cxix;
+ I32 items;
+ SV **savesp;
+ LISTOP return_op;
+ OP proxy_op;
} my_cxt_t;
START_MY_CXT
# define SU_SAVE_HELEM_OR_HDELETE_SIZE SU_SAVE_HELEM_SIZE
#endif
-#define SU_SAVE_SPTR_SIZE 3
+#define SU_SAVE_GVCV_SIZE SU_SAVE_DESTRUCTOR_SIZE
#if !SU_HAS_PERL(5, 8, 9)
# define SU_SAVE_GP_SIZE 6
#elif !SU_HAS_PERL(5, 13, 0) || (SU_RELEASE && SU_HAS_PERL_EXACT(5, 13, 0))
# define SU_SAVE_GP_SIZE 3
-#else
+#elif !SU_HAS_PERL(5, 13, 8)
# define SU_SAVE_GP_SIZE 4
+#else
+# define SU_SAVE_GP_SIZE 3
#endif
#ifndef SvCANEXISTDELETE
}
}
+/* ... Saving code slots from a glob ....................................... */
+
+#if !SU_HAS_PERL(5, 10, 0) && !defined(mro_method_changed_in)
+# define mro_method_changed_in(G) PL_sub_generation++
+#endif
+
+typedef struct {
+ GV *gv;
+ CV *old_cv;
+} su_save_gvcv_ud;
+
+STATIC void su_restore_gvcv(pTHX_ void *ud_) {
+ su_save_gvcv_ud *ud = ud_;
+ GV *gv = ud->gv;
+
+ GvCV_set(gv, ud->old_cv);
+ GvCVGEN(gv) = 0;
+ mro_method_changed_in(GvSTASH(gv));
+
+ Safefree(ud);
+}
+
+STATIC void su_save_gvcv(pTHX_ GV *gv) {
+#define su_save_gvcv(G) su_save_gvcv(aTHX_ (G))
+ su_save_gvcv_ud *ud;
+
+ Newx(ud, 1, su_save_gvcv_ud);
+ ud->gv = gv;
+ ud->old_cv = GvCV(gv);
+
+ GvCV_set(gv, NULL);
+ GvCVGEN(gv) = 0;
+ mro_method_changed_in(GvSTASH(gv));
+
+ SAVEDESTRUCTOR_X(su_restore_gvcv, ud);
+}
+
/* --- Actions ------------------------------------------------------------- */
typedef struct {
deref = 0;
break;
case SVt_PVCV:
- size = SU_SAVE_SPTR_SIZE;
+ size = SU_SAVE_GVCV_SIZE;
deref = 0;
break;
default:
save_gp(gv, 1); /* hide previous entry in symtab */
break;
case SVt_PVCV:
- SAVESPTR(GvCV(gv));
- GvCV(gv) = NULL;
+ su_save_gvcv(gv);
break;
default:
gv = (GV *) save_scalar(gv);
items, PL_stack_sp - PL_stack_base, *PL_markstack_ptr, mark);
});
- PL_op = PL_ppaddr[OP_RETURN](aTHX);
+ PL_op = (OP *) &(MY_CXT.return_op);
+ PL_op = PL_op->op_ppaddr(aTHX);
+
*PL_markstack_ptr = mark;
- MY_CXT.fakeop.op_next = PL_op;
- PL_op = &(MY_CXT.fakeop);
+ MY_CXT.proxy_op.op_next = PL_op;
+ PL_op = &(MY_CXT.proxy_op);
}
/* --- XS ------------------------------------------------------------------ */
HV *stash;
MY_CXT_INIT;
+
MY_CXT.stack_placeholder = NULL;
+ /* NewOp() calls calloc() which just zeroes the memory with memset(). */
+ Zero(&(MY_CXT.return_op), 1, sizeof(MY_CXT.return_op));
+ MY_CXT.return_op.op_type = OP_RETURN;
+ MY_CXT.return_op.op_ppaddr = PL_ppaddr[OP_RETURN];
+
+ Zero(&(MY_CXT.proxy_op), 1, sizeof(MY_CXT.proxy_op));
+ MY_CXT.proxy_op.op_type = OP_STUB;
+ MY_CXT.proxy_op.op_ppaddr = NULL;
+
stash = gv_stashpv(__PACKAGE__, 1);
newCONSTSUB(stash, "TOP", newSViv(0));
newCONSTSUB(stash, "SU_THREADSAFE", newSVuv(SU_THREADSAFE));