X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Magic.xs;h=afb7713c62a12504ae16fc13737905367938dd93;hb=dee682e232db910b1e38e162ac51b0d98725e40e;hp=fa09ec197eaaf5f4adda03367ff45c0bc47582c8;hpb=de17a4857e738f4474bea721e6064f1b52273f6d;p=perl%2Fmodules%2FVariable-Magic.git diff --git a/Magic.xs b/Magic.xs index fa09ec1..afb7713 100644 --- a/Magic.xs +++ b/Magic.xs @@ -12,6 +12,13 @@ #define __PACKAGE__ "Variable::Magic" +#undef VOID2 +#ifdef __cplusplus +# define VOID2(T, P) static_cast(P) +#else +# define VOID2(T, P) (P) +#endif + #ifndef VMG_PERL_PATCHLEVEL # ifdef PERL_PATCHNUM # define VMG_PERL_PATCHLEVEL PERL_PATCHNUM @@ -79,13 +86,25 @@ STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) { #define vmg_clone(P, O) vmg_clone(aTHX_ (P), (O)) + SV *dupsv; + +#if VMG_HAS_PERL(5, 13, 2) + CLONE_PARAMS *param = Perl_clone_params_new(owner, aTHX); + + dupsv = sv_dup(sv, param); + + Perl_clone_params_del(param); +#else CLONE_PARAMS param; param.stashes = NULL; /* don't need it unless sv is a PVHV */ param.flags = 0; param.proto_perl = owner; - return SvREFCNT_inc(sv_dup(sv, ¶m)); + dupsv = sv_dup(sv, ¶m); +#endif + + return SvREFCNT_inc(dupsv); } #endif /* VMG_THREADSAFE */ @@ -105,7 +124,7 @@ 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 @@ -136,18 +155,8 @@ STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) { # define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling) #endif -#if VMG_HAS_PERL(5, 10, 0) || defined(PL_parser) -# ifndef PL_error_count -# define PL_error_count PL_parser->error_count -# endif -#else -# ifndef PL_error_count -# define PL_error_count PL_Ierror_count -# endif -#endif - -/* uvar magic and Hash::Util::FieldHash were commited with 28419, but only - * enable it on 5.10 */ +/* uvar magic and Hash::Util::FieldHash were commited with 28419, but we only + * enable them on 5.10 */ #if VMG_HAS_PERL(5, 10, 0) # define VMG_UVAR 1 #else @@ -158,9 +167,11 @@ STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) { * reverted to dev-5.11 as 9cdcb38b */ #if VMG_HAS_PERL_MAINT(5, 8, 9, 28160) || VMG_HAS_PERL_MAINT(5, 9, 3, 25854) || VMG_HAS_PERL(5, 10, 0) # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN -/* This branch should only apply for perls before the official 5.11.0 release. - * Makefile.PL takes care of the higher ones. */ -# define VMG_COMPAT_ARRAY_PUSH_NOLEN 1 +# if VMG_HAS_PERL(5, 11, 0) +# define VMG_COMPAT_ARRAY_PUSH_NOLEN 0 +# else +# define VMG_COMPAT_ARRAY_PUSH_NOLEN 1 +# endif # endif # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID # define VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID 1 @@ -175,7 +186,7 @@ STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) { #endif /* Applied to dev-5.11 as 34908 */ -#if VMG_HAS_PERL_MAINT(5, 11, 0, 34908) +#if VMG_HAS_PERL_MAINT(5, 11, 0, 34908) || VMG_HAS_PERL(5, 12, 0) # define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 1 #else # define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 0 @@ -188,35 +199,119 @@ STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) { # define VMG_COMPAT_ARRAY_UNDEF_CLEAR 0 #endif -#if VMG_HAS_PERL_MAINT(5, 11, 0, 32969) +#if VMG_HAS_PERL_MAINT(5, 11, 0, 32969) || VMG_HAS_PERL(5, 12, 0) # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 1 #else # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 0 #endif -#if VMG_UVAR +#if VMG_HAS_PERL(5, 13, 2) +# define VMG_COMPAT_GLOB_GET 1 +#else +# define VMG_COMPAT_GLOB_GET 0 +#endif + +/* ... Bug-free mg_magical ................................................. */ -/* Bug-free mg_magical - see http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2008-01/msg00036.html - but specialized to our needs. */ -STATIC void vmg_sv_magicuvar(pTHX_ SV *sv, const char *uf, I32 len) { -#define vmg_sv_magicuvar(S, U, L) vmg_sv_magicuvar(aTHX_ (S), (U), (L)) - const MAGIC* mg; - sv_magic(sv, NULL, PERL_MAGIC_uvar, uf, len); - /* uvar magic has set and get magic, hence this has set SVs_GMG and SVs_SMG. */ +/* See the discussion at http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2008-01/msg00036.html */ + +#if VMG_HAS_PERL(5, 11, 3) + +#define vmg_mg_magical(S) mg_magical(S) + +#else + +STATIC void vmg_mg_magical(SV *sv) { + const MAGIC *mg; + + SvMAGICAL_off(sv); if ((mg = SvMAGIC(sv))) { - SvRMAGICAL_off(sv); do { const MGVTBL* const vtbl = mg->mg_virtual; if (vtbl) { - if (vtbl->svt_clear) { + if (vtbl->svt_get && !(mg->mg_flags & MGf_GSKIP)) + SvGMAGICAL_on(sv); + if (vtbl->svt_set) + SvSMAGICAL_on(sv); + if (vtbl->svt_clear) SvRMAGICAL_on(sv); - break; - } } } while ((mg = mg->mg_moremagic)); + if (!(SvFLAGS(sv) & (SVs_GMG|SVs_SMG))) + SvRMAGICAL_on(sv); } } -#endif /* VMG_UVAR */ +#endif + +/* ... Safe version of call_sv() ........................................... */ + +#define VMG_SAVE_LAST_CX (!VMG_HAS_PERL(5, 8, 4) || VMG_HAS_PERL(5, 9, 5)) + +STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, I32 destructor) { +#define vmg_call_sv(S, F, D) vmg_call_sv(aTHX_ (S), (F), (D)) + I32 ret, cxix = 0, in_eval = 0; +#if VMG_SAVE_LAST_CX + PERL_CONTEXT saved_cx; +#endif + SV *old_err = NULL; + + if (SvTRUE(ERRSV)) { + old_err = ERRSV; + ERRSV = newSV(0); + } + + if (cxstack_ix < cxstack_max) { + cxix = cxstack_ix + 1; + if (destructor && CxTYPE(cxstack + cxix) == CXt_EVAL) + in_eval = 1; + } + +#if VMG_SAVE_LAST_CX + /* 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]; +#endif + + ret = call_sv(sv, flags | G_EVAL); + +#if VMG_SAVE_LAST_CX + cxstack[cxix] = saved_cx; +#endif + + 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) + croak(NULL); + } else { + if (old_err) { + SvREFCNT_dec(ERRSV); + ERRSV = old_err; + } + } + + return ret; +} /* --- Stolen chunk of B --------------------------------------------------- */ @@ -264,9 +359,11 @@ STATIC opclass vmg_opclass(const OP *o) { return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP); if (o->op_type == OP_AELEMFAST) { +#if PERL_VERSION <= 14 if (o->op_flags & OPf_SPECIAL) return OPc_BASEOP; else +#endif #ifdef USE_ITHREADS return OPc_PADOP; #else @@ -367,26 +464,35 @@ STATIC void vmg_mgwiz_free(pTHX_ MGWIZ *w) { if (!w) return; - if (w->cb_data) SvREFCNT_dec(w->cb_data); - if (w->cb_get) SvREFCNT_dec(w->cb_get); - if (w->cb_set) SvREFCNT_dec(w->cb_set); - if (w->cb_len) SvREFCNT_dec(w->cb_len); - if (w->cb_clear) SvREFCNT_dec(w->cb_clear); - if (w->cb_free) SvREFCNT_dec(w->cb_free); + /* We reach this point in dirty state when ptable_free() is called from the + * atexit cleanup callback, and that the global table still holds a live + * wizard. This happens before all the SV bodies are freed, so all the wizard + * callbacks are still alive (as they are referenced by the undead wizard). + * Hence it is safe to decrement their refcount. Later on, the wizard free + * callback itself will trigger when the wizard body is reaped, but it will + * be skipped as it guards against dirty state - which is good since nothing + * has to be done anymore at that point. */ + + SvREFCNT_dec(w->cb_data); + SvREFCNT_dec(w->cb_get); + SvREFCNT_dec(w->cb_set); + SvREFCNT_dec(w->cb_len); + SvREFCNT_dec(w->cb_clear); + SvREFCNT_dec(w->cb_free); #if MGf_COPY - if (w->cb_copy) SvREFCNT_dec(w->cb_copy); + SvREFCNT_dec(w->cb_copy); #endif /* MGf_COPY */ #if 0 /* MGf_DUP */ - if (w->cb_dup) SvREFCNT_dec(w->cb_dup); + SvREFCNT_dec(w->cb_dup); #endif /* MGf_DUP */ #if MGf_LOCAL - if (w->cb_local) SvREFCNT_dec(w->cb_local); + SvREFCNT_dec(w->cb_local); #endif /* MGf_LOCAL */ #if VMG_UVAR - if (w->cb_fetch) SvREFCNT_dec(w->cb_fetch); - if (w->cb_store) SvREFCNT_dec(w->cb_store); - if (w->cb_exists) SvREFCNT_dec(w->cb_exists); - if (w->cb_delete) SvREFCNT_dec(w->cb_delete); + SvREFCNT_dec(w->cb_fetch); + SvREFCNT_dec(w->cb_store); + SvREFCNT_dec(w->cb_exists); + SvREFCNT_dec(w->cb_delete); #endif /* VMG_UVAR */ Safefree(w->vtbl); @@ -452,7 +558,7 @@ STATIC MGWIZ *vmg_mgwiz_clone(pTHX_ const MGWIZ *w) { #if VMG_THREADSAFE #define PTABLE_NAME ptable -#define PTABLE_VAL_FREE(V) vmg_mgwiz_free(V) +#define PTABLE_VAL_FREE(V) vmg_mgwiz_free(VOID2(MGWIZ *, (V))) #define pPTBL pTHX #define pPTBL_ pTHX_ @@ -482,13 +588,13 @@ START_MY_CXT #if VMG_THREADSAFE STATIC void vmg_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) { - my_cxt_t *ud = ud_; + my_cxt_t *ud = VOID2(my_cxt_t *, ud_); MGWIZ *w; if (ud->owner == aTHX) return; - w = vmg_mgwiz_clone(ent->val); + w = vmg_mgwiz_clone(VOID2(MGWIZ *, ent->val)); if (w) ptable_store(ud->wizards, ent->key, w); } @@ -581,7 +687,7 @@ STATIC const MGWIZ *vmg_wizard_mgwiz(pTHX_ const SV *wiz) { { dMY_CXT; - return ptable_fetch(MY_CXT.wizards, w); + return VOID2(const MGWIZ *, ptable_fetch(MY_CXT.wizards, w)); } } @@ -632,7 +738,7 @@ STATIC SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, SV **args, I32 items) { PUSHs(args[i]); PUTBACK; - call_sv(ctor, G_SCALAR); + vmg_call_sv(ctor, G_SCALAR, 0); SPAGAIN; nsv = POPs; @@ -653,7 +759,7 @@ STATIC SV *vmg_data_get(pTHX_ SV *sv, const SV *wiz) { #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 .................................................. */ @@ -674,7 +780,7 @@ STATIC void vmg_uvar_del(SV *sv, MAGIC *prevmagic, MAGIC *mg, MAGIC *moremagic) 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; + MAGIC *mg; SV *data; const MGWIZ *w; U32 oldgmg; @@ -686,7 +792,9 @@ STATIC UV vmg_cast(pTHX_ SV *sv, const SV *wiz, SV **args, I32 items) { oldgmg = SvGMAGICAL(sv); 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); + /* sv_magicext() calls mg_magical and increments data's refcount */ + 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 @@ -716,7 +824,7 @@ STATIC UV vmg_cast(pTHX_ SV *sv, const SV *wiz, SV **args, I32 items) { #if VMG_UVAR if (w->uvar) { - MAGIC *prevmagic; + MAGIC *prevmagic, *moremagic = NULL; struct ufuncs uf[2]; uf[0].uf_val = vmg_svt_val; @@ -745,7 +853,8 @@ STATIC UV vmg_cast(pTHX_ SV *sv, const SV *wiz, SV **args, I32 items) { } } - vmg_sv_magicuvar(sv, (const char *) &uf, sizeof(uf)); + sv_magic(sv, NULL, PERL_MAGIC_uvar, (const char *) &uf, sizeof(uf)); + vmg_mg_magical(sv); /* Our hash now carries uvar magic. The uvar/clear shortcoming has to be * handled by our uvar callback. */ } @@ -769,7 +878,9 @@ STATIC UV vmg_dispell(pTHX_ SV *sv, const SV *wiz) { for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) { moremagic = mg->mg_moremagic; if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) { +#if VMG_UVAR const MGWIZ *z = vmg_wizard_mgwiz(mg->mg_ptr); +#endif /* VMG_UVAR */ IV zid = vmg_wizard_id(mg->mg_ptr); if (zid == wid) { #if VMG_UVAR @@ -840,6 +951,8 @@ STATIC UV vmg_dispell(pTHX_ SV *sv, const SV *wiz) { } #endif /* VMG_UVAR */ + vmg_mg_magical(sv); + return 1; } @@ -875,7 +988,7 @@ STATIC void vmg_op_info_init(pTHX_ unsigned int opinfo) { case VMG_OP_INFO_OBJECT: { dMY_CXT; if (!MY_CXT.b__op_stashes[0]) { - opclass c; + int c; require_pv("B.pm"); for (c = OPc_NULL; c < OPc_MAX; ++c) MY_CXT.b__op_stashes[c] = gv_stashpv(vmg_opclassnames[c], 1); @@ -943,7 +1056,7 @@ STATIC int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) { XPUSHs(vmg_op_info(opinfo)); PUTBACK; - call_sv(cb, G_SCALAR); + vmg_call_sv(cb, G_SCALAR, 0); SPAGAIN; svr = POPs; @@ -996,7 +1109,7 @@ STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) { if (t < SVt_PVAV) { STRLEN l; #if VMG_HAS_PERL(5, 9, 3) - const U8 *s = SvPV_const(sv, l); + const U8 *s = VOID2(const U8 *, VOID2(const void *, SvPV_const(sv, l))); #else U8 *s = SvPV(sv, l); #endif @@ -1016,7 +1129,7 @@ STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) { XPUSHs(vmg_op_info(opinfo)); PUTBACK; - call_sv(w->cb_len, G_SCALAR); + vmg_call_sv(w->cb_len, G_SCALAR, 0); SPAGAIN; svr = POPs; @@ -1038,11 +1151,6 @@ STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) { STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { const MGWIZ *w; -#if VMG_HAS_PERL(5, 9, 5) - PERL_CONTEXT saved_cx; - I32 cxix; -#endif - I32 had_err, has_err, flags = G_SCALAR | G_EVAL; int ret = 0; SV *svr; @@ -1058,7 +1166,7 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { /* So that it survives the temp cleanup below */ SvREFCNT_inc_simple_void(sv); -#if !VMG_HAS_PERL_MAINT(5, 11, 0, 32686) +#if !(VMG_HAS_PERL_MAINT(5, 11, 0, 32686) || VMG_HAS_PERL(5, 12, 0)) /* The previous magic tokens were freed but the magic chain wasn't updated, so * if you access the sv from the callback the old deleted magics will trigger * and cause memory misreads. Change 32686 solved it that way : */ @@ -1076,30 +1184,7 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { XPUSHs(vmg_op_info(w->opinfo)); PUTBACK; - had_err = SvTRUE(ERRSV); - if (had_err) - flags |= G_KEEPERR; - -#if VMG_HAS_PERL(5, 9, 5) - /* This context should not be used anymore, but since we croak in places the - * core doesn't even dare to, some pointers to it may remain in the upper call - * stack. Make sure call_sv() doesn't clobber it. */ - if (cxstack_ix < cxstack_max) - cxix = cxstack_ix + 1; - else - cxix = Perl_cxinc(aTHX); - saved_cx = cxstack[cxix]; -#endif - - call_sv(w->cb_free, flags); - -#if VMG_HAS_PERL(5, 9, 5) - cxstack[cxix] = saved_cx; -#endif - - has_err = SvTRUE(ERRSV); - if (IN_PERL_COMPILETIME && !had_err && has_err) - ++PL_error_count; + vmg_call_sv(w->cb_free, G_SCALAR, 1); SPAGAIN; svr = POPs; @@ -1121,7 +1206,7 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { #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) +# if VMG_HAS_PERL_MAINT(5, 11, 0, 33256) || VMG_HAS_PERL(5, 12, 0) I32 keylen # else int keylen @@ -1311,6 +1396,7 @@ BOOT: newSVuv(VMG_COMPAT_ARRAY_UNDEF_CLEAR)); newCONSTSUB(stash, "VMG_COMPAT_SCALAR_LENGTH_NOLEN", newSVuv(VMG_COMPAT_SCALAR_LENGTH_NOLEN)); + newCONSTSUB(stash, "VMG_COMPAT_GLOB_GET", newSVuv(VMG_COMPAT_GLOB_GET)); newCONSTSUB(stash, "VMG_PERL_PATCHLEVEL", newSVuv(VMG_PERL_PATCHLEVEL)); newCONSTSUB(stash, "VMG_THREADSAFE", newSVuv(VMG_THREADSAFE)); newCONSTSUB(stash, "VMG_FORKSAFE", newSVuv(VMG_FORKSAFE)); @@ -1326,7 +1412,7 @@ PROTOTYPE: DISABLE PREINIT: ptable *t; U32 had_b__op_stash = 0; - opclass c; + int c; PPCODE: { my_cxt_t ud;