# define MY_CXT_CLONE NOOP
#endif
+#if VMG_THREADSAFE
+# define VMG_LOCK(M) MUTEX_LOCK(M)
+# define VMG_UNLOCK(M) MUTEX_UNLOCK(M)
+#else
+# define VMG_LOCK(M)
+# define VMG_UNLOCK(M)
+#endif
+
#if VMG_THREADSAFE
STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) {
#endif
#ifndef SvREFCNT_inc_simple_void
-# define SvREFCNT_inc_simple_void(sv) SvREFCNT_inc(sv)
+# define SvREFCNT_inc_simple_void(sv) ((void) SvREFCNT_inc(sv))
#endif
#ifndef mPUSHu
# define PERL_MAGIC_tied 'P'
#endif
-#ifndef MGf_COPY
-# define MGf_COPY 0
-#endif
-
-#ifndef MGf_DUP
-# define MGf_DUP 0
-#endif
-
#ifndef MGf_LOCAL
# define MGf_LOCAL 0
#endif
#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;
SV *cb_data;
SV *cb_get, *cb_set, *cb_len, *cb_clear, *cb_free;
-#if MGf_COPY
SV *cb_copy;
-#endif /* MGf_COPY */
-#if MGf_DUP
SV *cb_dup;
-#endif /* MGf_DUP */
#if MGf_LOCAL
SV *cb_local;
#endif /* MGf_LOCAL */
#endif /* VMG_MULTIPLICITY */
} MGWIZ;
+STATIC void vmg_op_info_init(pTHX_ unsigned int opinfo);
+
+STATIC MGWIZ *vmg_mgwiz_alloc(pTHX_ UV opinfo) {
+#define vmg_mgwiz_alloc(O) vmg_mgwiz_alloc(aTHX_ (O))
+ MGWIZ *w;
+ MGVTBL *t;
+
+ Newx(w, 1, MGWIZ);
+
+ w->uvar = 0;
+ w->opinfo = (U8) ((opinfo < 255) ? opinfo : 255);
+ if (w->opinfo)
+ vmg_op_info_init(aTHX_ w->opinfo);
+
+ w->vtable = vmg_vtable_alloc();
+
+ return w;
+}
+
STATIC void vmg_mgwiz_free(pTHX_ MGWIZ *w) {
#define vmg_mgwiz_free(W) vmg_mgwiz_free(aTHX_ (W))
if (!w)
SvREFCNT_dec(w->cb_len);
SvREFCNT_dec(w->cb_clear);
SvREFCNT_dec(w->cb_free);
-#if MGf_COPY
SvREFCNT_dec(w->cb_copy);
-#endif /* MGf_COPY */
-#if 0 /* MGf_DUP */
+#if 0
SvREFCNT_dec(w->cb_dup);
-#endif /* MGf_DUP */
+#endif
#if MGf_LOCAL
SvREFCNT_dec(w->cb_local);
#endif /* MGf_LOCAL */
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;
VMG_CLONE_CB(len);
VMG_CLONE_CB(clear);
VMG_CLONE_CB(free);
-#if MGf_COPY
VMG_CLONE_CB(copy);
-#endif /* MGf_COPY */
-#if MGf_DUP
VMG_CLONE_CB(dup);
-#endif /* MGf_DUP */
#if MGf_LOCAL
VMG_CLONE_CB(local);
#endif /* MGf_LOCAL */
NULL, /* len */
NULL, /* clear */
vmg_wizard_free, /* free */
-#if MGf_COPY
NULL, /* copy */
-#endif /* MGf_COPY */
-#if MGf_DUP
NULL, /* dup */
-#endif /* MGf_DUP */
#if MGf_LOCAL
NULL, /* local */
#endif /* MGf_LOCAL */
#define vmg_data_get(S, W) vmg_data_get(aTHX_ (S), (W))
const MAGIC *mg = vmg_find(sv, wiz);
return mg ? mg->mg_obj : NULL;
-}
+}
/* ... Magic cast/dispell .................................................. */
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;
-#if MGf_COPY
if (w->cb_copy)
mg->mg_flags |= MGf_COPY;
-#endif /* MGf_COPY */
-#if 0 /* MGf_DUP */
+#if 0
if (w->cb_dup)
mg->mg_flags |= MGf_DUP;
-#endif /* MGf_DUP */
+#endif
#if MGf_LOCAL
if (w->cb_local)
mg->mg_flags |= MGf_LOCAL;
#define vmg_op_info_init(W) vmg_op_info_init(aTHX_ (W))
switch (opinfo) {
case VMG_OP_INFO_NAME:
-#if VMG_THREADSAFE
- MUTEX_LOCK(&vmg_op_name_init_mutex);
-#endif
+ VMG_LOCK(&vmg_op_name_init_mutex);
if (!vmg_op_name_init) {
OPCODE t;
for (t = 0; t < OP_max; ++t)
vmg_op_name_len[t] = strlen(PL_op_name[t]);
vmg_op_name_init = 1;
}
-#if VMG_THREADSAFE
- MUTEX_UNLOCK(&vmg_op_name_init_mutex);
-#endif
+ VMG_UNLOCK(&vmg_op_name_init_mutex);
break;
case VMG_OP_INFO_OBJECT: {
dMY_CXT;
return ret;
}
-#if MGf_COPY
STATIC int vmg_svt_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *key,
# if VMG_HAS_PERL_MAINT(5, 11, 0, 33256) || VMG_HAS_PERL(5, 12, 0)
I32 keylen
return ret;
}
-#endif /* MGf_COPY */
-#if 0 /* MGf_DUP */
+#if 0
STATIC int vmg_svt_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param) {
return 0;
}
-#endif /* MGf_DUP */
+#endif
#if MGf_LOCAL
STATIC int vmg_svt_local(pTHX_ SV *nsv, MAGIC *mg) {
#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
PROTOTYPE: DISABLE
PREINIT:
I32 i = 0;
- UV opinfo;
MGWIZ *w;
MGVTBL *t;
- SV *cb;
+ SV *cb, *op_info, *copy_key;
CODE:
dMY_CXT;
- if (items != 7
-#if MGf_COPY
- + 1
-#endif /* MGf_COPY */
-#if MGf_DUP
- + 1
-#endif /* MGf_DUP */
+ if (items != 9
#if MGf_LOCAL
+ 1
#endif /* MGf_LOCAL */
#endif /* VMG_UVAR */
) { croak(vmg_wrongargnum); }
- Newx(t, 1, MGVTBL);
- Newx(w, 1, MGWIZ);
+ op_info = ST(i++);
+ w = vmg_mgwiz_alloc(SvOK(op_info) ? SvUV(op_info) : 0);
+ t = vmg_vtable_vtbl(w->vtable);
VMG_SET_CB(ST(i++), data);
- cb = ST(i++);
- opinfo = SvOK(cb) ? SvUV(cb) : 0;
- w->opinfo = (U8) ((opinfo < 255) ? opinfo : 255);
- if (w->opinfo)
- vmg_op_info_init(w->opinfo);
-
VMG_SET_SVT_CB(ST(i++), get);
VMG_SET_SVT_CB(ST(i++), set);
VMG_SET_SVT_CB(ST(i++), len);
VMG_SET_SVT_CB(ST(i++), clear);
VMG_SET_SVT_CB(ST(i++), free);
-#if MGf_COPY
VMG_SET_SVT_CB(ST(i++), copy);
-#endif /* MGf_COPY */
-#if MGf_DUP
/* VMG_SET_SVT_CB(ST(i++), dup); */
i++;
t->svt_dup = NULL;
w->cb_dup = NULL;
-#endif /* MGf_DUP */
#if MGf_LOCAL
VMG_SET_SVT_CB(ST(i++), local);
#endif /* MGf_LOCAL */
VMG_SET_CB(ST(i++), store);
VMG_SET_CB(ST(i++), exists);
VMG_SET_CB(ST(i++), delete);
- cb = ST(i++);
+
+ copy_key = ST(i++);
if (w->cb_fetch || w->cb_store || w->cb_exists || w->cb_delete)
- w->uvar = SvTRUE(cb) ? 2 : 1;
- else
- w->uvar = 0;
+ w->uvar = SvTRUE(copy_key) ? 2 : 1;
#endif /* VMG_UVAR */
#if VMG_MULTIPLICITY
w->owner = aTHX;
#endif /* VMG_MULTIPLICITY */
- w->vtbl = t;
#if VMG_THREADSAFE
ptable_store(MY_CXT.wizards, w, w);
#endif /* VMG_THREADSAFE */