From: gfx Date: Wed, 4 Nov 2009 06:57:36 +0000 (+0900) Subject: Refactor XS metaclass object structure X-Git-Tag: 0.40_06~26 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMouse.git;a=commitdiff_plain;h=a39e954129372fa75494ba57ea876c35f91b1457;hp=0d615023d82778635c398300ecc6b518c35d4408 Refactor XS metaclass object structure --- diff --git a/mouse.h b/mouse.h index 662e227..a7a5986 100644 --- a/mouse.h +++ b/mouse.h @@ -72,9 +72,18 @@ bool mouse_is_class_loaded(pTHX_ SV*); #define mcall0s(invocant, m) mcall0((invocant), sv_2mortal(newSVpvs_share(m))) #define mcall1s(invocant, m, arg1) mcall1((invocant), sv_2mortal(newSVpvs_share(m)), (arg1)) +#define get_metaclass_by_name(name) mouse_get_metaclass_by_name(aTHX_ name) + SV* mouse_call0(pTHX_ SV *const self, SV *const method); SV* mouse_call1(pTHX_ SV *const self, SV *const method, SV* const arg1); +SV* mouse_get_metaclass_by_name(pTHX_ SV* const metaclass_name); + +GV* mouse_stash_fetch(pTHX_ HV* const stash, const char* const name, I32 const namelen, I32 const create); +#define stash_fetch(s, n, l, c) mouse_stash_fetch(aTHX_ (s), (n), (l), (c)) +#define stash_fetchs(s, n, c) mouse_stash_fetch(aTHX_ (s), STR_WITH_LEN(n), (c)) + + #define MOUSEf_DIE_ON_FAIL 0x01 MAGIC* mouse_mg_find(pTHX_ SV* const sv, const MGVTBL* const vtbl, I32 const flags); diff --git a/xs-src/Mouse.xs b/xs-src/Mouse.xs index 4783961..0521e1d 100644 --- a/xs-src/Mouse.xs +++ b/xs-src/Mouse.xs @@ -9,97 +9,156 @@ SV* mouse_name; static SV* mouse_all_attrs_cache; static SV* mouse_all_attrs_cache_gen; -AV* -mouse_get_all_attributes(pTHX_ SV* const metaclass){ - SV* const package = get_slot(metaclass, mouse_package); - HV* const stash = gv_stashsv(package, TRUE); - UV const pkg_gen = mro_get_pkg_gen(stash); - SV* cache_gen = get_slot(metaclass, mouse_all_attrs_cache_gen); +#define MOUSE_xc_gen(a) MOUSE_av_at((a), MOUSE_XC_GEN) +#define MOUSE_xc_attrall(a) ( (AV*)MOUSE_av_at((a), MOUSE_XC_ATTRALL) ) +#define MOUSE_xc_buildall(a) ( (AV*)MOUSE_av_at((a), MOUSE_XC_BUILDALL) ) +#define MOUSE_xc_demolishall(a) ( (AV*)MOUSE_av_at((a), MOUSE_XC_DEOLISHALL) ) + +/* Mouse XS Metaclass object */ +enum mouse_xc_ix_t{ + MOUSE_XC_GEN, /* class generation */ + MOUSE_XC_ATTRALL, /* all the attributes */ + MOUSE_XC_BUILDALL, /* all the BUILD methods */ + MOUSE_XC_DEMOLISHALL, /* all the DEMOLISH methods */ + + MOUSE_XC_last +}; + +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_method("get_attribute_list", G_ARRAY); + 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); - if(!(cache_gen && pkg_gen == SvUV(cache_gen))){ /* update */ - CV* const get_metaclass = get_cvs("Mouse::Util::get_metaclass_by_name", TRUE); - AV* const all_attrs = newAV(); - SV* const get_attribute = newSVpvs_share("get_attribute"); + av_push(attrall, newSVsv( mcall1s(metaclass, "get_attribute", name) )); + } +} - AV* const linearized_isa = mro_get_linear_isa(stash); - I32 const len = AvFILLp(linearized_isa); - I32 i; - HV* seen; +static void +mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stash, AV* const xc) { + AV* const linearized_isa = mro_get_linear_isa(stash); + I32 const len = AvFILLp(linearized_isa); + I32 i; + AV* const attrall = newAV(); + AV* const buildall = newAV(); + AV* const demolishall = newAV(); + HV* const seen = newHV(); /* for attributes */ - /* warn("Update all_attrs_cache (cache_gen %d != pkg_gen %d)", (cache_gen ? (int)SvIV(cache_gen) : 0), (int)pkg_gen); //*/ + ENTER; + SAVETMPS; - ENTER; - SAVETMPS; + sv_2mortal((SV*)seen); - sv_2mortal(get_attribute); + /* 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); + av_delete(xc, MOUSE_XC_ATTRALL, 0x00); - set_slot(metaclass, mouse_all_attrs_cache, sv_2mortal(newRV_inc((SV*)all_attrs))); + SvREFCNT_inc_simple_void_NN(linearized_isa); + sv_2mortal((SV*)linearized_isa); - seen = newHV(); - sv_2mortal((SV*)seen); + /* update */ - for(i = 0; i < len; i++){ - SV* const klass = MOUSE_av_at(linearized_isa, i); - SV* meta; - I32 n; - dSP; + av_store(xc, MOUSE_XC_ATTRALL, (SV*)attrall); + av_store(xc, MOUSE_XC_BUILDALL, (SV*)buildall); + av_store(xc, MOUSE_XC_DEMOLISHALL, (SV*)demolishall); - PUSHMARK(SP); - XPUSHs(klass); - PUTBACK; + for(i = 0; i < len; i++){ + SV* const klass = MOUSE_av_at(linearized_isa, i); + SV* meta; + GV* gv; - call_sv((SV*)get_metaclass, G_SCALAR); + gv = stash_fetchs(stash, "BUILD", FALSE); + if(gv && GvCVu(gv)){ + av_push(buildall, newRV_inc((SV*)GvCV(gv))); + } - SPAGAIN; - meta = POPs; - PUTBACK; + gv = stash_fetchs(stash, "DEMOLISH", FALSE); + if(gv && GvCVu(gv)){ + av_push(demolishall, newRV_inc((SV*)GvCV(gv))); + } - if(!SvOK(meta)){ - continue; /* skip non-Mouse classes */ - } + /* ATTRIBUTES */ + meta = get_metaclass_by_name(klass); + if(!SvOK(meta)){ + continue; /* skip non-Mouse classes */ + } - /* $meta->get_attribute_list */ - PUSHMARK(SP); - XPUSHs(meta); - PUTBACK; + mouse_class_push_attribute_list(aTHX_ meta, attrall, seen); + } - n = call_method("get_attribute_list", G_ARRAY); - for(NOOP; n > 0; n--){ - SV* name; + FREETMPS; + LEAVE; - SPAGAIN; - name = POPs; - PUTBACK; + sv_setuv(MOUSE_xc_gen(xc), mro_get_pkg_gen(stash)); +} - if(hv_exists_ent(seen, name, 0U)){ - continue; - } - (void)hv_store_ent(seen, name, &PL_sv_undef, 0U); +AV* +mouse_get_xc(pTHX_ SV* const metaclass) { + AV* xc; + SV* gen; + HV* stash; + MAGIC* mg; + + if(!IsObject(metaclass)){ + croak("Not a Mouse metaclass"); + } - av_push(all_attrs, newSVsv( mcall1(meta, get_attribute, name) )); - } - } + mg = mouse_mg_find(aTHX_ SvRV(metaclass), &mouse_xc_vtbl, 0x00); + if(!mg){ + SV* const package = get_slot(metaclass, mouse_package); - if(!cache_gen){ - cache_gen = sv_newmortal(); - } - sv_setuv(cache_gen, mro_get_pkg_gen(stash)); - set_slot(metaclass, mouse_all_attrs_cache_gen, cache_gen); + stash = gv_stashsv(package, TRUE); + xc = newAV(); - FREETMPS; - LEAVE; + mg = sv_magicext(SvRV(metaclass), (SV*)xc, PERL_MAGIC_ext, &mouse_xc_vtbl, (char*)stash, HEf_SVKEY); + SvREFCNT_dec(xc); /* refcnt++ in sv_magicext */ - return all_attrs; + av_extend(xc, MOUSE_XC_last - 1); + av_store(xc, MOUSE_XC_GEN, newSViv(0)); } - else { - SV* const all_attrs_ref = get_slot(metaclass, mouse_all_attrs_cache); + else{ + stash = (HV*)MOUSE_mg_ptr(mg); + xc = (AV*)MOUSE_mg_obj(mg); - if(!IsArrayRef(all_attrs_ref)){ - croak("Not an ARRAY reference"); - } + assert(stash); + assert(SvTYPE(stash) == SVt_PVAV); - return (AV*)SvRV(all_attrs_ref); + assert(xc); + assert(SvTYPE(xc) == SVt_PVAV); } + + gen = MOUSE_xc_gen(xc); + if(SvUV(gen) != mro_get_pkg_gen(stash)){ + mouse_class_update_xc(aTHX_ metaclass, stash, xc); + } + + return xc; +} + +AV* +mouse_get_all_attributes(pTHX_ SV* const metaclass) { + AV* const xc = mouse_get_xc(aTHX_ metaclass); + return MOUSE_xc_attrall(xc); } MODULE = Mouse PACKAGE = Mouse diff --git a/xs-src/MouseAccessor.xs b/xs-src/MouseAccessor.xs index b6c11cc..d2ae129 100644 --- a/xs-src/MouseAccessor.xs +++ b/xs-src/MouseAccessor.xs @@ -6,8 +6,10 @@ } \ } STMT_END -/* Moose XS Attribute object */ +/* Mouse XS Attribute object */ enum mouse_xa_ix_t{ + MOUSE_XA_SLOT, /* for constructors, sync to mg_obj */ + MOUSE_XA_FLAGS, /* for constructors, sync to mg_private */ MOUSE_XA_ATTRIBUTE, MOUSE_XA_TC, MOUSE_XA_TC_CODE, @@ -25,7 +27,7 @@ enum mouse_xa_flags_t{ MOUSEf_ATTR_HAS_TC = 0x0001, MOUSEf_ATTR_HAS_DEFAULT = 0x0002, MOUSEf_ATTR_HAS_BUILDER = 0x0004, - MOUSEf_ATTR_HAS_INITIALIZER = 0x0008, /* not used in Mouse */ + MOUSEf_ATTR_HAS_INITIALIZER = 0x0008, MOUSEf_ATTR_HAS_TRIGGER = 0x0010, MOUSEf_ATTR_IS_LAZY = 0x0020, diff --git a/xs-src/MouseUtil.xs b/xs-src/MouseUtil.xs index d47ed8b..2e7f50b 100644 --- a/xs-src/MouseUtil.xs +++ b/xs-src/MouseUtil.xs @@ -196,6 +196,25 @@ mouse_call1 (pTHX_ SV *const self, SV *const method, SV* const arg1) return ret; } +SV* +mouse_get_metaclass_by_name(pTHX_ SV* const metaclass_name){ + CV* const get_metaclass = get_cvs("Mouse::Util::get_metaclass_by_name", TRUE); + SV* metaclass; + dSP; + + PUSHMARK(SP); + XPUSHs(metaclass_name); + PUTBACK; + + call_sv((SV*)get_metaclass, G_SCALAR); + + SPAGAIN; + metaclass = POPs; + PUTBACK; + + return metaclass; +} + MAGIC* mouse_mg_find(pTHX_ SV* const sv, const MGVTBL* const vtbl, I32 const flags){ MAGIC* mg; @@ -213,6 +232,21 @@ mouse_mg_find(pTHX_ SV* const sv, const MGVTBL* const vtbl, I32 const flags){ return NULL; } +GV* +mouse_stash_fetch(pTHX_ HV* const stash, const char* const name, I32 const namelen, I32 const create) { + GV** const gvp = (GV**)hv_fetch(stash, name, namelen, create); + + if(gvp){ + if(!isGV(*gvp)){ + gv_init(*gvp, stash, name, namelen, GV_ADDMULTI); + } + return *gvp; + } + else{ + return NULL; + } +} + MODULE = Mouse::Util PACKAGE = Mouse::Util PROTOTYPES: DISABLE @@ -252,7 +286,9 @@ get_code_ref(SV* package, SV* name) CODE: { HV* stash; - HE* he; + STRLEN name_len; + const char* name_pv; + GV* gv; if(!SvOK(package)){ croak("You must define a package name"); @@ -265,19 +301,10 @@ CODE: if(!stash){ XSRETURN_UNDEF; } - he = hv_fetch_ent(stash, name, FALSE, 0U); - if(he){ - GV* const gv = (GV*)hv_iterval(stash, he); - if(!isGV(gv)){ /* special constant or stub */ - STRLEN len; - const char* const pv = SvPV_const(name, len); - gv_init(gv, stash, pv, len, GV_ADDMULTI); - } - RETVAL = GvCVu(gv); - } - else{ - RETVAL = NULL; - } + + name_pv = SvPV_const(name, name_len); + gv = stash_fetch(stash, name_pv, name_len, FALSE); + RETVAL = gv ? GvCVu(gv) : NULL; if(!RETVAL){ XSRETURN_UNDEF;