#define SIG_WZO ((U16) (0x3891))
#define SIG_WIZ ((U16) (0x3892))
-/* --- MGWIZ structure ----------------------------------------------------- */
+/* --- <vmg_vtable> structure ---------------------------------------------- */
+
+#if VMG_THREADSAFE
typedef struct {
MGVTBL *vtbl;
+ U32 refcount;
+} vmg_vtable;
+
+STATIC vmg_vtable *vmg_vtable_alloc(pTHX) {
+#define vmg_vtable_alloc() vmg_vtable_alloc(aTHX)
+ vmg_vtable *t;
+
+ t = VOID2(vmg_vtable *, PerlMemShared_malloc(sizeof *t));
+
+ t->vtbl = VOID2(MGVTBL *, PerlMemShared_malloc(sizeof *t->vtbl));
+ t->refcount = 1;
+
+ return t;
+}
+
+#define vmg_vtable_vtbl(T) (T)->vtbl
+
+#if VMG_THREADSAFE
+STATIC perl_mutex vmg_vtable_refcount_mutex;
+#endif
+
+STATIC vmg_vtable *vmg_vtable_dup(pTHX_ vmg_vtable *t) {
+#define vmg_vtable_dup(T) vmg_vtable_dup(aTHX_ (T))
+ VMG_LOCK(&vmg_vtable_refcount_mutex);
+ ++t->refcount;
+ VMG_UNLOCK(&vmg_vtable_refcount_mutex);
+
+ return t;
+}
+
+STATIC void vmg_vtable_free(pTHX_ vmg_vtable *t) {
+#define vmg_vtable_free(T) vmg_vtable_free(aTHX_ (T))
+ U32 refcount;
+
+ VMG_LOCK(&vmg_vtable_refcount_mutex);
+ refcount = --t->refcount;
+ VMG_UNLOCK(&vmg_vtable_refcount_mutex);
+
+ if (!refcount) {
+ PerlMemShared_free(t->vtbl);
+ PerlMemShared_free(t);
+ }
+}
+
+#else /* VMG_THREADSAFE */
+
+typedef MGVTBL vmg_vtable;
+
+STATIC vmg_vtable *vmg_vtable_alloc(pTHX) {
+#define vmg_vtable_alloc() vmg_vtable_alloc(aTHX)
+ vmg_vtable *t;
+
+ Newx(t, 1, vmg_vtable);
+
+ return t;
+}
+
+#define vmg_vtable_vtbl(T) ((MGVTBL *) (T))
+
+#define vmg_vtable_free(T) Safefree(T)
+
+#endif /* !VMG_THREADSAFE */
+
+/* --- MGWIZ structure ----------------------------------------------------- */
+
+typedef struct {
+ vmg_vtable *vtable;
U8 opinfo;
U8 uvar;
if (w->opinfo)
vmg_op_info_init(aTHX_ w->opinfo);
- Newx(t, 1, MGVTBL);
- w->vtbl = t;
+ w->vtable = vmg_vtable_alloc();
return w;
}
SvREFCNT_dec(w->cb_delete);
#endif /* VMG_UVAR */
- Safefree(w->vtbl);
+ vmg_vtable_free(w->vtable);
Safefree(w);
return;
STATIC MGWIZ *vmg_mgwiz_clone(pTHX_ const MGWIZ *w) {
#define vmg_mgwiz_clone(W) vmg_mgwiz_clone(aTHX_ (W))
- MGVTBL *t;
MGWIZ *z;
if (!w)
return NULL;
- Newx(t, 1, MGVTBL);
- Copy(w->vtbl, t, 1, MGVTBL);
-
Newx(z, 1, MGWIZ);
- z->vtbl = t;
+ z->vtable = vmg_vtable_dup(w->vtable);
z->uvar = w->uvar;
z->opinfo = w->opinfo;
data = (w->cb_data) ? vmg_data_new(w->cb_data, sv, args, items) : NULL;
/* sv_magicext() calls mg_magical and increments data's refcount */
- mg = sv_magicext(sv, data, PERL_MAGIC_ext, w->vtbl,
+ mg = sv_magicext(sv, data, PERL_MAGIC_ext, vmg_vtable_vtbl(w->vtable),
(const char *) wiz, HEf_SVKEY);
SvREFCNT_dec(data);
mg->mg_private = SIG_WIZ;
#endif
MY_CXT.b__op_stashes[0] = NULL;
#if VMG_THREADSAFE
+ MUTEX_INIT(&vmg_vtable_refcount_mutex);
MUTEX_INIT(&vmg_op_name_init_mutex);
call_atexit(vmg_cleanup, NULL);
#endif
op_info = ST(i++);
w = vmg_mgwiz_alloc(SvOK(op_info) ? SvUV(op_info) : 0);
- t = w->vtbl;
+ t = vmg_vtable_vtbl(w->vtable);
VMG_SET_CB(ST(i++), data);