From: gfx Date: Sat, 15 Aug 2009 12:30:52 +0000 (+0900) Subject: Merge commit 'origin/topic/xs-attr-template' into topic/unified-method-generation... X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=ffec3ec39c4145cbfa8c07cadf5a5d38f4b3cac7;p=gitmo%2FClass-MOP.git Merge commit 'origin/topic/xs-attr-template' into topic/unified-method-generation-w-xs Conflicts: lib/Class/MOP/Class.pm xs/Class.xs --- ffec3ec39c4145cbfa8c07cadf5a5d38f4b3cac7 diff --cc lib/Class/MOP/Class.pm index 9ffcda3,7fb3622..49a2adc --- a/lib/Class/MOP/Class.pm +++ b/lib/Class/MOP/Class.pm @@@ -341,13 -337,15 +341,13 @@@ sub create # all these attribute readers will be bootstrapped # away in the Class::MOP bootstrap section - sub get_attribute_map { $_[0]->{'attributes'} } - sub attribute_metaclass { $_[0]->{'attribute_metaclass'} } - sub instance_metaclass { $_[0]->{'instance_metaclass'} } - sub immutable_trait { $_[0]->{'immutable_trait'} } - sub constructor_class { $_[0]->{'constructor_class'} } - sub constructor_name { $_[0]->{'constructor_name'} } - sub destructor_class { $_[0]->{'destructor_class'} } + #sub get_attribute_map { $_[0]->{'attributes'} } + #sub attribute_metaclass { $_[0]->{'attribute_metaclass'} } -#sub method_metaclass { $_[0]->{'method_metaclass'} } -#sub wrapped_method_metaclass { $_[0]->{'wrapped_method_metaclass'} } + #sub instance_metaclass { $_[0]->{'instance_metaclass'} } + #sub immutable_trait { $_[0]->{'immutable_trait'} } + #sub constructor_class { $_[0]->{'constructor_class'} } + #sub constructor_name { $_[0]->{'constructor_name'} } + #sub destructor_class { $_[0]->{'destructor_class'} } # Instance Construction & Cloning diff --cc lib/Class/MOP/Method/Accessor.pm index 8a9ee8c,de883de..c6c4284 --- a/lib/Class/MOP/Method/Accessor.pm +++ b/lib/Class/MOP/Method/Accessor.pm @@@ -70,9 -52,21 +70,19 @@@ sub _new ## accessors - sub associated_attribute { (shift)->{'attribute'} } - sub accessor_type { (shift)->{'accessor_type'} } + #sub associated_attribute { (shift)->{'attribute'} } + #sub accessor_type { (shift)->{'accessor_type'} } + + -sub can_xs { ++sub _can_xs { + my($self, $method_name) = @_; + # don't use $method_name here, but there may be cases it is required. + + # FIXME: I didn't know how to detect it properly (gfx) + return ref($self) eq __PACKAGE__ - && $self->associated_attribute->associated_class->instance_metaclass eq 'Class::MOP::Instance'; ++ && $self->associated_metaclass->instance_metaclass eq 'Class::MOP::Instance'; + } -sub attribute_name{ (shift)->associated_attribute->name } - ## factory sub initialize_body { @@@ -87,10 -81,13 +97,13 @@@ sub _initialize_body my $method_name = join "_" => ( '_generate', $self->accessor_type, - 'method', - ($self->is_inline ? 'inline' : ()) + 'method' ); + if($self->is_inline){ - $method_name .= $self->can_xs($method_name) ? '_xs' : '_inline'; ++ $method_name .= $self->_can_xs($method_name) ? '_xs' : '_inline'; + } + $self->{'body'} = $self->$method_name(); } diff --cc mop.h index 288c8ad,08b448e..3f9134a --- a/mop.h +++ b/mop.h @@@ -48,7 -42,15 +42,16 @@@ XS(mop_xs_simple_clearer) extern SV *mop_method_metaclass; extern SV *mop_associated_metaclass; ++extern SV *mop_associated_attribute; extern SV *mop_wrap; + extern SV *mop_methods; + extern SV *mop_name; + extern SV *mop_body; + extern SV *mop_package; + extern SV *mop_package_name; + extern SV *mop_package_cache_flag; + extern SV *mop_VERSION; + extern SV *mop_ISA; UV mop_check_package_cache_flag(pTHX_ HV *stash); int mop_get_code_info (SV *coderef, char **pkg, char **name); diff --cc xs/Class.xs index 0000000,d779683..cca3823 mode 000000,100644..100644 --- a/xs/Class.xs +++ b/xs/Class.xs @@@ -1,0 -1,129 +1,15 @@@ + #include "mop.h" + -static void -mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stash, HV *const map) -{ - const char *const class_name_pv = HvNAME(stash); /* must be HvNAME(stash), not SvPV_nolen_const(class_name) */ - SV *method_metaclass_name; - char *method_name; - I32 method_name_len; - SV *coderef; - HV *symbols; - dSP; - - symbols = mop_get_all_package_symbols(stash, TYPE_FILTER_CODE); - sv_2mortal((SV*)symbols); - (void)hv_iterinit(symbols); - while ( (coderef = hv_iternextsv(symbols, &method_name, &method_name_len)) ) { - CV *cv = (CV *)SvRV(coderef); - char *cvpkg_name; - char *cv_name; - SV *method_slot; - SV *method_object; - - if (!mop_get_code_info(coderef, &cvpkg_name, &cv_name)) { - continue; - } - - /* this checks to see that the subroutine is actually from our package */ - if ( !(strEQ(cvpkg_name, "constant") && strEQ(cv_name, "__ANON__")) ) { - if ( strNE(cvpkg_name, class_name_pv) ) { - continue; - } - } - - method_slot = *hv_fetch(map, method_name, method_name_len, TRUE); - if ( SvOK(method_slot) ) { - SV *const body = mop_call0(aTHX_ method_slot, mop_body); /* $method_object->body() */ - if ( SvROK(body) && ((CV *) SvRV(body)) == cv ) { - continue; - } - } - - method_metaclass_name = mop_call0(aTHX_ self, mop_method_metaclass); /* $self->method_metaclass() */ - - /* - $method_object = $method_metaclass->wrap( - $cv, - associated_metaclass => $self, - package_name => $class_name, - name => $method_name - ); - */ - ENTER; - SAVETMPS; - - PUSHMARK(SP); - EXTEND(SP, 8); - PUSHs(method_metaclass_name); /* invocant */ - mPUSHs(newRV_inc((SV *)cv)); - PUSHs(mop_associated_metaclass); - PUSHs(self); - PUSHs(mop_package_name); - PUSHs(class_name); - PUSHs(mop_name); - mPUSHs(newSVpv(method_name, method_name_len)); - PUTBACK; - - call_sv(mop_wrap, G_SCALAR | G_METHOD); - SPAGAIN; - method_object = POPs; - PUTBACK; - /* $map->{$method_name} = $method_object */ - sv_setsv(method_slot, method_object); - - FREETMPS; - LEAVE; - } -} + + MODULE = Class::MOP::Class PACKAGE = Class::MOP::Class + ++PROTOTYPES: DISABLE ++ + BOOT: + INSTALL_SIMPLE_READER_WITH_KEY(Class, get_attribute_map, attributes); - /* INSTALL_SIMPLE_READER_WITH_KEY(Class, _method_map, methods); */ + INSTALL_SIMPLE_READER(Class, attribute_metaclass); - INSTALL_SIMPLE_READER(Class, method_metaclass); - INSTALL_SIMPLE_READER(Class, wrapped_method_metaclass); + INSTALL_SIMPLE_READER(Class, instance_metaclass); + INSTALL_SIMPLE_READER(Class, immutable_trait); + INSTALL_SIMPLE_READER(Class, constructor_name); + INSTALL_SIMPLE_READER(Class, constructor_class); + INSTALL_SIMPLE_READER(Class, destructor_class); - - -PROTOTYPES: DISABLE - -void -get_method_map(self) - SV *self - PREINIT: - HV *const obj = (HV *)SvRV(self); - SV *const class_name = HeVAL( hv_fetch_ent(obj, mop_package, 0, 0U) ); - HV *const stash = gv_stashsv(class_name, 0); - UV current; - SV *cache_flag; - SV *map_ref; - PPCODE: - if (!stash) { - mXPUSHs(newRV_noinc((SV *)newHV())); - return; - } - - current = mop_check_package_cache_flag(aTHX_ stash); - cache_flag = HeVAL( hv_fetch_ent(obj, mop_package_cache_flag, TRUE, 0U)); - map_ref = HeVAL( hv_fetch_ent(obj, mop_methods, TRUE, 0U)); - - /* $self->{methods} does not yet exist (or got deleted) */ - if ( !SvROK(map_ref) || SvTYPE(SvRV(map_ref)) != SVt_PVHV ) { - SV *new_map_ref = newRV_noinc((SV *)newHV()); - sv_2mortal(new_map_ref); - sv_setsv(map_ref, new_map_ref); - } - - if ( !SvOK(cache_flag) || SvUV(cache_flag) != current ) { - mop_update_method_map(aTHX_ self, class_name, stash, (HV *)SvRV(map_ref)); - sv_setuv(cache_flag, mop_check_package_cache_flag(aTHX_ stash)); /* update_cache_flag() */ - } - - XPUSHs(map_ref); diff --cc xs/MOP.xs index 85c7659,11e4f95..af912f2 --- a/xs/MOP.xs +++ b/xs/MOP.xs @@@ -2,7 -2,16 +2,17 @@@ SV *mop_method_metaclass; SV *mop_associated_metaclass; ++SV *mop_associated_attribute; SV *mop_wrap; + SV *mop_methods; + SV *mop_name; + SV *mop_body; + SV *mop_package; + SV *mop_package_name; + SV *mop_package_cache_flag; + + SV *mop_VERSION; + SV *mop_ISA; static bool find_method (const char *key, STRLEN keylen, SV *val, void *ud) @@@ -24,15 -36,24 +37,25 @@@ MODULE = Class::MOP PACKAGE = Class:: PROTOTYPES: DISABLE BOOT: - mop_prehash_keys(); - - mop_method_metaclass = newSVpvs("method_metaclass"); - mop_wrap = newSVpvs("wrap"); - mop_associated_metaclass = newSVpvs("associated_metaclass"); + mop_method_metaclass = MAKE_KEYSV(method_metaclass); + mop_wrap = MAKE_KEYSV(wrap); + mop_associated_metaclass = MAKE_KEYSV(associated_metaclass); ++ mop_associated_attribute = MAKE_KEYSV(associated_attribute); + mop_methods = MAKE_KEYSV(methods); + mop_name = MAKE_KEYSV(name); + mop_body = MAKE_KEYSV(body); + mop_package = MAKE_KEYSV(package); + mop_package_name = MAKE_KEYSV(package_name); + mop_package_cache_flag = MAKE_KEYSV(_package_cache_flag); + mop_VERSION = MAKE_KEYSV(VERSION); + mop_ISA = MAKE_KEYSV(ISA); MOP_CALL_BOOT (boot_Class__MOP__Package); + MOP_CALL_BOOT (boot_Class__MOP__Class); MOP_CALL_BOOT (boot_Class__MOP__Attribute); MOP_CALL_BOOT (boot_Class__MOP__Method); + MOP_CALL_BOOT (boot_Class__MOP__Instance); + MOP_CALL_BOOT (boot_Class__MOP__Method__Accessor); # use prototype here to be compatible with get_code_info from Sub::Identify void diff --cc xs/MethodAccessor.xs index 0000000,86dad34..037ed41 mode 000000,100755..100755 --- a/xs/MethodAccessor.xs +++ b/xs/MethodAccessor.xs @@@ -1,0 -1,54 +1,56 @@@ + #include "mop.h" + + static CV* -mop_instantiate_xs_accessor(pTHX_ SV* const meta_attr, XSPROTO(accessor_impl)){ - SV* const key = mop_call0(aTHX_ meta_attr, sv_2mortal(newSVpvs("attribute_name"))); ++mop_instantiate_xs_accessor(pTHX_ SV* const accessor, XSPROTO(accessor_impl)){ ++ /* $key = $accessor->associated_attribute->name */ ++ SV* const attr = mop_call0(aTHX_ accessor, mop_associated_attribute); ++ SV* const key = mop_call0(aTHX_ attr, mop_name); + STRLEN len; + const char* const pv = SvPV_const(key, len); + return mop_install_simple_accessor(aTHX_ NULL /* anonymous */, pv, len, accessor_impl); + } + + MODULE = Class::MOP::Method::Accessor PACKAGE = Class::MOP::Method::Accessor + + PROTOTYPES: DISABLE + + BOOT: + INSTALL_SIMPLE_READER_WITH_KEY(Method::Accessor, associated_attribute, attribute); + INSTALL_SIMPLE_READER(Method::Accessor, accessor_type); + + + CV* + _generate_accessor_method_xs(SV* self) + CODE: + RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_accessor); + OUTPUT: + RETVAL + + CV* + _generate_reader_method_xs(SV* self) + CODE: + RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_reader); + OUTPUT: + RETVAL + + CV* + _generate_writer_method_xs(SV* self) + CODE: + RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_writer); + OUTPUT: + RETVAL + + CV* + _generate_predicate_method_xs(SV* self) + CODE: + RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_predicate); + OUTPUT: + RETVAL + + CV* + _generate_clearer_method_xs(SV* self) + CODE: + RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_clearer); + OUTPUT: + RETVAL + diff --cc xs/Package.xs index 362c407,79d92a2..0cbeb52 --- a/xs/Package.xs +++ b/xs/Package.xs @@@ -1,82 -1,5 +1,82 @@@ #include "mop.h" +static void +mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stash, HV *const map) +{ + const char *const class_name_pv = HvNAME(stash); /* must be HvNAME(stash), not SvPV_nolen_const(class_name) */ + SV *method_metaclass_name; + char *method_name; + I32 method_name_len; + SV *coderef; + HV *symbols; + dSP; + + symbols = mop_get_all_package_symbols(stash, TYPE_FILTER_CODE); + sv_2mortal((SV*)symbols); + (void)hv_iterinit(symbols); + while ( (coderef = hv_iternextsv(symbols, &method_name, &method_name_len)) ) { + CV *cv = (CV *)SvRV(coderef); + char *cvpkg_name; + char *cv_name; + SV *method_slot; + SV *method_object; + + if (!mop_get_code_info(coderef, &cvpkg_name, &cv_name)) { + continue; + } + + /* this checks to see that the subroutine is actually from our package */ + if ( !(strEQ(cvpkg_name, "constant") && strEQ(cv_name, "__ANON__")) ) { + if ( strNE(cvpkg_name, class_name_pv) ) { + continue; + } + } + + method_slot = *hv_fetch(map, method_name, method_name_len, TRUE); + if ( SvOK(method_slot) ) { - SV *const body = mop_call0(aTHX_ method_slot, KEY_FOR(body)); /* $method_object->body() */ ++ SV *const body = mop_call0(aTHX_ method_slot, mop_body); /* $method_object->body() */ + if ( SvROK(body) && ((CV *) SvRV(body)) == cv ) { + continue; + } + } + + method_metaclass_name = mop_call0(aTHX_ self, mop_method_metaclass); /* $self->method_metaclass() */ + + /* + $method_object = $method_metaclass->wrap( + $cv, + associated_metaclass => $self, + package_name => $class_name, + name => $method_name + ); + */ + ENTER; + SAVETMPS; + + PUSHMARK(SP); + EXTEND(SP, 8); + PUSHs(method_metaclass_name); /* invocant */ + mPUSHs(newRV_inc((SV *)cv)); + PUSHs(mop_associated_metaclass); + PUSHs(self); - PUSHs(KEY_FOR(package_name)); ++ PUSHs(mop_package_name); + PUSHs(class_name); - PUSHs(KEY_FOR(name)); ++ PUSHs(mop_name); + mPUSHs(newSVpv(method_name, method_name_len)); + PUTBACK; + + call_sv(mop_wrap, G_SCALAR | G_METHOD); + SPAGAIN; + method_object = POPs; + PUTBACK; + /* $map->{$method_name} = $method_object */ + sv_setsv(method_slot, method_object); + + FREETMPS; + LEAVE; + } +} + MODULE = Class::MOP::Package PACKAGE = Class::MOP::Package PROTOTYPES: DISABLE @@@ -112,39 -35,5 +112,42 @@@ get_all_package_symbols(self, filter=TY symbols = mop_get_all_package_symbols(stash, filter); PUSHs(sv_2mortal(newRV_noinc((SV *)symbols))); +void +get_method_map(self) + SV *self + PREINIT: + HV *const obj = (HV *)SvRV(self); - SV *const class_name = HeVAL( hv_fetch_ent(obj, KEY_FOR(package), 0, HASH_FOR(package)) ); ++ SV *const class_name = HeVAL( hv_fetch_ent(obj, mop_package, 0, 0U) ); + HV *const stash = gv_stashsv(class_name, 0); + UV current; + SV *cache_flag; + SV *map_ref; + PPCODE: + if (!stash) { + mXPUSHs(newRV_noinc((SV *)newHV())); + return; + } + + current = mop_check_package_cache_flag(aTHX_ stash); - cache_flag = HeVAL( hv_fetch_ent(obj, KEY_FOR(package_cache_flag), TRUE, HASH_FOR(package_cache_flag))); - map_ref = HeVAL( hv_fetch_ent(obj, KEY_FOR(methods), TRUE, HASH_FOR(methods))); ++ cache_flag = HeVAL( hv_fetch_ent(obj, mop_package_cache_flag, TRUE, 0U)); ++ map_ref = HeVAL( hv_fetch_ent(obj, mop_methods, TRUE, 0U)); + + /* $self->{methods} does not yet exist (or got deleted) */ + if ( !SvROK(map_ref) || SvTYPE(SvRV(map_ref)) != SVt_PVHV ) { + SV *new_map_ref = newRV_noinc((SV *)newHV()); + sv_2mortal(new_map_ref); + sv_setsv(map_ref, new_map_ref); + } + + if ( !SvOK(cache_flag) || SvUV(cache_flag) != current ) { + mop_update_method_map(aTHX_ self, class_name, stash, (HV *)SvRV(map_ref)); + sv_setuv(cache_flag, mop_check_package_cache_flag(aTHX_ stash)); /* update_cache_flag() */ + } + + XPUSHs(map_ref); + BOOT: INSTALL_SIMPLE_READER_WITH_KEY(Package, name, package); ++ INSTALL_SIMPLE_READER_WITH_KEY(Package, _method_map, methods); ++ INSTALL_SIMPLE_READER(Package, method_metaclass); ++ INSTALL_SIMPLE_READER(Package, wrapped_method_metaclass);