X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2FVariable-Magic.git;a=blobdiff_plain;f=Magic.xs;h=5ca81e35766050b99b966877a513d6eb32420903;hp=15d51caac77c520d969b8e37c84648c423e13edb;hb=561734f7d9ced589e9336a805b83294f903bdd2a;hpb=7bd7c3d822cc5f91b1ebf227e3756d2ef6e977e1 diff --git a/Magic.xs b/Magic.xs index 15d51ca..5ca81e3 100644 --- a/Magic.xs +++ b/Magic.xs @@ -139,6 +139,12 @@ # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 0 #endif +#if VMG_HAS_PERL(5, 17, 4) +# define VMG_COMPAT_SCALAR_NOLEN 1 +#else +# define VMG_COMPAT_SCALAR_NOLEN 0 +#endif + /* Applied to dev-5.9 as 25854, integrated to maint-5.8 as 28160, partially * 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) @@ -181,12 +187,23 @@ # define VMG_COMPAT_HASH_DELETE_NOUVAR_VOID 0 #endif +#if VMG_HAS_PERL(5, 17, 0) +# define VMG_COMPAT_CODE_COPY_CLONE 1 +#else +# define VMG_COMPAT_CODE_COPY_CLONE 0 +#endif + #if VMG_HAS_PERL(5, 13, 2) # define VMG_COMPAT_GLOB_GET 1 #else # define VMG_COMPAT_GLOB_GET 0 #endif +#define VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE (VMG_HAS_PERL(5, 10, 0) && !VMG_HAS_PERL(5, 10, 1)) + +/* NewOp() isn't public in perl 5.8.0. */ +#define VMG_RESET_RMG_NEEDS_TRAMPOLINE (VMG_UVAR && (VMG_THREADSAFE || !VMG_HAS_PERL(5, 8, 1))) + /* ... Bug-free mg_magical ................................................. */ /* See the discussion at http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2008-01/msg00036.html */ @@ -220,12 +237,9 @@ STATIC void vmg_mg_magical(SV *sv) { #endif -/* ... Trampoline ops ...................................................... */ +/* --- Trampoline ops ------------------------------------------------------ */ -/* NewOp() isn't public in perl 5.8.0. */ -#define VMG_RESET_RMG_NEEDS_TRAMPOLINE (VMG_UVAR && (VMG_THREADSAFE || !VMG_HAS_PERL(5, 8, 1))) - -#define VMG_NEEDS_TRAMPOLINE VMG_RESET_RMG_NEEDS_TRAMPOLINE +#define VMG_NEEDS_TRAMPOLINE VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE || VMG_RESET_RMG_NEEDS_TRAMPOLINE #if VMG_NEEDS_TRAMPOLINE @@ -262,25 +276,20 @@ STATIC OP *vmg_trampoline_bump(pTHX_ vmg_trampoline *t, SV *sv, OP *o) { #endif /* VMG_NEEDS_TRAMPOLINE */ -/* ... Safe version of call_sv() ........................................... */ +/* --- Safe version of call_sv() ------------------------------------------- */ STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, int (*cleanup)(pTHX_ void *), void *ud) { #define vmg_call_sv(S, F, C, U) vmg_call_sv(aTHX_ (S), (F), (C), (U)) - I32 ret, cxix, in_eval = 0; + I32 ret, cxix; PERL_CONTEXT saved_cx; SV *old_err = NULL; if (SvTRUE(ERRSV)) { - old_err = ERRSV; - ERRSV = newSV(0); + old_err = newSVsv(ERRSV); + sv_setsv(ERRSV, &PL_sv_undef); } - if (cxstack_ix < cxstack_max) { - cxix = cxstack_ix + 1; - in_eval = CxTYPE(cxstack + cxix) == CXt_EVAL; - } else { - cxix = Perl_cxinc(aTHX); - } + cxix = (cxstack_ix < cxstack_max) ? (cxstack_ix + 1) : Perl_cxinc(aTHX); /* 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]; @@ -290,11 +299,8 @@ STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, int (*cleanup)(pTHX_ void *), vo cxstack[cxix] = saved_cx; if (SvTRUE(ERRSV)) { - if (old_err) { - sv_setsv(old_err, ERRSV); - SvREFCNT_dec(ERRSV); - ERRSV = old_err; - } + SvREFCNT_dec(old_err); + if (IN_PERL_COMPILETIME) { if (!PL_in_eval) { if (PL_errors) @@ -311,14 +317,14 @@ STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, int (*cleanup)(pTHX_ void *), vo #else ++PL_Ierror_count; #endif - } else if (!in_eval) { + } else { if (!cleanup || cleanup(aTHX_ ud)) croak(NULL); } } else { if (old_err) { - SvREFCNT_dec(ERRSV); - ERRSV = old_err; + sv_setsv(ERRSV, old_err); + SvREFCNT_dec(old_err); } } @@ -328,19 +334,22 @@ STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, int (*cleanup)(pTHX_ void *), vo /* --- Stolen chunk of B --------------------------------------------------- */ typedef enum { - OPc_NULL = 0, - OPc_BASEOP = 1, - OPc_UNOP = 2, - OPc_BINOP = 3, - OPc_LOGOP = 4, - OPc_LISTOP = 5, - OPc_PMOP = 6, - OPc_SVOP = 7, - OPc_PADOP = 8, - OPc_PVOP = 9, - OPc_LOOP = 10, - OPc_COP = 11, - OPc_MAX = 12 + OPc_NULL, + OPc_BASEOP, + OPc_UNOP, + OPc_BINOP, + OPc_LOGOP, + OPc_LISTOP, + OPc_PMOP, + OPc_SVOP, + OPc_PADOP, + OPc_PVOP, + OPc_LOOP, + OPc_COP, +#if VMG_HAS_PERL(5, 21, 5) + OPc_METHOP, +#endif + OPc_MAX } opclass; STATIC const char *const vmg_opclassnames[] = { @@ -355,7 +364,11 @@ STATIC const char *const vmg_opclassnames[] = { "B::PADOP", "B::PVOP", "B::LOOP", - "B::COP" + "B::COP", +#if VMG_HAS_PERL(5, 21, 5) + "B::METHOP", +#endif + NULL }; STATIC opclass vmg_opclass(const OP *o) { @@ -427,6 +440,10 @@ STATIC opclass vmg_opclass(const OP *o) { return OPc_BASEOP; else return OPc_PVOP; +#if VMG_HAS_PERL(5, 21, 5) + case OA_METHOP: + return OPc_METHOP; +#endif } return OPc_BASEOP; @@ -446,6 +463,9 @@ typedef struct { HV *b__op_stashes[OPc_MAX]; I32 depth; MAGIC *freed_tokens; +#if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE + vmg_trampoline propagate_errsv; +#endif #if VMG_RESET_RMG_NEEDS_TRAMPOLINE vmg_trampoline reset_rmg; #endif @@ -1349,26 +1369,113 @@ STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) { /* ... free magic .......................................................... */ -STATIC int vmg_svt_free_cleanup(pTHX_ void *ud) { - SV *sv = VOID2(SV *, ud); - MAGIC *mg; +#if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE + +STATIC OP *vmg_pp_propagate_errsv(pTHX) { + SVOP *o = cSVOPx(PL_op); - /* We are about to croak() while sv is being destroyed. Try to clean up - * things a bit. */ - mg = SvMAGIC(sv); - if (mg) { - vmg_mg_del(sv, NULL, mg, mg->mg_moremagic); - mg_magical(sv); + if (o->op_sv) { + sv_setsv(ERRSV, o->op_sv); + SvREFCNT_dec(o->op_sv); + o->op_sv = NULL; } - SvREFCNT_dec(sv); - vmg_dispell_guard_oncroak(aTHX_ ud); + return NORMAL; +} - /* After that, propagate the error upwards. */ - return 1; +#endif /* VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE */ + +STATIC int vmg_propagate_errsv_free(pTHX_ SV *sv, MAGIC *mg) { + if (mg->mg_obj) + sv_setsv(ERRSV, mg->mg_obj); + + return 0; +} + +/* perl is already kind enough to handle the cloning of the mg_obj member, + hence we don't need to define a dup magic callback. */ + +STATIC MGVTBL vmg_propagate_errsv_vtbl = { + 0, /* get */ + 0, /* set */ + 0, /* len */ + 0, /* clear */ + vmg_propagate_errsv_free, /* free */ + 0, /* copy */ + 0, /* dup */ +#if MGf_LOCAL + 0, /* local */ +#endif /* MGf_LOCAL */ +}; + +typedef struct { + SV *sv; + int in_eval; + I32 base; +} vmg_svt_free_cleanup_ud; + +STATIC int vmg_svt_free_cleanup(pTHX_ void *ud_) { + vmg_svt_free_cleanup_ud *ud = VOID2(vmg_svt_free_cleanup_ud *, ud_); + + if (ud->in_eval) { + U32 optype = PL_op ? PL_op->op_type : OP_NULL; + + if (optype == OP_LEAVETRY || optype == OP_LEAVEEVAL) { + SV *errsv = newSVsv(ERRSV); + + FREETMPS; + LEAVE_SCOPE(ud->base); + +#if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE + if (optype == OP_LEAVETRY) { + dMY_CXT; + PL_op = vmg_trampoline_bump(&MY_CXT.propagate_errsv, errsv, PL_op); + } else if (optype == OP_LEAVEEVAL) { + SV *guard = sv_newmortal(); + sv_magicext(guard, errsv, PERL_MAGIC_ext, &vmg_propagate_errsv_vtbl, + NULL, 0); + } +#else /* !VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE */ +# if !VMG_HAS_PERL(5, 8, 9) + { + SV *guard = sv_newmortal(); + sv_magicext(guard, errsv, PERL_MAGIC_ext, &vmg_propagate_errsv_vtbl, + NULL, 0); + } +# else + sv_magicext(ERRSV, errsv, PERL_MAGIC_ext, &vmg_propagate_errsv_vtbl, + NULL, 0); + SvREFCNT_dec(errsv); +# endif +#endif /* VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE */ + + SAVETMPS; + } + + /* Don't propagate */ + return 0; + } else { + SV *sv = ud->sv; + MAGIC *mg; + + /* We are about to croak() while sv is being destroyed. Try to clean up + * things a bit. */ + mg = SvMAGIC(sv); + if (mg) { + vmg_mg_del(sv, NULL, mg, mg->mg_moremagic); + mg_magical(sv); + } + SvREFCNT_dec(sv); + + vmg_dispell_guard_oncroak(aTHX_ NULL); + + /* After that, propagate the error upwards. */ + return 1; + } } STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { + vmg_svt_free_cleanup_ud ud; const vmg_wizard *w; int ret = 0; SV *svr; @@ -1392,6 +1499,15 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { SvMAGIC_set(sv, mg); #endif + ud.sv = sv; + if (cxstack_ix < cxstack_max) { + ud.in_eval = (CxTYPE(cxstack + cxstack_ix + 1) == CXt_EVAL); + ud.base = ud.in_eval ? PL_scopestack[PL_scopestack_ix] : 0; + } else { + ud.in_eval = 0; + ud.base = 0; + } + ENTER; SAVETMPS; @@ -1406,7 +1522,7 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { { dMY_CXT; MY_CXT.depth++; - vmg_call_sv(w->cb_free, G_SCALAR, vmg_svt_free_cleanup, sv); + vmg_call_sv(w->cb_free, G_SCALAR, vmg_svt_free_cleanup, &ud); MY_CXT.depth--; if (MY_CXT.depth == 0 && MY_CXT.freed_tokens) { /* Free all the tokens in the chain but the current one (if it's present). @@ -1455,6 +1571,9 @@ STATIC int vmg_svt_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *key, VMG_S keysv = newSVpvn(key, keylen); } + if (SvTYPE(sv) >= SVt_PVCV) + nsv = sv_2mortal(newRV_inc(nsv)); + ret = vmg_cb_call3(w->cb_copy, w->opinfo, sv, mg->mg_obj, keysv, nsv); if (keylen != HEf_SVKEY) { @@ -1680,6 +1799,9 @@ BOOT: MY_CXT.freed_tokens = NULL; /* XS doesn't like a blank line here */ +#if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE + vmg_trampoline_init(&MY_CXT.propagate_errsv, vmg_pp_propagate_errsv); +#endif #if VMG_RESET_RMG_NEEDS_TRAMPOLINE vmg_trampoline_init(&MY_CXT.reset_rmg, vmg_pp_reset_rmg); #endif @@ -1697,6 +1819,8 @@ BOOT: newCONSTSUB(stash, "VMG_UVAR", newSVuv(VMG_UVAR)); newCONSTSUB(stash, "VMG_COMPAT_SCALAR_LENGTH_NOLEN", newSVuv(VMG_COMPAT_SCALAR_LENGTH_NOLEN)); + newCONSTSUB(stash, "VMG_COMPAT_SCALAR_NOLEN", + newSVuv(VMG_COMPAT_SCALAR_NOLEN)); newCONSTSUB(stash, "VMG_COMPAT_ARRAY_PUSH_NOLEN", newSVuv(VMG_COMPAT_ARRAY_PUSH_NOLEN)); newCONSTSUB(stash, "VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID", @@ -1707,6 +1831,8 @@ BOOT: newSVuv(VMG_COMPAT_ARRAY_UNDEF_CLEAR)); newCONSTSUB(stash, "VMG_COMPAT_HASH_DELETE_NOUVAR_VOID", newSVuv(VMG_COMPAT_HASH_DELETE_NOUVAR_VOID)); + newCONSTSUB(stash, "VMG_COMPAT_CODE_COPY_CLONE", + newSVuv(VMG_COMPAT_CODE_COPY_CLONE)); 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));