X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2FVariable-Magic.git;a=blobdiff_plain;f=Magic.xs;h=aa4af3518fc3c50dc6d35484ab3160cee3929a12;hp=69ad981a726d862427de4e88d96de34b3a689432;hb=HEAD;hpb=670e590caf3db942b5e7feddc1e86669f9f46294 diff --git a/Magic.xs b/Magic.xs index 69ad981..aa4af35 100644 --- a/Magic.xs +++ b/Magic.xs @@ -10,158 +10,30 @@ #include "perl.h" #include "XSUB.h" -#define __PACKAGE__ "Variable::Magic" +/* --- XS helpers ---------------------------------------------------------- */ -#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 -# else -# define VMG_PERL_PATCHLEVEL 0 -# endif -#endif - -#define VMG_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S)))))) - -#define VMG_HAS_PERL_BRANCH(R, V, S) (PERL_REVISION == (R) && PERL_VERSION == (V) && PERL_SUBVERSION >= (S)) - -#define VMG_HAS_PERL_MAINT(R, V, S, P) (PERL_REVISION == (R) && PERL_VERSION == (V) && (VMG_PERL_PATCHLEVEL >= (P) || (!VMG_PERL_PATCHLEVEL && PERL_SUBVERSION >= (S)))) - -/* --- Threads and multiplicity -------------------------------------------- */ - -#ifndef NOOP -# define NOOP -#endif - -#ifndef dNOOP -# define dNOOP -#endif - -/* Safe unless stated otherwise in Makefile.PL */ -#ifndef VMG_FORKSAFE -# define VMG_FORKSAFE 1 -#endif - -#ifndef VMG_MULTIPLICITY -# if defined(MULTIPLICITY) -# define VMG_MULTIPLICITY 1 -# else -# define VMG_MULTIPLICITY 0 -# endif -#endif -#if VMG_MULTIPLICITY -# ifndef PERL_IMPLICIT_CONTEXT -# error MULTIPLICITY builds must set PERL_IMPLICIT_CONTEXT -# endif -#endif - -#if VMG_MULTIPLICITY && defined(USE_ITHREADS) && defined(dMY_CXT) && defined(MY_CXT) && defined(START_MY_CXT) && defined(MY_CXT_INIT) && (defined(MY_CXT_CLONE) || defined(dMY_CXT_SV)) -# ifndef VMG_THREADSAFE -# define VMG_THREADSAFE 1 -# endif -# ifndef MY_CXT_CLONE -# define MY_CXT_CLONE \ - dMY_CXT_SV; \ - my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \ - Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \ - sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) -# endif -#else -# undef VMG_THREADSAFE -# define VMG_THREADSAFE 0 -# undef dMY_CXT -# define dMY_CXT dNOOP -# undef MY_CXT -# define MY_CXT vmg_globaldata -# undef START_MY_CXT -# define START_MY_CXT STATIC my_cxt_t MY_CXT; -# undef MY_CXT_INIT -# define MY_CXT_INIT NOOP -# undef MY_CXT_CLONE -# 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 - -/* --- Compatibility ------------------------------------------------------- */ - -#ifndef Newx -# define Newx(v, n, c) New(0, v, n, c) -#endif - -#ifndef SvMAGIC_set -# define SvMAGIC_set(sv, val) (SvMAGIC(sv) = (val)) -#endif - -#ifndef SvRV_const -# define SvRV_const(sv) SvRV((SV *) sv) -#endif - -#ifndef SvREFCNT_inc_simple_void -# define SvREFCNT_inc_simple_void(sv) ((void) SvREFCNT_inc(sv)) -#endif - -#ifndef mPUSHu -# define mPUSHu(U) PUSHs(sv_2mortal(newSVuv(U))) -#endif - -#ifndef PERL_MAGIC_ext -# define PERL_MAGIC_ext '~' -#endif - -#ifndef PERL_MAGIC_tied -# define PERL_MAGIC_tied 'P' -#endif - -#ifndef MGf_LOCAL -# define MGf_LOCAL 0 -#endif - -#ifndef IN_PERL_COMPILETIME -# define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling) -#endif - -#ifndef OP_NAME -# define OP_NAME(O) (PL_op_name[(O)->op_type]) -#endif +#define XSH_PACKAGE "Variable::Magic" -#ifndef OP_CLASS -# define OP_CLASS(O) (PL_opargs[(O)->op_type] & OA_CLASS_MASK) -#endif +#include "xsh/caps.h" +#include "xsh/util.h" -#ifdef DEBUGGING -# define VMG_ASSERT(C) assert(C) -#else -# define VMG_ASSERT(C) -#endif +/* ... Features ............................................................ */ /* 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) +#if XSH_HAS_PERL(5, 10, 0) # define VMG_UVAR 1 #else # define VMG_UVAR 0 #endif -#if VMG_HAS_PERL_MAINT(5, 11, 0, 32969) || VMG_HAS_PERL(5, 12, 0) +#if XSH_HAS_PERL_MAINT(5, 11, 0, 32969) || XSH_HAS_PERL(5, 12, 0) # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 1 #else # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 0 #endif -#if VMG_HAS_PERL(5, 17, 4) +#if XSH_HAS_PERL(5, 17, 4) # define VMG_COMPAT_SCALAR_NOLEN 1 #else # define VMG_COMPAT_SCALAR_NOLEN 0 @@ -169,9 +41,9 @@ /* 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) +#if XSH_HAS_PERL_MAINT(5, 8, 9, 28160) || XSH_HAS_PERL_MAINT(5, 9, 3, 25854) || XSH_HAS_PERL(5, 10, 0) # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN -# if VMG_HAS_PERL(5, 11, 0) +# if XSH_HAS_PERL(5, 11, 0) # define VMG_COMPAT_ARRAY_PUSH_NOLEN 0 # else # define VMG_COMPAT_ARRAY_PUSH_NOLEN 1 @@ -190,76 +62,43 @@ #endif /* Applied to dev-5.11 as 34908 */ -#if VMG_HAS_PERL_MAINT(5, 11, 0, 34908) || VMG_HAS_PERL(5, 12, 0) +#if XSH_HAS_PERL_MAINT(5, 11, 0, 34908) || XSH_HAS_PERL(5, 12, 0) # define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 1 #else # define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 0 #endif /* Applied to dev-5.9 as 31473 (see #43357), integrated to maint-5.8 as 32542 */ -#if VMG_HAS_PERL_MAINT(5, 8, 9, 32542) || VMG_HAS_PERL_MAINT(5, 9, 5, 31473) || VMG_HAS_PERL(5, 10, 0) +#if XSH_HAS_PERL_MAINT(5, 8, 9, 32542) || XSH_HAS_PERL_MAINT(5, 9, 5, 31473) || XSH_HAS_PERL(5, 10, 0) # define VMG_COMPAT_ARRAY_UNDEF_CLEAR 1 #else # define VMG_COMPAT_ARRAY_UNDEF_CLEAR 0 #endif -#if VMG_HAS_PERL(5, 11, 0) +#if XSH_HAS_PERL(5, 11, 0) # define VMG_COMPAT_HASH_DELETE_NOUVAR_VOID 1 #else # define VMG_COMPAT_HASH_DELETE_NOUVAR_VOID 0 #endif -#if VMG_HAS_PERL(5, 17, 0) +#if XSH_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) +#if XSH_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)) +/* ... 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))) - -/* ... Bug-free mg_magical ................................................. */ - -/* See the discussion at http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2008-01/msg00036.html */ +#define VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE (XSH_HAS_PERL(5, 10, 0) && !XSH_HAS_PERL(5, 10, 1)) -#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))) { - do { - const MGVTBL* const vtbl = mg->mg_virtual; - if (vtbl) { - 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); - } - } while ((mg = mg->mg_moremagic)); - if (!(SvFLAGS(sv) & (SVs_GMG|SVs_SMG))) - SvRMAGICAL_on(sv); - } -} - -#endif - -/* --- Trampoline ops ------------------------------------------------------ */ +/* NewOp() isn't public in perl 5.8.0. */ +#define VMG_RESET_RMG_NEEDS_TRAMPOLINE (VMG_UVAR && (XSH_THREADSAFE || !XSH_HAS_PERL(5, 8, 1))) #define VMG_NEEDS_TRAMPOLINE VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE || VMG_RESET_RMG_NEEDS_TRAMPOLINE @@ -298,7 +137,92 @@ static OP *vmg_trampoline_bump(pTHX_ vmg_trampoline *t, SV *sv, OP *o) { #endif /* VMG_NEEDS_TRAMPOLINE */ -/* --- Cleaner version of sv_magicext() ------------------------------------ */ +/* --- Compatibility ------------------------------------------------------- */ + +#ifndef Newx +# define Newx(v, n, c) New(0, v, n, c) +#endif + +#ifndef SvMAGIC_set +# define SvMAGIC_set(sv, val) (SvMAGIC(sv) = (val)) +#endif + +#ifndef SvRV_const +# define SvRV_const(sv) SvRV((SV *) sv) +#endif + +#ifndef SvREFCNT_inc_simple_void +# define SvREFCNT_inc_simple_void(sv) ((void) SvREFCNT_inc(sv)) +#endif + +#ifndef SvREFCNT_dec_NN +# define SvREFCNT_dec_NN(sv) ((void) SvREFCNT_dec(sv)) +#endif + +#ifndef mPUSHu +# define mPUSHu(U) PUSHs(sv_2mortal(newSVuv(U))) +#endif + +#ifndef PERL_MAGIC_ext +# define PERL_MAGIC_ext '~' +#endif + +#ifndef PERL_MAGIC_tied +# define PERL_MAGIC_tied 'P' +#endif + +#ifndef MGf_LOCAL +# define MGf_LOCAL 0 +#endif + +#ifndef IN_PERL_COMPILETIME +# define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling) +#endif + +#ifndef OP_NAME +# define OP_NAME(O) (PL_op_name[(O)->op_type]) +#endif + +#ifndef OP_CLASS +# define OP_CLASS(O) (PL_opargs[(O)->op_type] & OA_CLASS_MASK) +#endif + +#define VMG_CAREFUL_SELF_DESTRUCTION XSH_HAS_PERL(5, 25, 3) + +/* ... Bug-free mg_magical ................................................. */ + +/* See the discussion at http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2008-01/msg00036.html */ + +#if XSH_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))) { + do { + const MGVTBL* const vtbl = mg->mg_virtual; + if (vtbl) { + 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); + } + } while ((mg = mg->mg_moremagic)); + if (!(SvFLAGS(sv) & (SVs_GMG|SVs_SMG))) + SvRMAGICAL_on(sv); + } +} + +#endif + +/* ... Cleaner version of sv_magicext() .................................... */ static MAGIC *vmg_sv_magicext(pTHX_ SV *sv, SV *obj, const MGVTBL *vtbl, const void *ptr, I32 len) { #define vmg_sv_magicext(S, O, V, P, L) vmg_sv_magicext(aTHX_ (S), (O), (V), (P), (L)) @@ -327,12 +251,11 @@ static MAGIC *vmg_sv_magicext(pTHX_ SV *sv, SV *obj, const MGVTBL *vtbl, const v return mg; } -/* --- 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; - PERL_CONTEXT saved_cx; + I32 ret; SV *old_err = NULL; if (SvTRUE(ERRSV)) { @@ -340,15 +263,8 @@ static I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, int (*cleanup)(pTHX_ void *), vo sv_setsv(ERRSV, &PL_sv_undef); } - 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]; - ret = call_sv(sv, flags | G_EVAL); - cxstack[cxix] = saved_cx; - if (SvTRUE(ERRSV)) { SvREFCNT_dec(old_err); @@ -360,7 +276,7 @@ static I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, int (*cleanup)(pTHX_ void *), vo Perl_warn(aTHX_ "%s", SvPV_nolen(ERRSV)); SvCUR_set(ERRSV, 0); } -#if VMG_HAS_PERL(5, 10, 0) || defined(PL_parser) +#if XSH_HAS_PERL(5, 10, 0) || defined(PL_parser) if (PL_parser) ++PL_parser->error_count; #elif defined(PL_error_count) @@ -397,10 +313,10 @@ typedef enum { OPc_PVOP, OPc_LOOP, OPc_COP, -#if VMG_HAS_PERL(5, 21, 5) +#if XSH_HAS_PERL(5, 21, 5) OPc_METHOP, #endif -#if VMG_HAS_PERL(5, 21, 7) +#if XSH_HAS_PERL(5, 21, 7) OPc_UNOP_AUX, #endif OPc_MAX @@ -419,10 +335,10 @@ static const char *const vmg_opclassnames[] = { "B::PVOP", "B::LOOP", "B::COP", -#if VMG_HAS_PERL(5, 21, 5) +#if XSH_HAS_PERL(5, 21, 5) "B::METHOP", #endif -#if VMG_HAS_PERL(5, 21, 7) +#if XSH_HAS_PERL(5, 21, 7) "B::UNOP_AUX", #endif NULL @@ -436,7 +352,7 @@ static opclass vmg_opclass(pTHX_ const OP *o) { #endif if (o->op_type == 0) { -#if VMG_HAS_PERL(5, 21, 7) +#if XSH_HAS_PERL(5, 21, 7) if (o->op_targ == OP_NEXTSTATE || o->op_targ == OP_DBSTATE) return OPc_COP; #endif @@ -483,11 +399,11 @@ static opclass vmg_opclass(pTHX_ const OP *o) { return OPc_PADOP; case OA_PVOP_OR_SVOP: return ( -#if VMG_HAS_PERL(5, 13, 7) +#if XSH_HAS_PERL(5, 13, 7) (o->op_type != OP_CUSTOM) && #endif (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))) -#if defined(USE_ITHREADS) && VMG_HAS_PERL(5, 8, 9) +#if defined(USE_ITHREADS) && XSH_HAS_PERL(5, 8, 9) ? OPc_PADOP : OPc_PVOP; #else ? OPc_SVOP : OPc_PVOP; @@ -512,11 +428,11 @@ static opclass vmg_opclass(pTHX_ const OP *o) { return OPc_BASEOP; else return OPc_PVOP; -#if VMG_HAS_PERL(5, 21, 5) +#if XSH_HAS_PERL(5, 21, 5) case OA_METHOP: return OPc_METHOP; #endif -#if VMG_HAS_PERL(5, 21, 7) +#if XSH_HAS_PERL(5, 21, 7) case OA_UNOP_AUX: return OPc_UNOP_AUX; #endif @@ -530,9 +446,7 @@ static opclass vmg_opclass(pTHX_ const OP *o) { static const char vmg_invalid_wiz[] = "Invalid wizard object"; static const char vmg_wrongargnum[] = "Wrong number of arguments"; -/* --- Context-safe global data -------------------------------------------- */ - -#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION +/* --- Thread-local storage ------------------------------------------------ */ typedef struct { HV *b__op_stashes[OPc_MAX]; @@ -544,13 +458,35 @@ typedef struct { #if VMG_RESET_RMG_NEEDS_TRAMPOLINE vmg_trampoline reset_rmg; #endif -} my_cxt_t; +} xsh_user_cxt_t; + +#if XSH_THREADSAFE + +static void xsh_user_clone(pTHX_ const xsh_user_cxt_t *old_cxt, xsh_user_cxt_t *new_cxt) { + int c; + + for (c = OPc_NULL; c < OPc_MAX; ++c) { + new_cxt->b__op_stashes[c] = old_cxt->b__op_stashes[c] + ? gv_stashpv(vmg_opclassnames[c], 1) + : NULL; + } + + new_cxt->depth = old_cxt->depth; + new_cxt->freed_tokens = NULL; + + return; +} + + +#endif /* XSH_THREADSAFE */ -START_MY_CXT +#define XSH_THREADS_NEED_TEARDOWN_LATE 1 + +#include "xsh/threads.h" /* --- structure ---------------------------------------------- */ -#if VMG_THREADSAFE +#if XSH_THREADSAFE typedef struct { MGVTBL *vtbl; @@ -575,9 +511,9 @@ static perl_mutex vmg_vtable_refcount_mutex; 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); + XSH_LOCK(&vmg_vtable_refcount_mutex); ++t->refcount; - VMG_UNLOCK(&vmg_vtable_refcount_mutex); + XSH_UNLOCK(&vmg_vtable_refcount_mutex); return t; } @@ -586,9 +522,9 @@ 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); + XSH_LOCK(&vmg_vtable_refcount_mutex); refcount = --t->refcount; - VMG_UNLOCK(&vmg_vtable_refcount_mutex); + XSH_UNLOCK(&vmg_vtable_refcount_mutex); if (!refcount) { PerlMemShared_free(t->vtbl); @@ -596,7 +532,7 @@ static void vmg_vtable_free(pTHX_ vmg_vtable *t) { } } -#else /* VMG_THREADSAFE */ +#else /* XSH_THREADSAFE */ typedef MGVTBL vmg_vtable; @@ -613,7 +549,7 @@ static vmg_vtable *vmg_vtable_alloc(pTHX) { #define vmg_vtable_free(T) Safefree(T) -#endif /* !VMG_THREADSAFE */ +#endif /* !XSH_THREADSAFE */ /* --- structure ---------------------------------------------- */ @@ -690,7 +626,7 @@ static void vmg_wizard_free(pTHX_ vmg_wizard *w) { return; } -#if VMG_THREADSAFE +#if XSH_THREADSAFE #define VMG_CLONE_CB(N) \ z->cb_ ## N = (w->cb_ ## N) ? SvREFCNT_inc(sv_dup(w->cb_ ## N, params)) \ @@ -730,7 +666,7 @@ static const vmg_wizard *vmg_wizard_dup(pTHX_ const vmg_wizard *w, CLONE_PARAMS return z; } -#endif /* VMG_THREADSAFE */ +#endif /* XSH_THREADSAFE */ #define vmg_wizard_id(W) PTR2IV(vmg_vtable_vtbl((W)->vtable)) @@ -742,7 +678,7 @@ static int vmg_wizard_sv_free(pTHX_ SV *sv, MAGIC *mg) { return 0; } -#if VMG_THREADSAFE +#if XSH_THREADSAFE static int vmg_wizard_sv_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params) { mg->mg_ptr = (char *) vmg_wizard_dup((const vmg_wizard *) mg->mg_ptr, params); @@ -750,7 +686,7 @@ static int vmg_wizard_sv_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params) { return 0; } -#endif /* VMG_THREADSAFE */ +#endif /* XSH_THREADSAFE */ static MGVTBL vmg_wizard_sv_vtbl = { NULL, /* get */ @@ -759,7 +695,7 @@ static MGVTBL vmg_wizard_sv_vtbl = { NULL, /* clear */ vmg_wizard_sv_free, /* free */ NULL, /* copy */ -#if VMG_THREADSAFE +#if XSH_THREADSAFE vmg_wizard_sv_dup, /* dup */ #else NULL, /* dup */ @@ -773,7 +709,7 @@ static SV *vmg_wizard_sv_new(pTHX_ const vmg_wizard *w) { #define vmg_wizard_sv_new(W) vmg_wizard_sv_new(aTHX_ (W)) SV *wiz; -#if VMG_THREADSAFE +#if XSH_THREADSAFE wiz = newSV(0); #else wiz = newSViv(PTR2IV(w)); @@ -786,7 +722,7 @@ static SV *vmg_wizard_sv_new(pTHX_ const vmg_wizard *w) { return wiz; } -#if VMG_THREADSAFE +#if XSH_THREADSAFE #define vmg_sv_has_wizard_type(S) (SvTYPE(S) >= SVt_PVMG) @@ -801,13 +737,13 @@ static const vmg_wizard *vmg_wizard_from_sv_nocheck(const SV *wiz) { return NULL; } -#else /* VMG_THREADSAFE */ +#else /* XSH_THREADSAFE */ #define vmg_sv_has_wizard_type(S) SvIOK(S) #define vmg_wizard_from_sv_nocheck(W) INT2PTR(const vmg_wizard *, SvIVX(W)) -#endif /* !VMG_THREADSAFE */ +#endif /* !XSH_THREADSAFE */ #define vmg_wizard_from_sv(W) (vmg_sv_has_wizard_type(W) ? vmg_wizard_from_sv_nocheck(W) : NULL) @@ -857,6 +793,8 @@ static SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, SV **args, I32 items) { ENTER; SAVETMPS; + PUSHSTACKi(PERLSI_MAGIC); + PUSHMARK(SP); EXTEND(SP, items + 1); PUSHs(sv_2mortal(newRV_inc(sv))); @@ -868,13 +806,15 @@ static SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, SV **args, I32 items) { SPAGAIN; nsv = POPs; -#if VMG_HAS_PERL(5, 8, 3) +#if XSH_HAS_PERL(5, 8, 3) SvREFCNT_inc_simple_void(nsv); /* Or it will be destroyed in FREETMPS */ #else nsv = sv_newref(nsv); /* Workaround some bug in SvREFCNT_inc() */ #endif PUTBACK; + POPSTACK; + FREETMPS; LEAVE; @@ -903,7 +843,7 @@ typedef struct { static void vmg_mg_del(pTHX_ SV *sv, MAGIC *prevmagic, MAGIC *mg, MAGIC *moremagic) { #define vmg_mg_del(S, P, M, N) vmg_mg_del(aTHX_ (S), (P), (M), (N)) - dMY_CXT; + dXSH_CXT; if (prevmagic) prevmagic->mg_moremagic = moremagic; @@ -927,9 +867,9 @@ static void vmg_mg_del(pTHX_ SV *sv, MAGIC *prevmagic, MAGIC *mg, MAGIC *moremag } #endif /* VMG_UVAR */ - if (MY_CXT.depth) { - mg->mg_moremagic = MY_CXT.freed_tokens; - MY_CXT.freed_tokens = mg; + if (XSH_CXT.depth) { + mg->mg_moremagic = XSH_CXT.freed_tokens; + XSH_CXT.freed_tokens = mg; } else { mg->mg_moremagic = NULL; Safefree(mg); @@ -1114,7 +1054,7 @@ static UV vmg_dispell(pTHX_ SV *sv, const vmg_wizard *w) { #define VMG_OP_INFO_NAME 1 #define VMG_OP_INFO_OBJECT 2 -#if VMG_THREADSAFE +#if XSH_THREADSAFE static perl_mutex vmg_op_name_init_mutex; #endif @@ -1125,22 +1065,22 @@ static void vmg_op_info_init(pTHX_ unsigned int opinfo) { #define vmg_op_info_init(W) vmg_op_info_init(aTHX_ (W)) switch (opinfo) { case VMG_OP_INFO_NAME: - VMG_LOCK(&vmg_op_name_init_mutex); + XSH_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; } - VMG_UNLOCK(&vmg_op_name_init_mutex); + XSH_UNLOCK(&vmg_op_name_init_mutex); break; case VMG_OP_INFO_OBJECT: { - dMY_CXT; - if (!MY_CXT.b__op_stashes[0]) { + dXSH_CXT; + if (!XSH_CXT.b__op_stashes[0]) { 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); + XSH_CXT.b__op_stashes[c] = gv_stashpv(vmg_opclassnames[c], 1); } break; } @@ -1164,9 +1104,9 @@ static SV *vmg_op_info(pTHX_ unsigned int opinfo) { return sv_2mortal(newSVpvn(name, name_len)); } case VMG_OP_INFO_OBJECT: { - dMY_CXT; + dXSH_CXT; return sv_bless(sv_2mortal(newRV_noinc(newSViv(PTR2IV(PL_op)))), - MY_CXT.b__op_stashes[vmg_opclass(PL_op)]); + XSH_CXT.b__op_stashes[vmg_opclass(PL_op)]); } default: break; @@ -1183,16 +1123,16 @@ static SV *vmg_op_info(pTHX_ unsigned int opinfo) { #define VMG_CB_CALL_GUARD 4 static int vmg_dispell_guard_oncroak(pTHX_ void *ud) { - dMY_CXT; + dXSH_CXT; - MY_CXT.depth--; + XSH_CXT.depth--; /* If we're at the upmost magic call and we're about to die, we can just free * the tokens right now, since we will jump past the problematic part of our * caller. */ - if (MY_CXT.depth == 0 && MY_CXT.freed_tokens) { - vmg_magic_chain_free(MY_CXT.freed_tokens, NULL); - MY_CXT.freed_tokens = NULL; + if (XSH_CXT.depth == 0 && XSH_CXT.freed_tokens) { + vmg_magic_chain_free(XSH_CXT.freed_tokens, NULL); + XSH_CXT.freed_tokens = NULL; } return 1; @@ -1204,7 +1144,7 @@ static int vmg_dispell_guard_free(pTHX_ SV *sv, MAGIC *mg) { return 0; } -#if VMG_THREADSAFE +#if XSH_THREADSAFE static int vmg_dispell_guard_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params) { /* The freed magic tokens aren't cloned by perl because it cannot reach them @@ -1215,7 +1155,7 @@ static int vmg_dispell_guard_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params) { return 0; } -#endif /* VMG_THREADSAFE */ +#endif /* XSH_THREADSAFE */ static MGVTBL vmg_dispell_guard_vtbl = { NULL, /* get */ @@ -1224,7 +1164,7 @@ static MGVTBL vmg_dispell_guard_vtbl = { NULL, /* clear */ vmg_dispell_guard_free, /* free */ NULL, /* copy */ -#if VMG_THREADSAFE +#if XSH_THREADSAFE vmg_dispell_guard_dup, /* dup */ #else NULL, /* dup */ @@ -1260,6 +1200,8 @@ static int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) { ENTER; SAVETMPS; + PUSHSTACKi(PERLSI_MAGIC); + PUSHMARK(SP); EXTEND(SP, args + 1); PUSHs(sv_2mortal(newRV_inc(sv))); @@ -1274,12 +1216,12 @@ static int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) { PUTBACK; if (flags & VMG_CB_CALL_GUARD) { - dMY_CXT; - MY_CXT.depth++; + dXSH_CXT; + XSH_CXT.depth++; vmg_call_sv(cb, G_SCALAR, vmg_dispell_guard_oncroak, NULL); - MY_CXT.depth--; - if (MY_CXT.depth == 0 && MY_CXT.freed_tokens) - chain = &MY_CXT.freed_tokens; + XSH_CXT.depth--; + if (XSH_CXT.depth == 0 && XSH_CXT.freed_tokens) + chain = &XSH_CXT.freed_tokens; } else { vmg_call_sv(cb, G_SCALAR, 0, NULL); } @@ -1294,6 +1236,8 @@ static int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) { svr = NULL; PUTBACK; + POPSTACK; + FREETMPS; LEAVE; @@ -1349,7 +1293,7 @@ static int vmg_svt_set(pTHX_ SV *sv, MAGIC *mg) { static U32 vmg_sv_len(pTHX_ SV *sv) { #define vmg_sv_len(S) vmg_sv_len(aTHX_ (S)) STRLEN len; -#if VMG_HAS_PERL(5, 9, 3) +#if XSH_HAS_PERL(5, 9, 3) const U8 *s = VOID2(const U8 *, VOID2(const void *, SvPV_const(sv, len))); #else U8 *s = SvPV(sv, len); @@ -1370,6 +1314,8 @@ static U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) { ENTER; SAVETMPS; + PUSHSTACKi(PERLSI_MAGIC); + PUSHMARK(SP); EXTEND(SP, 3); PUSHs(sv_2mortal(newRV_inc(sv))); @@ -1397,6 +1343,8 @@ static U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) { --ret; PUTBACK; + POPSTACK; + FREETMPS; LEAVE; @@ -1422,7 +1370,7 @@ static int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) { const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg); unsigned int flags = w->opinfo; -#if !VMG_HAS_PERL(5, 12, 0) +#if !XSH_HAS_PERL(5, 12, 0) flags |= VMG_CB_CALL_GUARD; #endif @@ -1474,6 +1422,9 @@ static MGVTBL vmg_propagate_errsv_vtbl = { typedef struct { SV *sv; +#if VMG_CAREFUL_SELF_DESTRUCTION + SV *rsv; /* The ref to the sv currently being freed, pushed on the stack */ +#endif int in_eval; I32 base; } vmg_svt_free_cleanup_ud; @@ -1492,14 +1443,14 @@ static int vmg_svt_free_cleanup(pTHX_ void *ud_) { #if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE if (optype == OP_LEAVETRY) { - dMY_CXT; - PL_op = vmg_trampoline_bump(&MY_CXT.propagate_errsv, errsv, PL_op); + dXSH_CXT; + PL_op = vmg_trampoline_bump(&XSH_CXT.propagate_errsv, errsv, PL_op); } else if (optype == OP_LEAVEEVAL) { SV *guard = sv_newmortal(); vmg_sv_magicext(guard, errsv, &vmg_propagate_errsv_vtbl, NULL, 0); } #else /* !VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE */ -# if !VMG_HAS_PERL(5, 8, 9) +# if !XSH_HAS_PERL(5, 8, 9) { SV *guard = sv_newmortal(); vmg_sv_magicext(guard, errsv, &vmg_propagate_errsv_vtbl, NULL, 0); @@ -1518,6 +1469,17 @@ static int vmg_svt_free_cleanup(pTHX_ void *ud_) { SV *sv = ud->sv; MAGIC *mg; +#if VMG_CAREFUL_SELF_DESTRUCTION + /* Silently undo the ref - don't trigger destruction in the referent + * for a second time */ + if (SvROK(ud->rsv) && SvRV(ud->rsv) == sv) { + SvRV_set(ud->rsv, NULL); + SvROK_off(ud->rsv); + --SvREFCNT(sv); /* Silent */ + } + SvREFCNT_dec_NN(ud->rsv); +#endif + /* We are about to croak() while sv is being destroyed. Try to clean up * things a bit. */ mg = SvMAGIC(sv); @@ -1525,7 +1487,7 @@ static int vmg_svt_free_cleanup(pTHX_ void *ud_) { vmg_mg_del(sv, NULL, mg, mg->mg_moremagic); mg_magical(sv); } - SvREFCNT_dec(sv); + SvREFCNT_dec(sv); /* Re-trigger destruction */ vmg_dispell_guard_oncroak(aTHX_ NULL); @@ -1552,7 +1514,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) || VMG_HAS_PERL(5, 12, 0)) +#if !(XSH_HAS_PERL_MAINT(5, 11, 0, 32686) || XSH_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 : */ @@ -1571,24 +1533,32 @@ static int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { ENTER; SAVETMPS; + PUSHSTACKi(PERLSI_MAGIC); + PUSHMARK(SP); EXTEND(SP, 2); + /* This will bump the refcount of sv from 0 to 1 */ +#if VMG_CAREFUL_SELF_DESTRUCTION + ud.rsv = newRV_inc(sv); + PUSHs(ud.rsv); +#else PUSHs(sv_2mortal(newRV_inc(sv))); +#endif PUSHs(mg->mg_obj ? mg->mg_obj : &PL_sv_undef); if (w->opinfo) XPUSHs(vmg_op_info(w->opinfo)); PUTBACK; { - dMY_CXT; - MY_CXT.depth++; + dXSH_CXT; + XSH_CXT.depth++; 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) { + XSH_CXT.depth--; + if (XSH_CXT.depth == 0 && XSH_CXT.freed_tokens) { /* Free all the tokens in the chain but the current one (if it's present). * It will be taken care of by our caller, Perl_mg_free(). */ - vmg_magic_chain_free(MY_CXT.freed_tokens, mg); - MY_CXT.freed_tokens = NULL; + vmg_magic_chain_free(XSH_CXT.freed_tokens, mg); + XSH_CXT.freed_tokens = NULL; } } @@ -1598,6 +1568,19 @@ static int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { ret = (int) SvIV(svr); PUTBACK; + POPSTACK; + +#if VMG_CAREFUL_SELF_DESTRUCTION + /* Silently undo the ref - don't trigger destruction in the referent + * for a second time */ + if (SvROK(ud.rsv) && SvRV(ud.rsv) == sv) { + SvRV_set(ud.rsv, NULL); + SvROK_off(ud.rsv); + --SvREFCNT(sv); /* Silent */ + } + SvREFCNT_dec_NN(ud.rsv); +#endif + FREETMPS; LEAVE; @@ -1612,7 +1595,7 @@ static int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { #define vmg_svt_free_noop vmg_svt_default_noop -#if VMG_HAS_PERL_MAINT(5, 11, 0, 33256) || VMG_HAS_PERL(5, 12, 0) +#if XSH_HAS_PERL_MAINT(5, 11, 0, 33256) || XSH_HAS_PERL(5, 12, 0) # define VMG_SVT_COPY_KEYLEN_TYPE I32 #else # define VMG_SVT_COPY_KEYLEN_TYPE int @@ -1763,9 +1746,9 @@ static I32 vmg_svt_val(pTHX_ IV action, SV *sv) { #if VMG_RESET_RMG_NEEDS_TRAMPOLINE - dMY_CXT; + dXSH_CXT; - PL_op = vmg_trampoline_bump(&MY_CXT.reset_rmg, sv, PL_op); + PL_op = vmg_trampoline_bump(&XSH_CXT.reset_rmg, sv, PL_op); #else /* !VMG_RESET_RMG_NEEDS_TRAMPOLINE */ @@ -1799,56 +1782,16 @@ static I32 vmg_svt_val(pTHX_ IV action, SV *sv) { /* --- Module setup/teardown ----------------------------------------------- */ -#if VMG_THREADSAFE - -static I32 vmg_loaded = 0; - -/* We must use preexistent global mutexes or we will never be able to destroy - * them. */ -# if VMG_HAS_PERL(5, 9, 3) -# define VMG_LOADED_LOCK MUTEX_LOCK(&PL_my_ctx_mutex) -# define VMG_LOADED_UNLOCK MUTEX_UNLOCK(&PL_my_ctx_mutex) -# else -# define VMG_LOADED_LOCK OP_REFCNT_LOCK -# define VMG_LOADED_UNLOCK OP_REFCNT_UNLOCK -# endif +#if XSH_THREADSAFE -static void vmg_global_teardown_late_locked(pTHX) { -#define vmg_global_teardown_late_locked() vmg_global_teardown_late_locked(aTHX) +static void vmg_global_teardown_late_locked(pTHX_ void *ud) { +#define vmg_global_teardown_late_locked(UD) vmg_global_teardown_late_locked(aTHX_ (UD)) MUTEX_DESTROY(&vmg_op_name_init_mutex); MUTEX_DESTROY(&vmg_vtable_refcount_mutex); return; } -static int vmg_global_teardown_free(pTHX_ SV *sv, MAGIC *mg) { - VMG_LOADED_LOCK; - - if (vmg_loaded == 0) - vmg_global_teardown_late_locked(); - - VMG_LOADED_UNLOCK; - - return 0; -} - -static MGVTBL vmg_global_teardown_vtbl = { - 0, - 0, - 0, - 0, - vmg_global_teardown_free -#if MGf_COPY - , 0 -#endif -#if MGf_DUP - , 0 -#endif -#if MGf_LOCAL - , 0 -#endif -}; - static signed char vmg_destruct_level(pTHX) { #define vmg_destruct_level() vmg_destruct_level(aTHX) signed char lvl; @@ -1860,21 +1803,21 @@ static signed char vmg_destruct_level(pTHX) { const char *s = PerlEnv_getenv("PERL_DESTRUCT_LEVEL"); if (s) { int i; -#if VMG_HAS_PERL(5, 21, 3) +#if XSH_HAS_PERL(5, 21, 3) if (strEQ(s, "-1")) { i = -1; } else { -# if VMG_HAS_PERL(5, 21, 10) +# if XSH_HAS_PERL(5, 21, 10) UV uv; if (Perl_grok_atoUV(s, &uv, NULL) && uv <= INT_MAX) i = (int) uv; else i = 0; -# else /* VMG_HAS_PERL(5, 21, 3) && !VMG_HAS_PERL(5, 21, 10) */ +# else /* XSH_HAS_PERL(5, 21, 3) && !XSH_HAS_PERL(5, 21, 10) */ i = Perl_grok_atou(s, NULL); # endif } -#else /* !VMG_HAS_PERL(5, 21, 3) */ +#else /* !XSH_HAS_PERL(5, 21, 3) */ i = atoi(s); #endif if (lvl < i) @@ -1886,74 +1829,35 @@ static signed char vmg_destruct_level(pTHX) { return lvl; } -#endif /* VMG_THREADSAFE */ - -static void vmg_teardown(pTHX_ void *param) { - dMY_CXT; - -#if VMG_THREADSAFE - VMG_LOADED_LOCK; +#endif /* XSH_THREADSAFE */ - if (vmg_loaded == 1) { - vmg_loaded = 0; - if (vmg_destruct_level() == 0) { - vmg_global_teardown_late_locked(); - } else { - if (!PL_strtab) - PL_strtab = newHV(); - vmg_sv_magicext((SV *) PL_strtab, NULL, &vmg_global_teardown_vtbl, NULL, 0); - } - } else { - VMG_ASSERT(vmg_loaded > 1); - --vmg_loaded; - } - - VMG_LOADED_UNLOCK; +static void xsh_user_global_setup(pTHX) { +#if XSH_THREADSAFE + MUTEX_INIT(&vmg_vtable_refcount_mutex); + MUTEX_INIT(&vmg_op_name_init_mutex); #endif - if (MY_CXT.depth == 0 && MY_CXT.freed_tokens) { - vmg_magic_chain_free(MY_CXT.freed_tokens, NULL); - MY_CXT.freed_tokens = NULL; - } - return; } -static void vmg_setup(pTHX) { -#define vmg_setup() vmg_setup(aTHX) +static void xsh_user_local_setup(pTHX_ xsh_user_cxt_t *cxt) { HV *stash; int c; - MY_CXT_INIT; - -#if VMG_THREADSAFE - VMG_LOADED_LOCK; - - if (vmg_loaded == 0) { - MUTEX_INIT(&vmg_vtable_refcount_mutex); - MUTEX_INIT(&vmg_op_name_init_mutex); - vmg_loaded = 1; - } else { - VMG_ASSERT(vmg_loaded > 0); - ++vmg_loaded; - } - - VMG_LOADED_UNLOCK; -#endif for (c = OPc_NULL; c < OPc_MAX; ++c) - MY_CXT.b__op_stashes[c] = NULL; + cxt->b__op_stashes[c] = NULL; - MY_CXT.depth = 0; - MY_CXT.freed_tokens = NULL; + cxt->depth = 0; + cxt->freed_tokens = NULL; #if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE - vmg_trampoline_init(&MY_CXT.propagate_errsv, vmg_pp_propagate_errsv); + vmg_trampoline_init(&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); + vmg_trampoline_init(&cxt->reset_rmg, vmg_pp_reset_rmg); #endif - stash = gv_stashpv(__PACKAGE__, 1); + stash = gv_stashpv(XSH_PACKAGE, 1); newCONSTSUB(stash, "MGf_COPY", newSVuv(MGf_COPY)); newCONSTSUB(stash, "MGf_DUP", newSVuv(MGf_DUP)); newCONSTSUB(stash, "MGf_LOCAL", newSVuv(MGf_LOCAL)); @@ -1975,13 +1879,31 @@ static void vmg_setup(pTHX) { 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)); - newCONSTSUB(stash, "VMG_FORKSAFE", newSVuv(VMG_FORKSAFE)); + newCONSTSUB(stash, "VMG_PERL_PATCHLEVEL", newSVuv(XSH_PERL_PATCHLEVEL)); + newCONSTSUB(stash, "VMG_THREADSAFE", newSVuv(XSH_THREADSAFE)); + newCONSTSUB(stash, "VMG_FORKSAFE", newSVuv(XSH_FORKSAFE)); newCONSTSUB(stash, "VMG_OP_INFO_NAME", newSVuv(VMG_OP_INFO_NAME)); newCONSTSUB(stash, "VMG_OP_INFO_OBJECT", newSVuv(VMG_OP_INFO_OBJECT)); - call_atexit(vmg_teardown, NULL); + return; +} + +static void xsh_user_local_teardown(pTHX_ xsh_user_cxt_t *cxt) { + if (cxt->depth == 0 && cxt->freed_tokens) { + vmg_magic_chain_free(cxt->freed_tokens, NULL); + cxt->freed_tokens = NULL; + } + + return; +} + +static void xsh_user_global_teardown(pTHX) { +#if XSH_THREADSAFE + if (vmg_destruct_level() == 0) + vmg_global_teardown_late_locked(NULL); + else + xsh_teardown_late_register(vmg_global_teardown_late_locked, NULL); +#endif return; } @@ -2037,43 +1959,19 @@ PROTOTYPES: ENABLE BOOT: { - vmg_setup(); + xsh_setup(); } -#if VMG_THREADSAFE +#if XSH_THREADSAFE void CLONE(...) PROTOTYPE: DISABLE -PREINIT: - U32 had_b__op_stash = 0; - I32 old_depth; - int c; PPCODE: - { - dMY_CXT; - for (c = OPc_NULL; c < OPc_MAX; ++c) { - if (MY_CXT.b__op_stashes[c]) - had_b__op_stash |= (((U32) 1) << c); - } - old_depth = MY_CXT.depth; - } - { - MY_CXT_CLONE; - 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; - } - MY_CXT.depth = old_depth; - MY_CXT.freed_tokens = NULL; - VMG_LOADED_LOCK; - VMG_ASSERT(vmg_loaded > 0); - ++vmg_loaded; - VMG_LOADED_UNLOCK; - } + xsh_clone(); XSRETURN(0); -#endif /* VMG_THREADSAFE */ +#endif /* XSH_THREADSAFE */ SV *_wizard(...) PROTOTYPE: DISABLE