X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=xs-src%2FMouse.xs;h=27f871c8d32831f1c970ccaa9195176127c18b95;hb=3001d9acb5b99317145fbef8785855161a128f04;hp=e5670b26043718387e386797091717100ad30dca;hpb=074a414dea92037837ef040f5b0c0e75d0c075a0;p=gitmo%2FMouse.git diff --git a/xs-src/Mouse.xs b/xs-src/Mouse.xs index e5670b2..27f871c 100644 --- a/xs-src/Mouse.xs +++ b/xs-src/Mouse.xs @@ -150,7 +150,7 @@ mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stas sv_setuv(MOUSE_xc_gen(xc), mro_get_pkg_gen(stash)); } -AV* +static AV* mouse_get_xc(pTHX_ SV* const metaclass) { AV* xc; SV* gen; @@ -175,7 +175,7 @@ mouse_get_xc(pTHX_ SV* const metaclass) { av_extend(xc, MOUSE_XC_last - 1); - av_store(xc, MOUSE_XC_GEN, newSViv(0)); + av_store(xc, MOUSE_XC_GEN, newSVuv(0U)); av_store(xc, MOUSE_XC_STASH, (SV*)stash); SvREFCNT_inc_simple_void_NN(stash); @@ -188,16 +188,21 @@ mouse_get_xc(pTHX_ SV* const metaclass) { } gen = MOUSE_xc_gen(xc); + + if(SvUVX(gen) != 0U && MOUSE_xc_flags(xc) & MOUSEf_XC_IS_IMMUTABLE){ + return xc; + } + stash = MOUSE_xc_stash(xc); - if(SvUV(gen) != mro_get_pkg_gen(stash)){ + if(SvUVX(gen) != mro_get_pkg_gen(stash)){ mouse_class_update_xc(aTHX_ metaclass, stash, xc); } return xc; } -HV* +static HV* mouse_buildargs(pTHX_ SV* metaclass, SV* const klass, I32 ax, I32 items) { HV* args; @@ -232,7 +237,7 @@ mouse_buildargs(pTHX_ SV* metaclass, SV* const klass, I32 ax, I32 items) { return args; } -void +static void mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const args, bool const ignore_triggers) { AV* const xc = mouse_get_xc(aTHX_ meta); AV* const attrs = MOUSE_xc_attrall(xc); @@ -308,6 +313,28 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const LEAVE; } +static SV* +mouse_initialize_metaclass(pTHX_ SV* const klass) { + SV* meta = get_metaclass(klass); + + if(!SvOK(meta)){ + dSP; + PUSHMARK(SP); + + EXTEND(SP, 2); + mPUSHp("Mouse::Meta::Class", sizeof("Mouse::Meta::Class")-1); + PUSHs(klass); + PUTBACK; + + call_method("initialize", G_SCALAR); + SPAGAIN; + meta = POPs; + PUTBACK; + } + + return meta; +} + MODULE = Mouse PACKAGE = Mouse PROTOTYPES: DISABLE @@ -392,14 +419,16 @@ CODE: set_slot(methods, name, code); /* $self->{methods}{$name} = $code */ - /* TODO: name the CODE ref if it's anonymous */ - //code_entity = (CV*)SvRV(code_ref); - //if(CvANON(code_entity) - // && CvGV(code_entity) /* a cv under construction has no gv */ ){ + /* name the CODE ref if it's anonymous */ + { + CV* const code_entity = (CV*)SvRV(code_ref); + if(CvANON(code_entity) + && CvGV(code_entity) /* a cv under construction has no gv */ ){ - // CvGV(code_entity) = gv; - // CvANON_off(code_entity); - //} + CvGV(code_entity) = gv; + CvANON_off(code_entity); + } + } } MODULE = Mouse PACKAGE = Mouse::Meta::Class @@ -407,6 +436,17 @@ MODULE = Mouse PACKAGE = Mouse::Meta::Class BOOT: INSTALL_SIMPLE_READER(Class, roles); INSTALL_SIMPLE_PREDICATE_WITH_KEY(Class, is_anon_class, anon_serial_id); + newCONSTSUB(gv_stashpvs("Mouse::Meta::Class", TRUE), "constructor_class", + newSVpvs("Mouse::Meta::Method::Constructor::XS")); + newCONSTSUB(gv_stashpvs("Mouse::Meta::Class", TRUE), "destructor_class", + newSVpvs("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))); + void linearized_isa(SV* self) @@ -483,11 +523,11 @@ SV* new(SV* klass, ...) CODE: { - SV* const meta = get_metaclass(klass); + SV* const meta = mouse_initialize_metaclass(aTHX_ klass); AV* const xc = mouse_get_xc(aTHX_ meta); UV const flags = MOUSE_xc_flags(xc); SV* args; - AV* av; + AV* buildall; I32 len, i; /* BUILDARGS */ @@ -520,8 +560,8 @@ CODE: mouse_class_initialize_object(aTHX_ meta, RETVAL, (HV*)SvRV(args), FALSE); /* BUILDALL */ - av = MOUSE_xc_buildall(xc); - len = AvFILLp(av) + 1; + buildall = MOUSE_xc_buildall(xc); + len = AvFILLp(buildall) + 1; for(i = 0; i < len; i++){ dSP; @@ -531,12 +571,76 @@ CODE: PUSHs(args); PUTBACK; - call_sv(AvARRAY(av)[i], G_VOID | G_DISCARD); + call_sv(AvARRAY(buildall)[i], G_VOID | G_DISCARD); } } OUTPUT: RETVAL +void +DESTROY(SV* object) +CODE: +{ + SV* const meta = get_metaclass(object); + AV* demolishall; + I32 len, i; + + if(!IsObject(object)){ + croak("You must not call DESTROY as a class method"); + } + + if(SvOK(meta)){ + AV* const xc = mouse_get_xc(aTHX_ meta); + + demolishall = MOUSE_xc_demolishall(xc); + } + else { + AV* const linearized_isa = mro_get_linear_isa(SvSTASH(SvRV(object))); + + len = AvFILLp(linearized_isa) + 1; + + demolishall = newAV_mortal(); + for(i = 0; i < len; i++){ + SV* const klass = MOUSE_av_at(linearized_isa, i); + HV* const st = gv_stashsv(klass, TRUE); + GV* const gv = stash_fetchs(st, "DEMOLISH", FALSE); + if(gv && GvCVu(gv)){ + av_push(demolishall, newRV_inc((SV*)GvCV(gv))); + } + } + } + + /* DEMOLISHALL */ + len = AvFILLp(demolishall) + 1; + if(len > 0){ + GV* const statusvalue = gv_fetchpvs("?", 0, SVt_PV); + SAVESPTR(GvSV(statusvalue)); /* local $? */ + SAVESPTR(ERRSV); /* local $@ */ + + GvSV(statusvalue) = sv_2mortal(newSViv(0)); + ERRSV = sv_2mortal(newSVpvs("")); + for(i = 0; i < len; i++){ + dSP; + + PUSHMARK(SP); + XPUSHs(object); + PUTBACK; + + call_sv(AvARRAY(demolishall)[i], G_VOID | G_DISCARD | G_EVAL); + if(SvTRUE(ERRSV)){ + SV* const e = newSVsv(ERRSV); + + FREETMPS; + LEAVE; + + sv_setsv(ERRSV, e); + SvREFCNT_dec(e); + croak(NULL); /* rethrow */ + } + } + } +} + HV* BUILDARGS(SV* klass, ...) CODE: @@ -545,3 +649,5 @@ CODE: } OUTPUT: RETVAL + +