From: gfx Date: Fri, 10 Jul 2009 08:57:03 +0000 (+0900) Subject: Make all the simple readers and predicates XS template X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fxs-attr-template;p=gitmo%2FClass-MOP.git Make all the simple readers and predicates XS template About 3% faster. --- diff --git a/lib/Class/MOP/Attribute.pm b/lib/Class/MOP/Attribute.pm index 3e41652..da4de78 100644 --- a/lib/Class/MOP/Attribute.pm +++ b/lib/Class/MOP/Attribute.pm @@ -155,30 +155,30 @@ sub _set_initial_slot_value { # the next bunch of methods will get bootstrapped # away in the Class::MOP bootstrapping section -sub associated_class { $_[0]->{'associated_class'} } -sub associated_methods { $_[0]->{'associated_methods'} } - -sub has_accessor { defined($_[0]->{'accessor'}) } -sub has_reader { defined($_[0]->{'reader'}) } -sub has_writer { defined($_[0]->{'writer'}) } -sub has_predicate { defined($_[0]->{'predicate'}) } -sub has_clearer { defined($_[0]->{'clearer'}) } -sub has_builder { defined($_[0]->{'builder'}) } -sub has_init_arg { defined($_[0]->{'init_arg'}) } -sub has_default { defined($_[0]->{'default'}) } -sub has_initializer { defined($_[0]->{'initializer'}) } -sub has_insertion_order { defined($_[0]->{'insertion_order'}) } - -sub accessor { $_[0]->{'accessor'} } -sub reader { $_[0]->{'reader'} } -sub writer { $_[0]->{'writer'} } -sub predicate { $_[0]->{'predicate'} } -sub clearer { $_[0]->{'clearer'} } -sub builder { $_[0]->{'builder'} } -sub init_arg { $_[0]->{'init_arg'} } -sub initializer { $_[0]->{'initializer'} } -sub definition_context { $_[0]->{'definition_context'} } -sub insertion_order { $_[0]->{'insertion_order'} } +#sub associated_class { $_[0]->{'associated_class'} } +#sub associated_methods { $_[0]->{'associated_methods'} } + +#sub has_accessor { defined($_[0]->{'accessor'}) } +#sub has_reader { defined($_[0]->{'reader'}) } +#sub has_writer { defined($_[0]->{'writer'}) } +#sub has_predicate { defined($_[0]->{'predicate'}) } +#sub has_clearer { defined($_[0]->{'clearer'}) } +#sub has_builder { defined($_[0]->{'builder'}) } +#sub has_init_arg { defined($_[0]->{'init_arg'}) } +#sub has_default { defined($_[0]->{'default'}) } +#sub has_initializer { defined($_[0]->{'initializer'}) } +#sub has_insertion_order { defined($_[0]->{'insertion_order'}) } + +#sub accessor { $_[0]->{'accessor'} } +#sub reader { $_[0]->{'reader'} } +#sub writer { $_[0]->{'writer'} } +#sub predicate { $_[0]->{'predicate'} } +#sub clearer { $_[0]->{'clearer'} } +#sub builder { $_[0]->{'builder'} } +#sub init_arg { $_[0]->{'init_arg'} } +#sub initializer { $_[0]->{'initializer'} } +#sub definition_context { $_[0]->{'definition_context'} } +#sub insertion_order { $_[0]->{'insertion_order'} } sub _set_insertion_order { $_[0]->{'insertion_order'} = $_[1] } # end bootstrapped away method section. diff --git a/lib/Class/MOP/Class.pm b/lib/Class/MOP/Class.pm index 8810338..7fb3622 100644 --- a/lib/Class/MOP/Class.pm +++ b/lib/Class/MOP/Class.pm @@ -337,15 +337,15 @@ 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 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'} } +#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 --git a/lib/Class/MOP/Instance.pm b/lib/Class/MOP/Instance.pm index 8643e3e..39c0270 100644 --- a/lib/Class/MOP/Instance.pm +++ b/lib/Class/MOP/Instance.pm @@ -66,7 +66,7 @@ sub _new { sub _class_name { $_[0]->{_class_name} ||= $_[0]->associated_metaclass->name } -sub associated_metaclass { $_[0]{'associated_metaclass'} } +#sub associated_metaclass { $_[0]{'associated_metaclass'} } sub create_instance { my $self = shift; diff --git a/lib/Class/MOP/Method.pm b/lib/Class/MOP/Method.pm index ea580ab..4f65c62 100644 --- a/lib/Class/MOP/Method.pm +++ b/lib/Class/MOP/Method.pm @@ -55,7 +55,7 @@ sub _new { ## accessors -sub associated_metaclass { shift->{'associated_metaclass'} } +#sub associated_metaclass { shift->{'associated_metaclass'} } sub attach_to_class { my ( $self, $class ) = @_; @@ -73,7 +73,7 @@ sub fully_qualified_name { $self->package_name . '::' . $self->name; } -sub original_method { (shift)->{'original_method'} } +#sub original_method { (shift)->{'original_method'} } sub _set_original_method { $_[0]->{'original_method'} = $_[1] } diff --git a/mop.c b/mop.c index 0fc1be1..963b8b5 100644 --- a/mop.c +++ b/mop.c @@ -9,7 +9,7 @@ mop_call_xs (pTHX_ XSPROTO(subaddr), CV *cv, SV **mark) PUTBACK; } -#if PERL_VERSION >= 10 +#if PERL_BCDVERSION >= 0x5010000 UV mop_check_package_cache_flag (pTHX_ HV *stash) { @@ -132,7 +132,6 @@ mop_get_package_symbols (HV *stash, type_filter_t filter, get_package_symbols_cb char *key; STRLEN keylen; char *package; - SV *fq; switch( SvTYPE(gv) ) { #ifndef SVt_RV @@ -145,6 +144,7 @@ mop_get_package_symbols (HV *stash, type_filter_t filter, get_package_symbols_cb * return CODE symbols */ if (filter == TYPE_FILTER_CODE) { if (SvROK(gv)) { + SV* fq; /* we don't really care about the length, but that's the API */ key = HePV(he, keylen); @@ -202,59 +202,40 @@ mop_get_all_package_symbols (HV *stash, type_filter_t filter) return ret; } -#define DECLARE_KEY(name) { #name, #name, NULL, 0 } -#define DECLARE_KEY_WITH_VALUE(name, value) { #name, value, NULL, 0 } - -/* the order of these has to match with those in mop.h */ -static struct { - const char *name; - const char *value; - SV *key; - U32 hash; -} prehashed_keys[key_last] = { - DECLARE_KEY(name), - DECLARE_KEY(package), - DECLARE_KEY(package_name), - DECLARE_KEY(body), - DECLARE_KEY_WITH_VALUE(package_cache_flag, "_package_cache_flag"), - DECLARE_KEY(methods), - DECLARE_KEY(VERSION), - DECLARE_KEY(ISA) -}; +static MGVTBL mop_accessor_vtbl; /* the MAGIC identity */ -SV * -mop_prehashed_key_for (mop_prehashed_key_t key) -{ - return prehashed_keys[key].key; -} +void +mop_install_simple_reader(const char* const fq_name, const char* const key, const int accessor_type){ + CV* const xsub = newXS((char*)fq_name, mop_xs_simple_reader, __FILE__); + SV* const keysv = newSVpvn_share(key, strlen(key), 0U); -U32 -mop_prehashed_hash_for (mop_prehashed_key_t key) -{ - return prehashed_keys[key].hash; + sv_magicext((SV*)xsub, keysv, PERL_MAGIC_ext, &mop_accessor_vtbl, NULL, 0); + SvREFCNT_dec(keysv); /* sv_magicext() increases refcnt in mg_obj */ + + CvXSUBANY(xsub).any_i32 = accessor_type; } -void -mop_prehash_keys () -{ - int i; - for (i = 0; i < key_last; i++) { - const char *value = prehashed_keys[i].value; - prehashed_keys[i].key = newSVpv(value, strlen(value)); - PERL_HASH(prehashed_keys[i].hash, value, strlen(value)); +static MAGIC* +mop_mg_find_by_vtbl(SV* const sv, const MGVTBL* const vtbl){ + MAGIC* mg; + + assert(sv != NULL); + for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic){ + if(mg->mg_virtual == vtbl){ + break; + } } + return mg; } XS(mop_xs_simple_reader) { -#ifdef dVAR dVAR; dXSARGS; -#else - dXSARGS; -#endif + MAGIC* const mg = mop_mg_find_by_vtbl((SV*)cv, &mop_accessor_vtbl); + SV* const key = mg->mg_obj; register HE *he; - mop_prehashed_key_t key = (mop_prehashed_key_t)CvXSUBANY(cv).any_i32; SV *self; + SV *retval; if (items != 1) { croak("expected exactly one argument"); @@ -263,20 +244,30 @@ XS(mop_xs_simple_reader) self = ST(0); if (!SvROK(self)) { - croak("can't call %s as a class method", prehashed_keys[key].name); + croak("can't call %s as a class method", GvNAME(CvGV(cv))); } if (SvTYPE(SvRV(self)) != SVt_PVHV) { croak("object is not a hashref"); } - if ((he = hv_fetch_ent((HV *)SvRV(self), prehashed_keys[key].key, 0, prehashed_keys[key].hash))) { - ST(0) = HeVAL(he); + if ((he = hv_fetch_ent((HV *)SvRV(self), key, 0, 0U))) { + switch(XSANY.any_i32){ + case SIMPLE_READER: + retval = HeVAL(he); + break; + case SIMPLE_PREDICATE: + retval = boolSV(SvOK(HeVAL(he))); + break; + default: + croak("panic: not reached"); + retval = NULL; /* -W */ + } } else { - ST(0) = &PL_sv_undef; + retval = &PL_sv_undef; } + ST(0) = retval; XSRETURN(1); } - diff --git a/mop.h b/mop.h index 288c8ad..849ad1d 100644 --- a/mop.h +++ b/mop.h @@ -18,37 +18,34 @@ void mop_call_xs (pTHX_ XSPROTO(subaddr), CV *cv, SV **mark); -typedef enum { - KEY_name, - KEY_package, - KEY_package_name, - KEY_body, - KEY_package_cache_flag, - KEY_methods, - KEY_VERSION, - KEY_ISA, - key_last, -} mop_prehashed_key_t; - -#define KEY_FOR(name) mop_prehashed_key_for(KEY_ ##name) -#define HASH_FOR(name) mop_prehashed_hash_for(KEY_ ##name) - -void mop_prehash_keys (void); -SV *mop_prehashed_key_for (mop_prehashed_key_t key); -U32 mop_prehashed_hash_for (mop_prehashed_key_t key); + +#define MAKE_KEYSV(name) newSVpvn_share(#name, sizeof(#name)-1, 0U) + +void mop_install_simple_reader(const char* const fq_name, const char* const key, const int accessor_type); + +#define SIMPLE_READER 1 +#define SIMPLE_PREDICATE 2 #define INSTALL_SIMPLE_READER(klass, name) INSTALL_SIMPLE_READER_WITH_KEY(klass, name, name) -#define INSTALL_SIMPLE_READER_WITH_KEY(klass, name, key) \ - { \ - CV *cv = newXS("Class::MOP::" #klass "::" #name, mop_xs_simple_reader, __FILE__); \ - CvXSUBANY(cv).any_i32 = KEY_ ##key; \ - } +#define INSTALL_SIMPLE_READER_WITH_KEY(klass, name, key) mop_install_simple_reader("Class::MOP::" #klass "::" #name, #key, SIMPLE_READER) + +#define INSTALL_SIMPLE_PREDICATE(klass, name) INSTALL_SIMPLE_PREDICATE_WITH_KEY(klass, name, name) +#define INSTALL_SIMPLE_PREDICATE_WITH_KEY(klass, name, key) mop_install_simple_reader("Class::MOP::" #klass "::has_" #name, #key, SIMPLE_PREDICATE) + XS(mop_xs_simple_reader); extern SV *mop_method_metaclass; extern SV *mop_associated_metaclass; 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 --git a/xs/Attribute.xs b/xs/Attribute.xs index 0375cb4..6097b7c 100644 --- a/xs/Attribute.xs +++ b/xs/Attribute.xs @@ -6,3 +6,25 @@ PROTOTYPES: DISABLE BOOT: INSTALL_SIMPLE_READER(Attribute, name); + INSTALL_SIMPLE_READER(Attribute, associated_class); + INSTALL_SIMPLE_READER(Attribute, associated_methods); + INSTALL_SIMPLE_READER(Attribute, accessor); + INSTALL_SIMPLE_READER(Attribute, reader); + INSTALL_SIMPLE_READER(Attribute, writer); + INSTALL_SIMPLE_READER(Attribute, predicate); + INSTALL_SIMPLE_READER(Attribute, clearer); + INSTALL_SIMPLE_READER(Attribute, builder); + INSTALL_SIMPLE_READER(Attribute, init_arg); + INSTALL_SIMPLE_READER(Attribute, initializer); + INSTALL_SIMPLE_READER(Attribute, insertion_order); + INSTALL_SIMPLE_READER(Attribute, definition_context); + + INSTALL_SIMPLE_PREDICATE(Attribute, accessor); + INSTALL_SIMPLE_PREDICATE(Attribute, reader); + INSTALL_SIMPLE_PREDICATE(Attribute, writer); + INSTALL_SIMPLE_PREDICATE(Attribute, predicate); + INSTALL_SIMPLE_PREDICATE(Attribute, clearer); + INSTALL_SIMPLE_PREDICATE(Attribute, builder); + INSTALL_SIMPLE_PREDICATE(Attribute, init_arg); + INSTALL_SIMPLE_PREDICATE(Attribute, initializer); + INSTALL_SIMPLE_PREDICATE(Attribute, default); diff --git a/xs/Class.xs b/xs/Class.xs index e187b4d..d779683 100644 --- a/xs/Class.xs +++ b/xs/Class.xs @@ -34,7 +34,7 @@ mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stas 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; } @@ -59,9 +59,9 @@ mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stas 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; @@ -79,6 +79,19 @@ mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stas MODULE = Class::MOP::Class PACKAGE = Class::MOP::Class +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 @@ -86,7 +99,7 @@ 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; @@ -98,8 +111,8 @@ get_method_map(self) } 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 ) { diff --git a/xs/Instance.xs b/xs/Instance.xs new file mode 100755 index 0000000..ecef003 --- /dev/null +++ b/xs/Instance.xs @@ -0,0 +1,8 @@ +#include "mop.h" + +MODULE = Class::MOP::Instance PACKAGE = Class::MOP::Instance + +PROTOTYPES: DISABLE + +BOOT: + INSTALL_SIMPLE_READER(Instance, associated_metaclass); diff --git a/xs/MOP.xs b/xs/MOP.xs index 5dfc0cd..fe98956 100644 --- a/xs/MOP.xs +++ b/xs/MOP.xs @@ -3,6 +3,15 @@ SV *mop_method_metaclass; SV *mop_associated_metaclass; 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) @@ -19,22 +28,30 @@ EXTERN_C XS(boot_Class__MOP__Package); EXTERN_C XS(boot_Class__MOP__Class); EXTERN_C XS(boot_Class__MOP__Attribute); EXTERN_C XS(boot_Class__MOP__Method); +EXTERN_C XS(boot_Class__MOP__Instance); MODULE = Class::MOP PACKAGE = Class::MOP 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_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); # use prototype here to be compatible with get_code_info from Sub::Identify void @@ -70,8 +87,8 @@ is_class_loaded(klass=&PL_sv_undef) XSRETURN_NO; } - if (hv_exists_ent (stash, KEY_FOR(VERSION), HASH_FOR(VERSION))) { - HE *version = hv_fetch_ent(stash, KEY_FOR(VERSION), 0, HASH_FOR(VERSION)); + if (hv_exists_ent (stash, mop_VERSION, 0U)) { + HE *version = hv_fetch_ent(stash, mop_VERSION, 0, 0U); SV *version_sv; if (version && HeVAL(version) && (version_sv = GvSV(HeVAL(version)))) { if (SvROK(version_sv)) { @@ -87,8 +104,8 @@ is_class_loaded(klass=&PL_sv_undef) } } - if (hv_exists_ent (stash, KEY_FOR(ISA), HASH_FOR(ISA))) { - HE *isa = hv_fetch_ent(stash, KEY_FOR(ISA), 0, HASH_FOR(ISA)); + if (hv_exists_ent (stash, mop_ISA, 0U)) { + HE *isa = hv_fetch_ent(stash, mop_ISA, 0, 0U); if (isa && HeVAL(isa) && GvAV(HeVAL(isa)) && av_len(GvAV(HeVAL(isa))) != -1) { XSRETURN_YES; } diff --git a/xs/Method.xs b/xs/Method.xs index 590cd06..13dcf31 100644 --- a/xs/Method.xs +++ b/xs/Method.xs @@ -8,3 +8,5 @@ BOOT: INSTALL_SIMPLE_READER(Method, name); INSTALL_SIMPLE_READER(Method, package_name); INSTALL_SIMPLE_READER(Method, body); + INSTALL_SIMPLE_READER(Method, associated_metaclass); + INSTALL_SIMPLE_READER(Method, original_method); diff --git a/xs/Package.xs b/xs/Package.xs index ce8d390..79d92a2 100644 --- a/xs/Package.xs +++ b/xs/Package.xs @@ -23,7 +23,7 @@ get_all_package_symbols(self, filter=TYPE_FILTER_NONE) PUTBACK; - if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(package), 0, HASH_FOR(package))) ) { + if ( (he = hv_fetch_ent((HV *)SvRV(self), mop_package, 0, 0U)) ) { stash = gv_stashsv(HeVAL(he), 0); }