X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=xs-src%2FMouse.xs;h=1b124c7c21e6abd6665847d0cf38f028881a5dae;hb=f1575d9f6d73252e751770a6c7ac717237059f29;hp=955ab2f8926a1da41fc0b4b8310b1f3a435f5f13;hpb=b3cd4c14b73eb0160d29f7d76828de0060c0b522;p=gitmo%2FMouse.git diff --git a/xs-src/Mouse.xs b/xs-src/Mouse.xs index 955ab2f..1b124c7 100644 --- a/xs-src/Mouse.xs +++ b/xs-src/Mouse.xs @@ -49,58 +49,47 @@ enum mouse_modifier_t { static MGVTBL mouse_xc_vtbl; /* for identity */ -static void -mouse_class_push_attribute_list(pTHX_ SV* const metaclass, AV* const attrall, HV* const seen){ - dSP; - I32 n; - - /* $meta->get_attribute_list */ - PUSHMARK(SP); - XPUSHs(metaclass); - PUTBACK; - - n = call_sv(mouse_get_attribute_list, G_ARRAY | G_METHOD); - for(NOOP; n > 0; n--){ - SV* name; - - SPAGAIN; - name = POPs; - PUTBACK; - - if(hv_exists_ent(seen, name, 0U)){ - continue; - } - (void)hv_store_ent(seen, name, &PL_sv_undef, 0U); +HV* +mouse_get_namespace(pTHX_ SV* const meta) { + SV* const package = get_slot(meta, mouse_package); + if(!(package && SvOK(package))){ + croak("No package name defined for metaclass"); + } + return gv_stashsv(package, GV_ADDMULTI); +} - av_push(attrall, newSVsv( mcall1(metaclass, mouse_get_attribute, name) )); +static AV* +mouse_calculate_all_attributes(pTHX_ SV* const metaclass) { + SV* const avref = mcall0s(metaclass, "_calculate_all_attributes"); + if(!(SvROK(avref) && SvTYPE(SvRV(avref)) == SVt_PVAV)) { + croak("$meta->_calculate_all_attributes did not return an ARRAY reference"); } + return (AV*)SvRV(avref); } +XS(XS_Mouse__Object_BUILDARGS); /* prototype */ + static int mouse_class_has_custom_buildargs(pTHX_ HV* const stash) { - XS(XS_Mouse__Object_BUILDARGS); /* prototype */ - GV* const buildargs = gv_fetchmeth_autoload(stash, "BUILDARGS", sizeof("BUILDARGS")-1, 0); return buildargs && CvXSUB(GvCV(buildargs)) != XS_Mouse__Object_BUILDARGS; } -static void -mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stash, AV* const xc) { +static AV* +mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, AV* const xc) { + HV* const stash = MOUSE_xc_stash(xc); AV* const linearized_isa = mro_get_linear_isa(stash); - I32 const len = AvFILLp(linearized_isa); + I32 const len = AvFILLp(linearized_isa) + 1; I32 i; U32 flags = 0x00; - AV* const attrall = newAV(); AV* const buildall = newAV(); AV* const demolishall = newAV(); - HV* const seen = newHV(); /* for attributes */ + AV* attrall; ENTER; SAVETMPS; - sv_2mortal((SV*)seen); - /* old data will be delete at the end of the perl scope */ av_delete(xc, MOUSE_XC_DEMOLISHALL, 0x00); av_delete(xc, MOUSE_XC_BUILDALL, 0x00); @@ -111,6 +100,13 @@ mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stas /* update */ + av_store(xc, MOUSE_XC_BUILDALL, (SV*)buildall); + av_store(xc, MOUSE_XC_DEMOLISHALL, (SV*)demolishall); + + attrall = mouse_calculate_all_attributes(aTHX_ metaclass); + SvREFCNT_inc_simple_void_NN(attrall); + av_store(xc, MOUSE_XC_ATTRALL, (SV*)attrall); + if(predicate_calls(metaclass, "is_immutable")){ flags |= MOUSEf_XC_IS_IMMUTABLE; } @@ -123,19 +119,15 @@ mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stas flags |= MOUSEf_XC_HAS_BUILDARGS; } - if(predicate_calls(metaclass, "__strict_constructor")){ + if(predicate_calls(metaclass, "strict_constructor")){ flags |= MOUSEf_XC_CONSTRUCTOR_IS_STRICT; } av_store(xc, MOUSE_XC_FLAGS, newSVuv(flags)); - av_store(xc, MOUSE_XC_ATTRALL, (SV*)attrall); - av_store(xc, MOUSE_XC_BUILDALL, (SV*)buildall); - av_store(xc, MOUSE_XC_DEMOLISHALL, (SV*)demolishall); for(i = 0; i < len; i++){ SV* const klass = MOUSE_av_at(linearized_isa, i); HV* const st = gv_stashsv(klass, TRUE); - SV* meta; GV* gv; gv = stash_fetchs(st, "BUILD", FALSE); @@ -148,27 +140,18 @@ mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stas if(gv && GvCVu(gv)){ av_push(demolishall, newRV_inc((SV*)GvCV(gv))); } - - /* ATTRIBUTES */ - meta = get_metaclass(klass); - if(!SvOK(meta)){ - continue; /* skip non-Mouse classes */ - } - - mouse_class_push_attribute_list(aTHX_ meta, attrall, seen); } FREETMPS; LEAVE; sv_setuv(MOUSE_xc_gen(xc), mro_get_pkg_gen(stash)); + return xc; } static AV* -mouse_get_xc(pTHX_ SV* const metaclass) { +mouse_get_xc_wo_check(pTHX_ SV* const metaclass) { AV* xc; - SV* gen; - HV* stash; MAGIC* mg; if(!IsObject(metaclass)){ @@ -177,21 +160,18 @@ mouse_get_xc(pTHX_ SV* const metaclass) { mg = mouse_mg_find(aTHX_ SvRV(metaclass), &mouse_xc_vtbl, 0x00); if(!mg){ - SV* const package = get_slot(metaclass, mouse_package); - STRLEN len; - const char* const pv = SvPV_const(package, len); - - stash = gv_stashpvn(pv, len, TRUE); + /* cache stash for performance */ + HV* const stash = mouse_get_namespace(aTHX_ metaclass); xc = newAV(); - mg = sv_magicext(SvRV(metaclass), (SV*)xc, PERL_MAGIC_ext, &mouse_xc_vtbl, pv, len); + mg = sv_magicext(SvRV(metaclass), (SV*)xc, PERL_MAGIC_ext, + &mouse_xc_vtbl, NULL, 0); SvREFCNT_dec(xc); /* refcnt++ in sv_magicext */ av_extend(xc, MOUSE_XC_last - 1); av_store(xc, MOUSE_XC_GEN, newSVuv(0U)); av_store(xc, MOUSE_XC_STASH, (SV*)stash); - SvREFCNT_inc_simple_void_NN(stash); } else{ @@ -200,20 +180,33 @@ mouse_get_xc(pTHX_ SV* const metaclass) { assert(xc); assert(SvTYPE(xc) == SVt_PVAV); } + return xc; +} - gen = MOUSE_xc_gen(xc); - - if(SvUVX(gen) != 0U && MOUSE_xc_flags(xc) & MOUSEf_XC_IS_IMMUTABLE){ - return xc; +static int +mouse_xc_is_fresh(pTHX_ AV* const xc) { + HV* const stash = MOUSE_xc_stash(xc); + SV* const gen = MOUSE_xc_gen(xc); + if(SvUVX(gen) != 0U && MOUSE_xc_flags(xc) & MOUSEf_XC_IS_IMMUTABLE) { + return TRUE; } + return SvUVX(gen) == mro_get_pkg_gen(stash); +} - stash = MOUSE_xc_stash(xc); - - if(SvUVX(gen) != mro_get_pkg_gen(stash)){ - mouse_class_update_xc(aTHX_ metaclass, stash, xc); - } +STATIC_INLINE AV* +mouse_get_xc(pTHX_ SV* const metaclass) { + AV* const xc = mouse_get_xc_wo_check(aTHX_ metaclass); + return mouse_xc_is_fresh(aTHX_ xc) + ? xc + : mouse_class_update_xc(aTHX_ metaclass, xc); +} - return xc; +static AV* +mouse_get_xc_if_fresh(pTHX_ SV* const metaclass) { + AV* const xc = mouse_get_xc_wo_check(aTHX_ metaclass); + return mouse_xc_is_fresh(aTHX_ xc) + ? xc + : NULL; } static HV* @@ -236,13 +229,12 @@ mouse_buildargs(pTHX_ SV* metaclass, SV* const klass, I32 ax, I32 items) { else{ I32 i; - args = newHV_mortal(); - if( (items % 2) != 0 ){ if(!metaclass){ metaclass = get_metaclass(klass); } mouse_throw_error(metaclass, NULL, "Odd number of parameters to new()"); } + args = newHV_mortal(); for(i = 0; i < items; i += 2){ (void)hv_store_ent(args, ST(i), newSVsv(ST(i+1)), 0U); } @@ -291,10 +283,10 @@ mouse_report_unknown_args(pTHX_ SV* const meta, AV* const attrs, HV* const args) static void -mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const args, bool const ignore_triggers) { +mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const args, bool const is_cloning) { AV* const xc = mouse_get_xc(aTHX_ meta); AV* const attrs = MOUSE_xc_attrall(xc); - I32 len = AvFILLp(attrs) + 1; + I32 const len = AvFILLp(attrs) + 1; I32 i; AV* triggers_queue = NULL; I32 used = 0; @@ -307,10 +299,6 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const croak("You cannot use tied HASH reference as initializing arguments"); } - if(!ignore_triggers){ - triggers_queue = newAV_mortal(); - } - /* for each attribute */ for(i = 0; i < len; i++){ SV* const attr = MOUSE_av_at(attrs, i); @@ -327,36 +315,50 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const value = mouse_xa_apply_type_constraint(aTHX_ xa, value, flags); } value = set_slot(object, slot, value); - if(SvROK(value) && flags & MOUSEf_ATTR_IS_WEAK_REF){ + if(flags & MOUSEf_ATTR_IS_WEAK_REF && SvROK(value)){ weaken_slot(object, slot); } - if(flags & MOUSEf_ATTR_HAS_TRIGGER && triggers_queue){ + if(flags & MOUSEf_ATTR_HAS_TRIGGER){ AV* const pair = newAV(); av_push(pair, newSVsv( mcall0s(attr, "trigger") )); av_push(pair, newSVsv(value)); + if(!triggers_queue) { + triggers_queue = newAV_mortal(); + } av_push(triggers_queue, (SV*)pair); } used++; } else { /* no init arg */ if(flags & (MOUSEf_ATTR_HAS_DEFAULT | MOUSEf_ATTR_HAS_BUILDER)){ - if(!(flags & MOUSEf_ATTR_IS_LAZY)){ + /* skip if the object has the slot (it occurs on cloning/reblessing) */ + if(!(flags & MOUSEf_ATTR_IS_LAZY) && !has_slot(object, slot)){ mouse_xa_set_default(aTHX_ xa, object); } } + else if(is_cloning) { + if(flags & MOUSEf_ATTR_IS_WEAK_REF){ + SV* const value = get_slot(object, slot); + if(SvROK(value)) { + weaken_slot(object, slot); + } + } + } + /* don't check "required" while cloning (or reblesseing) */ else if(flags & MOUSEf_ATTR_IS_REQUIRED) { mouse_throw_error(attr, NULL, "Attribute (%"SVf") is required", slot); } } } /* for each attribute */ - if(MOUSE_xc_flags(xc) & MOUSEf_XC_CONSTRUCTOR_IS_STRICT && used < HvUSEDKEYS(args)){ + if(MOUSE_xc_flags(xc) & MOUSEf_XC_CONSTRUCTOR_IS_STRICT + && used < (I32)HvUSEDKEYS(args)){ mouse_report_unknown_args(aTHX_ meta, attrs, args); } if(triggers_queue){ - len = AvFILLp(triggers_queue) + 1; + I32 const len = AvFILLp(triggers_queue) + 1; for(i = 0; i < len; i++){ AV* const pair = (AV*)AvARRAY(triggers_queue)[i]; SV* const trigger = AvARRAY(pair)[0]; @@ -369,18 +371,16 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const if(MOUSE_xc_flags(xc) & MOUSEf_XC_IS_ANON){ (void)set_slot(object, newSVpvs_flags("__METACLASS__", SVs_TEMP), meta); } - } -static SV* +STATIC_INLINE SV* mouse_initialize_metaclass(pTHX_ SV* const klass) { - SV* meta = get_metaclass(klass); - - if(!SvOK(meta)){ - meta = mcall1s(newSVpvs_flags("Mouse::Meta::Class", SVs_TEMP), "initialize", klass); + SV* const meta = get_metaclass(klass); + if(LIKELY(SvOK(meta))){ + return meta; } - - return meta; + return mcall1s(newSVpvs_flags("Mouse::Meta::Class", SVs_TEMP), + "initialize", klass); } static void @@ -444,11 +444,27 @@ mouse_get_modifier_storage(pTHX_ return (AV*)SvRV(storage_ref); } +static +XSPROTO(XS_Mouse_value_holder) { + dVAR; dXSARGS; + SV* const value = (SV*)XSANY.any_ptr; + assert(value); + PERL_UNUSED_VAR(items); + ST(0) = value; + XSRETURN(1); +} + +DECL_BOOT(Mouse__Util); +DECL_BOOT(Mouse__Util__TypeConstraints); +DECL_BOOT(Mouse__Meta__Method__Accessor__XS); +DECL_BOOT(Mouse__Meta__Attribute); + MODULE = Mouse PACKAGE = Mouse PROTOTYPES: DISABLE BOOT: +{ mouse_package = newSVpvs_share("package"); mouse_namespace = newSVpvs_share("namespace"); mouse_methods = newSVpvs_share("methods"); @@ -458,11 +474,11 @@ BOOT: mouse_get_attribute = newSVpvs_share("get_attribute"); mouse_get_attribute_list = newSVpvs_share("get_attribute_list"); - MOUSE_CALL_BOOT(Mouse__Util); - MOUSE_CALL_BOOT(Mouse__Util__TypeConstraints); - MOUSE_CALL_BOOT(Mouse__Meta__Method__Accessor__XS); - MOUSE_CALL_BOOT(Mouse__Meta__Attribute); - + CALL_BOOT(Mouse__Util); + CALL_BOOT(Mouse__Util__TypeConstraints); + CALL_BOOT(Mouse__Meta__Method__Accessor__XS); + CALL_BOOT(Mouse__Meta__Attribute); +} MODULE = Mouse PACKAGE = Mouse::Meta::Module @@ -475,11 +491,7 @@ HV* namespace(SV* self) CODE: { - SV* const package = get_slot(self, mouse_package); - if(!(package && SvOK(package))){ - croak("No package name defined"); - } - RETVAL = gv_stashsv(package, GV_ADDMULTI); + RETVAL = mouse_get_namespace(aTHX_ self); } OUTPUT: RETVAL @@ -513,42 +525,49 @@ CODE: /* *{$package . '::' . $name} -> *gv */ gv = gv_fetchpv(form("%"SVf"::%"SVf, package, name), GV_ADDMULTI, SVt_PVCV); mouse_install_sub(aTHX_ gv, code_ref); - //CvMETHOD_on((CV*)SvRV(code_ref)); + /* CvMETHOD_on((CV*)SvRV(code_ref)); */ (void)set_slot(methods, name, code); /* $self->{methods}{$name} = $code */ } MODULE = Mouse PACKAGE = Mouse::Meta::Class BOOT: +{ + CV* xsub; + INSTALL_SIMPLE_READER(Class, roles); INSTALL_SIMPLE_PREDICATE_WITH_KEY(Class, is_anon_class, anon_serial_id); INSTALL_SIMPLE_READER(Class, is_immutable); - INSTALL_SIMPLE_READER_WITH_KEY(Class, __strict_constructor, strict_constructor); + + INSTALL_INHERITABLE_CLASS_ACCESSOR(strict_constructor); INSTALL_CLASS_HOLDER(Class, method_metaclass, "Mouse::Meta::Method"); INSTALL_CLASS_HOLDER(Class, attribute_metaclass, "Mouse::Meta::Attribute"); INSTALL_CLASS_HOLDER(Class, constructor_class, "Mouse::Meta::Method::Constructor::XS"); INSTALL_CLASS_HOLDER(Class, destructor_class, "Mouse::Meta::Method::Destructor::XS"); - newCONSTSUB(gv_stashpvs("Mouse::Meta::Method::Constructor::XS", TRUE), "_generate_constructor", - newRV_inc((SV*)get_cvs("Mouse::Object::new", TRUE))); - newCONSTSUB(gv_stashpvs("Mouse::Meta::Method::Destructor::XS", TRUE), "_generate_destructor", - newRV_inc((SV*)get_cvs("Mouse::Object::DESTROY", TRUE))); + xsub = newXS("Mouse::Meta::Method::Constructor::XS::_generate_constructor", + XS_Mouse_value_holder, file); + CvXSUBANY(xsub).any_ptr + = newRV_inc((SV*)get_cvs("Mouse::Object::new", GV_ADD)); + + xsub = newXS("Mouse::Meta::Method::Destructor::XS::_generate_destructor", + XS_Mouse_value_holder, file); + CvXSUBANY(xsub).any_ptr + = newRV_inc((SV*)get_cvs("Mouse::Object::DESTROY", GV_ADD)); +} void linearized_isa(SV* self) PPCODE: { - SV* const stash_ref = mcall0(self, mouse_namespace); /* $self->namespace */ - AV* linearized_isa; - I32 len; + /* MOUSE_xc_stash() is not available because the xc system depends on + linearized_isa() */ + HV* const stash = mouse_get_namespace(aTHX_ self); + AV* const linearized_isa = mro_get_linear_isa(stash); + I32 const len = AvFILLp(linearized_isa) + 1; I32 i; - if(!(SvROK(stash_ref) && SvTYPE(SvRV(stash_ref)) == SVt_PVHV)){ - croak("namespace() didn't return a HASH reference"); - } - linearized_isa = mro_get_linear_isa((HV*)SvRV(stash_ref)); - len = AvFILLp(linearized_isa) + 1; EXTEND(SP, len); for(i = 0; i < len; i++){ PUSHs(AvARRAY(linearized_isa)[i]); @@ -570,26 +589,61 @@ PPCODE: } } -SV* +void new_object(SV* meta, ...) CODE: { AV* const xc = mouse_get_xc(aTHX_ meta); HV* const args = mouse_buildargs(aTHX_ meta, NULL, ax, items); + SV* object; - RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); - mouse_class_initialize_object(aTHX_ meta, RETVAL, args, FALSE); + object = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); + mouse_class_initialize_object(aTHX_ meta, object, args, FALSE); + mouse_buildall(aTHX_ xc, object, sv_2mortal(newRV_inc((SV*)args))); + ST(0) = object; /* because object is mortal, we should return it as is */ + XSRETURN(1); } -OUTPUT: - RETVAL void -_initialize_object(SV* meta, SV* object, HV* args, bool ignore_triggers = FALSE) +clone_object(SV* meta, SV* object, ...) +CODE: +{ + AV* const xc = mouse_get_xc(aTHX_ meta); + HV* const args = mouse_buildargs(aTHX_ meta, NULL, ax + 1, items - 1); + SV* proto; + + if(!mouse_is_an_instance_of(aTHX_ MOUSE_xc_stash(xc), object)) { + mouse_throw_error(meta, object, + "You must pass an instance of the metaclass (%"SVf"), not (%"SVf")", + mcall0(meta, mouse_name), object); + } + + proto = mouse_instance_clone(aTHX_ object); + mouse_class_initialize_object(aTHX_ meta, proto, args, TRUE); + ST(0) = proto; /* because object is mortal, we should return it as is */ + XSRETURN(1); +} + +void +_initialize_object(SV* meta, SV* object, HV* args, bool is_cloning = FALSE) CODE: { - mouse_class_initialize_object(aTHX_ meta, object, args, ignore_triggers); + mouse_class_initialize_object(aTHX_ meta, object, args, is_cloning); } +void +_invalidate_metaclass_cache(SV* meta) +CODE: +{ + AV* const xc = mouse_get_xc_if_fresh(aTHX_ meta); + if(xc) { + SV* const gen = MOUSE_xc_gen(xc); + sv_setuv(gen, 0U); + } + delete_slot(meta, newSVpvs_flags("_mouse_cache_", SVs_TEMP)); +} + + MODULE = Mouse PACKAGE = Mouse::Meta::Role BOOT: @@ -602,7 +656,7 @@ void add_before_modifier(SV* self, SV* name, SV* modifier) CODE: { - av_push(mouse_get_modifier_storage(aTHX_ self, ix, name), newSVsv(modifier)); + av_push(mouse_get_modifier_storage(aTHX_ self, (enum mouse_modifier_t)ix, name), newSVsv(modifier)); } ALIAS: add_before_method_modifier = MOUSE_M_BEFORE @@ -617,7 +671,8 @@ ALIAS: get_after_method_modifiers = MOUSE_M_AFTER PPCODE: { - AV* const storage = mouse_get_modifier_storage(aTHX_ self, ix, name); + AV* const storage = mouse_get_modifier_storage(aTHX_ self, + (enum mouse_modifier_t)ix, name); I32 const len = av_len(storage) + 1; if(GIMME_V == G_ARRAY) { I32 i; @@ -631,9 +686,21 @@ PPCODE: } } +void +add_metaclass_accessor(SV* self, SV* name) +CODE: +{ + SV* const klass = mcall0(self, mouse_name); + const char* fq_name = form("%"SVf"::%"SVf, klass, name); + STRLEN keylen; + const char* const key = SvPV_const(name, keylen); + mouse_simple_accessor_generate(aTHX_ fq_name, key, keylen, + XS_Mouse_inheritable_class_accessor, NULL, 0); +} + MODULE = Mouse PACKAGE = Mouse::Object -SV* +void new(SV* klass, ...) CODE: { @@ -641,6 +708,7 @@ CODE: AV* const xc = mouse_get_xc(aTHX_ meta); UV const flags = MOUSE_xc_flags(xc); SV* args; + SV* object; /* BUILDARGS */ if(flags & MOUSEf_XC_HAS_BUILDARGS){ @@ -670,13 +738,13 @@ CODE: } /* new_object */ - RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); - mouse_class_initialize_object(aTHX_ meta, RETVAL, (HV*)SvRV(args), FALSE); - - mouse_buildall(aTHX_ xc, RETVAL, args); + object = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); + mouse_class_initialize_object(aTHX_ meta, object, (HV*)SvRV(args), FALSE); + /* BUILDALL */ + mouse_buildall(aTHX_ xc, object, args); + ST(0) = object; /* because object is mortal, we should return it as is */ + XSRETURN(1); } -OUTPUT: - RETVAL void DESTROY(SV* object) @@ -686,17 +754,17 @@ ALIAS: CODE: { SV* const meta = get_metaclass(object); + AV* xc; AV* demolishall; - I32 len, i; + I32 len; + I32 i; if(!IsObject(object)){ croak("You must not call %s as a class method", ix == 0 ? "DESTROY" : "DEMOLISHALL"); } - if(SvOK(meta)){ - AV* const xc = mouse_get_xc(aTHX_ meta); - + if(SvOK(meta) && (xc = mouse_get_xc_if_fresh(aTHX_ meta))) { demolishall = MOUSE_xc_demolishall(xc); } else { /* The metaclass is already destroyed */ @@ -715,14 +783,12 @@ CODE: } } - len = AvFILLp(demolishall) + 1; + len = AvFILLp(demolishall) + 1; if(len > 0){ - GV* const statusvalue = gv_fetchpvs("?", 0, SVt_PV); + SV* const in_global_destruction = boolSV(PL_dirty); + SAVEI32(PL_statusvalue); /* local $? */ + PL_statusvalue = 0; - if(statusvalue){ /* it can be NULL */ - SAVESPTR(GvSV(statusvalue)); /* local $? */ - GvSV(statusvalue) = sv_newmortal(); - } SAVESPTR(ERRSV); /* local $@ */ ERRSV = sv_newmortal(); @@ -733,7 +799,7 @@ CODE: PUSHMARK(SP); PUSHs(object); - PUSHs(boolSV(PL_dirty)); + PUSHs(in_global_destruction); PUTBACK; call_sv(AvARRAY(demolishall)[i], G_VOID | G_EVAL);