# define SvMAGIC_set(sv, val) (SvMAGIC(sv) = (val))
#endif
-#ifndef mPUSHu
-# define mPUSHu(U) PUSHs(sv_2mortal(newSVuv(U)))
+#ifndef SvRV_const
+# define SvRV_const(sv) SvRV((SV *) sv)
+#endif
+
+#ifndef SvREFCNT_inc_simple_void
+# define SvREFCNT_inc_simple_void(sv) SvREFCNT_inc(sv)
#endif
-#ifndef SvPV_const
-# define SvPV_const SvPV
+#ifndef mPUSHu
+# define mPUSHu(U) PUSHs(sv_2mortal(newSVuv(U)))
#endif
#ifndef PERL_MAGIC_ext
typedef struct {
MGVTBL *vtbl;
- U8 uvar;
U8 opinfo;
+ U8 uvar;
SV *cb_data;
SV *cb_get, *cb_set, *cb_len, *cb_clear, *cb_free;
#if VMG_THREADSAFE
#define VMG_CLONE_CB(N) \
- z->cb_ ## N = (w->cb_ ## N) ? newRV_noinc(vmg_clone(SvRV(w->cb_ ## N), \
- w->owner)) \
+ z->cb_ ## N = (w->cb_ ## N) ? vmg_clone(w->cb_ ## N, w->owner) \
: NULL;
STATIC MGWIZ *vmg_mgwiz_clone(pTHX_ const MGWIZ *w) {
ptable_store(ud->wizards, ent->key, w);
}
-STATIC void vmg_thread_cleanup(pTHX_ void *);
-
-STATIC void vmg_thread_cleanup(pTHX_ void *ud) {
- int *level = ud;
-
- if (*level) {
- --*level;
- LEAVE;
- SAVEDESTRUCTOR_X(vmg_thread_cleanup, level);
- ENTER;
- } else {
- dMY_CXT;
- PerlMemShared_free(level);
- ptable_free(MY_CXT.wizards);
- }
-}
#endif /* VMG_THREADSAFE */
/* --- Wizard objects ------------------------------------------------------ */
STATIC const SV *vmg_wizard_validate(pTHX_ const SV *wiz) {
#define vmg_wizard_validate(W) vmg_wizard_validate(aTHX_ (W))
if (SvROK(wiz)) {
- wiz = SvRV(wiz);
+ wiz = SvRV_const(wiz);
if (SvIOK(wiz))
return wiz;
}
croak(vmg_invalid_wiz);
+ /* Not reached */
+ return NULL;
}
#define vmg_wizard_id(W) SvIVX((const SV *) (W))
STATIC const MAGIC *vmg_find(const SV *sv, const SV *wiz) {
const MAGIC *mg, *moremagic;
- UV wid;
+ IV wid;
if (SvTYPE(sv) < SVt_PVMG)
return NULL;
for (mg = SvMAGIC(sv); mg; mg = moremagic) {
moremagic = mg->mg_moremagic;
if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) {
- UV zid = vmg_wizard_id(mg->mg_ptr);
+ IV zid = vmg_wizard_id(mg->mg_ptr);
if (zid == wid)
return mg;
}
/* ... Construct private data .............................................. */
-STATIC SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, AV *args) {
-#define vmg_data_new(C, S, A) vmg_data_new(aTHX_ (C), (S), (A))
+STATIC SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, SV **args, I32 items) {
+#define vmg_data_new(C, S, A, I) vmg_data_new(aTHX_ (C), (S), (A), (I))
+ I32 i;
SV *nsv;
- I32 i, alen = (args == NULL) ? 0 : av_len(args);
dSP;
SAVETMPS;
PUSHMARK(SP);
- EXTEND(SP, alen + 1);
+ EXTEND(SP, items + 1);
PUSHs(sv_2mortal(newRV_inc(sv)));
- for (i = 0; i < alen; ++i)
- PUSHs(*av_fetch(args, i, 0));
+ for (i = 0; i < items; ++i)
+ PUSHs(args[i]);
PUTBACK;
call_sv(ctor, G_SCALAR);
SPAGAIN;
nsv = POPs;
#if VMG_HAS_PERL(5, 8, 3)
- SvREFCNT_inc(nsv); /* Or it will be destroyed in FREETMPS */
+ SvREFCNT_inc_simple_void(nsv); /* Or it will be destroyed in FREETMPS */
#else
- nsv = sv_newref(nsv); /* Workaround some bug in SvREFCNT_inc() */
+ nsv = sv_newref(nsv); /* Workaround some bug in SvREFCNT_inc() */
#endif
PUTBACK;
}
#endif /* VMG_UVAR */
-STATIC UV vmg_cast(pTHX_ SV *sv, const SV *wiz, AV *args) {
-#define vmg_cast(S, W, A) vmg_cast(aTHX_ (S), (W), (A))
+STATIC UV vmg_cast(pTHX_ SV *sv, const SV *wiz, SV **args, I32 items) {
+#define vmg_cast(S, W, A, I) vmg_cast(aTHX_ (S), (W), (A), (I))
MAGIC *mg, *moremagic = NULL;
SV *data;
const MGWIZ *w;
w = vmg_wizard_mgwiz(wiz);
oldgmg = SvGMAGICAL(sv);
- data = (w->cb_data) ? vmg_data_new(w->cb_data, sv, args) : NULL;
+ data = (w->cb_data) ? vmg_data_new(w->cb_data, sv, args, items) : NULL;
mg = sv_magicext(sv, data, PERL_MAGIC_ext, w->vtbl, (const char *) wiz, HEf_SVKEY);
+ SvREFCNT_dec(data);
mg->mg_private = SIG_WIZ;
#if MGf_COPY
if (w->cb_copy)
U32 uvars = 0;
#endif /* VMG_UVAR */
MAGIC *mg, *prevmagic, *moremagic = NULL;
- UV wid = vmg_wizard_id(wiz);
+ IV wid = vmg_wizard_id(wiz);
if (SvTYPE(sv) < SVt_PVMG)
return 0;
moremagic = mg->mg_moremagic;
if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) {
const MGWIZ *z = vmg_wizard_mgwiz(mg->mg_ptr);
- UV zid = vmg_wizard_id(mg->mg_ptr);
+ IV zid = vmg_wizard_id(mg->mg_ptr);
if (zid == wid) {
#if VMG_UVAR
/* If the current has no uvar, short-circuit uvar deletion. */
if (!MY_CXT.b__op_stashes[0]) {
opclass c;
require_pv("B.pm");
- for (c = 0; c < OPc_MAX; ++c)
+ for (c = OPc_NULL; c < OPc_MAX; ++c)
MY_CXT.b__op_stashes[c] = gv_stashpv(vmg_opclassnames[c], 1);
}
break;
/* ... svt callbacks ....................................................... */
-#define VMG_CB_CALL_SET_RET(D) \
- { \
- SV *svr; \
- SPAGAIN; \
- svr = POPs; \
- ret = SvOK(svr) ? SvIV(svr) : (D); \
- PUTBACK; \
- }
-
#define VMG_CB_CALL_ARGS_MASK 15
#define VMG_CB_CALL_ARGS_SHIFT 4
#define VMG_CB_CALL_OPINFO (VMG_OP_INFO_NAME|VMG_OP_INFO_OBJECT)
STATIC int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) {
va_list ap;
- int ret;
+ int ret = 0;
unsigned int i, args, opinfo;
+ SV *svr;
dSP;
call_sv(cb, G_SCALAR);
- VMG_CB_CALL_SET_RET(0);
+ SPAGAIN;
+ svr = POPs;
+ if (SvOK(svr))
+ ret = (int) SvIV(svr);
+ PUTBACK;
FREETMPS;
LEAVE;
return ret;
}
-#define vmg_cb_call1(I, F, S, A1) \
- vmg_cb_call(aTHX_ (I), (((F) << VMG_CB_CALL_ARGS_SHIFT) | 1), (S), (A1))
-#define vmg_cb_call2(I, F, S, A1, A2) \
- vmg_cb_call(aTHX_ (I), (((F) << VMG_CB_CALL_ARGS_SHIFT) | 2), (S), (A1), (A2))
-#define vmg_cb_call3(I, F, S, A1, A2, A3) \
- vmg_cb_call(aTHX_ (I), (((F) << VMG_CB_CALL_ARGS_SHIFT) | 3), (S), (A1), (A2), (A3))
+#define VMG_CB_FLAGS(OI, A) \
+ ((((unsigned int) (OI)) << VMG_CB_CALL_ARGS_SHIFT) | (A))
+
+#define vmg_cb_call1(I, OI, S, A1) \
+ vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 1), (S), (A1))
+#define vmg_cb_call2(I, OI, S, A1, A2) \
+ vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 2), (S), (A1), (A2))
+#define vmg_cb_call3(I, OI, S, A1, A2, A3) \
+ vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 3), (S), (A1), (A2), (A3))
STATIC int vmg_svt_get(pTHX_ SV *sv, MAGIC *mg) {
const MGWIZ *w = vmg_wizard_mgwiz(mg->mg_ptr);
const MGWIZ *w = vmg_wizard_mgwiz(mg->mg_ptr);
unsigned int opinfo = w->opinfo;
U32 len, ret;
+ SV *svr;
svtype t = SvTYPE(sv);
dSP;
PUSHs(mg->mg_obj ? mg->mg_obj : &PL_sv_undef);
if (t < SVt_PVAV) {
STRLEN l;
- const U8 *s = (const U8 *) SvPV_const(sv, l);
+#if VMG_HAS_PERL(5, 9, 3)
+ const U8 *s = SvPV_const(sv, l);
+#else
+ U8 *s = SvPV(sv, l);
+#endif
if (DO_UTF8(sv))
len = utf8_length(s, s + l);
else
call_sv(w->cb_len, G_SCALAR);
- VMG_CB_CALL_SET_RET(len);
+ SPAGAIN;
+ svr = POPs;
+ ret = SvOK(svr) ? (U32) SvUV(svr) : len;
+ if (t == SVt_PVAV)
+ --ret;
+ PUTBACK;
FREETMPS;
LEAVE;
- return t == SVt_PVAV ? ret - 1 : ret;
+ return ret;
}
STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) {
PERL_CONTEXT saved_cx;
I32 cxix;
#endif
- unsigned int had_err, has_err, flags = G_SCALAR | G_EVAL;
+ I32 had_err, has_err, flags = G_SCALAR | G_EVAL;
int ret = 0;
+ SV *svr;
dSP;
w = vmg_wizard_mgwiz(mg->mg_ptr);
/* So that it survives the temp cleanup below */
- SvREFCNT_inc(sv);
+ SvREFCNT_inc_simple_void(sv);
#if !VMG_HAS_PERL_MAINT(5, 11, 0, 32686)
/* The previous magic tokens were freed but the magic chain wasn't updated, so
#endif
has_err = SvTRUE(ERRSV);
- if (IN_PERL_COMPILETIME && !had_err && has_err)
- ++PL_error_count;
+ if (IN_PERL_COMPILETIME && !had_err && has_err) {
+ if (PL_errors)
+ sv_catsv(PL_errors, ERRSV);
+ else
+ Perl_warn(aTHX_ "%s", SvPV_nolen(ERRSV));
+#ifdef PL_parser
+ if (PL_parser)
+#endif
+ ++PL_error_count;
+ }
- VMG_CB_CALL_SET_RET(0);
+ SPAGAIN;
+ svr = POPs;
+ if (SvOK(svr))
+ ret = (int) SvIV(svr);
+ PUTBACK;
FREETMPS;
LEAVE;
#define VMG_SET_CB(S, N) \
cb = (S); \
- w->cb_ ## N = (SvOK(cb) && SvROK(cb)) ? newRV_inc(SvRV(cb)) : NULL;
+ w->cb_ ## N = (SvOK(cb) && SvROK(cb)) ? SvREFCNT_inc(SvRV(cb)) : NULL;
#define VMG_SET_SVT_CB(S, N) \
cb = (S); \
if (SvOK(cb) && SvROK(cb)) { \
t->svt_ ## N = vmg_svt_ ## N; \
- w->cb_ ## N = newRV_inc(SvRV(cb)); \
+ w->cb_ ## N = SvREFCNT_inc(SvRV(cb)); \
} else { \
t->svt_ ## N = NULL; \
w->cb_ ## N = NULL; \
}
+#if VMG_THREADSAFE
+
+STATIC void vmg_cleanup(pTHX_ void *ud) {
+ dMY_CXT;
+
+ ptable_free(MY_CXT.wizards);
+ MY_CXT.wizards = NULL;
+}
+
+#endif /* VMG_THREADSAFE */
+
/* --- XS ------------------------------------------------------------------ */
MODULE = Variable::Magic PACKAGE = Variable::Magic
MY_CXT.b__op_stashes[0] = NULL;
#if VMG_THREADSAFE
MUTEX_INIT(&vmg_op_name_init_mutex);
+ call_atexit(vmg_cleanup, NULL);
#endif
stash = gv_stashpv(__PACKAGE__, 1);
ud.owner = MY_CXT.owner;
ptable_walk(MY_CXT.wizards, vmg_ptable_clone, &ud);
- for (c = 0; c < OPc_MAX; ++c) {
+ for (c = OPc_NULL; c < OPc_MAX; ++c) {
if (MY_CXT.b__op_stashes[c])
had_b__op_stash |= (((U32) 1) << c);
}
MY_CXT_CLONE;
MY_CXT.wizards = t;
MY_CXT.owner = aTHX;
- for (c = 0; c < OPc_MAX; ++c) {
+ for (c = OPc_NULL; c < OPc_MAX; ++c) {
MY_CXT.b__op_stashes[c] = (had_b__op_stash & (((U32) 1) << c))
? gv_stashpv(vmg_opclassnames[c], 1) : NULL;
}
}
- {
- int *level;
- level = PerlMemShared_malloc(sizeof *level);
- *level = 1;
- LEAVE;
- SAVEDESTRUCTOR_X(vmg_thread_cleanup, level);
- ENTER;
- }
XSRETURN(0);
#endif /* VMG_THREADSAFE */
PROTOTYPE: DISABLE
PREINIT:
I32 i = 0;
+ UV opinfo;
MGWIZ *w;
MGVTBL *t;
SV *cb;
Newx(w, 1, MGWIZ);
VMG_SET_CB(ST(i++), data);
+
cb = ST(i++);
- w->opinfo = SvOK(cb) ? SvUV(cb) : 0;
+ 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);
SV *cast(SV *sv, SV *wiz, ...)
PROTOTYPE: \[$@%&*]$@
PREINIT:
- AV *args = NULL;
- SV *ret;
+ SV **args = NULL;
+ I32 i = 0;
CODE:
if (items > 2) {
- I32 i;
- args = newAV();
- av_fill(args, items - 2);
- for (i = 2; i < items; ++i) {
- SV *arg = ST(i);
- SvREFCNT_inc(arg);
- if (av_store(args, i - 2, arg) == NULL) croak(vmg_argstorefailed);
- }
+ i = items - 2;
+ args = &ST(2);
}
- ret = newSVuv(vmg_cast(SvRV(sv), vmg_wizard_validate(wiz), args));
- SvREFCNT_dec(args);
- RETVAL = ret;
+ RETVAL = newSVuv(vmg_cast(SvRV(sv), vmg_wizard_validate(wiz), args, i));
OUTPUT:
RETVAL