From: gfx Date: Mon, 16 Nov 2009 10:33:25 +0000 (+0900) Subject: DEMOLISH to XS X-Git-Tag: 0.40_06~4 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=a5c683f611022dcabb13169162fa2f57ba72b200;p=gitmo%2FMouse.git DEMOLISH to XS --- diff --git a/lib/Mouse/Meta/Class.pm b/lib/Mouse/Meta/Class.pm index 24559c4..df95ad6 100644 --- a/lib/Mouse/Meta/Class.pm +++ b/lib/Mouse/Meta/Class.pm @@ -10,8 +10,8 @@ our @ISA = qw(Mouse::Meta::Module); sub method_metaclass() { 'Mouse::Meta::Method' } sub attribute_metaclass() { 'Mouse::Meta::Attribute' } -sub constructor_class(); # XS -sub destructor_class() { 'Mouse::Meta::Method::Destructor' } +sub constructor_class(); +sub destructor_class(); sub _construct_meta { my($class, %args) = @_; @@ -199,13 +199,17 @@ sub make_immutable { $self->{is_immutable}++; if ($args{inline_constructor}) { + my $c = $self->constructor_class; + Mouse::Util::load_class($c); $self->add_method($args{constructor_name} => - $self->constructor_class->_generate_constructor($self, \%args)); + $c->_generate_constructor($self, \%args)); } if ($args{inline_destructor}) { + my $c = $self->destructor_class; + Mouse::Util::load_class($c); $self->add_method(DESTROY => - $self->destructor_class->_generate_destructor($self, \%args)); + $c->_generate_destructor($self, \%args)); } # Moose's make_immutable returns true allowing calling code to skip setting an explicit true value diff --git a/lib/Mouse/Meta/Method/Constructor.pm b/lib/Mouse/Meta/Method/Constructor.pm index 5820a02..1f40a3c 100644 --- a/lib/Mouse/Meta/Method/Constructor.pm +++ b/lib/Mouse/Meta/Method/Constructor.pm @@ -1,5 +1,5 @@ package Mouse::Meta::Method::Constructor; -use Mouse::Util qw(get_code_ref); # enables strict and warnings +use Mouse::Util; # enables strict and warnings sub _inline_slot{ my(undef, $self_var, $attr_name) = @_; @@ -177,7 +177,7 @@ sub _generate_BUILDALL { my @code; for my $class ($metaclass->linearized_isa) { - if (get_code_ref($class, 'BUILD')) { + if (Mouse::Util::get_code_ref($class, 'BUILD')) { unshift @code, qq{${class}::BUILD(\$instance, \$args);}; } } diff --git a/lib/Mouse/Meta/Method/Destructor.pm b/lib/Mouse/Meta/Method/Destructor.pm index bdaea1b..5ffcd5c 100644 --- a/lib/Mouse/Meta/Method/Destructor.pm +++ b/lib/Mouse/Meta/Method/Destructor.pm @@ -1,5 +1,5 @@ package Mouse::Meta::Method::Destructor; -use Mouse::Util qw(get_code_ref); # enables strict and warnings +use Mouse::Util; # enables strict and warnings sub _empty_DESTROY{ } @@ -12,7 +12,7 @@ sub _generate_destructor{ my $demolishall = ''; for my $class ($metaclass->linearized_isa) { - if (get_code_ref($class, 'DEMOLISH')) { + if (Mouse::Util::get_code_ref($class, 'DEMOLISH')) { $demolishall .= "${class}::DEMOLISH(\$self);\n"; } } diff --git a/lib/Mouse/Object.pm b/lib/Mouse/Object.pm index 7cc315a..94a73d7 100644 --- a/lib/Mouse/Object.pm +++ b/lib/Mouse/Object.pm @@ -3,37 +3,6 @@ use Mouse::Util qw(does dump); # enables strict and warnings sub new; -sub DESTROY { - my $self = shift; - - return unless $self->can('DEMOLISH'); # short circuit - - local $?; - - my $e = do{ - local $@; - eval{ - - # DEMOLISHALL - - # We cannot count on being able to retrieve a previously made - # metaclass, _or_ being able to make a new one during global - # destruction. However, we should still be able to use mro at - # that time (at least tests suggest so ;) - - foreach my $class (@{ Mouse::Util::get_linear_isa(ref $self) }) { - my $demolish = Mouse::Util::get_code_ref($class, 'DEMOLISH') - || next; - - $self->$demolish(); - } - }; - $@; - }; - - no warnings 'misc'; - die $e if $e; # rethrow -} sub BUILDALL { my $self = shift; diff --git a/lib/Mouse/PurePerl.pm b/lib/Mouse/PurePerl.pm index d2f04f3..dcac898 100644 --- a/lib/Mouse/PurePerl.pm +++ b/lib/Mouse/PurePerl.pm @@ -203,9 +203,8 @@ sub add_method { package Mouse::Meta::Class; -use Mouse::Meta::Method::Constructor; - -sub constructor_class() { 'Mouse::Meta::Method::Constructor' } +sub constructor_class() { 'Mouse::Meta::Method::Constructor' } +sub destructor_class() { 'Mouse::Meta::Method::Destructor' } sub is_anon_class{ return exists $_[0]->{anon_serial_id}; @@ -437,6 +436,38 @@ sub new { return $self; } +sub DESTROY { + my $self = shift; + + return unless $self->can('DEMOLISH'); # short circuit + + local $?; + + my $e = do{ + local $@; + eval{ + + # DEMOLISHALL + + # We cannot count on being able to retrieve a previously made + # metaclass, _or_ being able to make a new one during global + # destruction. However, we should still be able to use mro at + # that time (at least tests suggest so ;) + + foreach my $class (@{ Mouse::Util::get_linear_isa(ref $self) }) { + my $demolish = Mouse::Util::get_code_ref($class, 'DEMOLISH') + || next; + + $self->$demolish(); + } + }; + $@; + }; + + no warnings 'misc'; + die $e if $e; # rethrow +} + 1; __END__ diff --git a/xs-src/Mouse.xs b/xs-src/Mouse.xs index 1dd44b3..627eabd 100644 --- a/xs-src/Mouse.xs +++ b/xs-src/Mouse.xs @@ -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,9 +188,14 @@ 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); } @@ -308,7 +313,7 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const LEAVE; } -SV* +static SV* mouse_initialize_metaclass(pTHX_ SV* const klass) { SV* meta = get_metaclass(klass); @@ -431,6 +436,15 @@ BOOT: 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) @@ -511,7 +525,7 @@ CODE: 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 */ @@ -544,8 +558,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; @@ -555,30 +569,83 @@ CODE: PUSHs(args); PUTBACK; - call_sv(AvARRAY(av)[i], G_VOID | G_DISCARD); + call_sv(AvARRAY(buildall)[i], G_VOID | G_DISCARD); } } OUTPUT: RETVAL -HV* -BUILDARGS(SV* klass, ...) +void +DESTROY(SV* object) CODE: { - RETVAL = mouse_buildargs(aTHX_ NULL, klass, ax, items); -} -OUTPUT: - RETVAL + 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))); -MODULE = Mouse PACKAGE = Mouse::Meta::Method::Constructor::XS + len = AvFILLp(linearized_isa) + 1; -CV* -_generate_constructor(...) + 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: { - RETVAL = get_cvs("Mouse::Object::new", TRUE); - SvREFCNT_inc_simple_void_NN(RETVAL); + RETVAL = mouse_buildargs(aTHX_ NULL, klass, ax, items); } OUTPUT: RETVAL + diff --git a/xs-src/MouseUtil.xs b/xs-src/MouseUtil.xs index e437c17..3e97648 100644 --- a/xs-src/MouseUtil.xs +++ b/xs-src/MouseUtil.xs @@ -215,7 +215,7 @@ mouse_get_metaclass(pTHX_ SV* metaclass_name){ assert(MY_CXT.metas); if(IsObject(metaclass_name)){ - HV* const stash = SvSTASH(metaclass_name); + HV* const stash = SvSTASH(SvRV(metaclass_name)); metaclass_name = newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U); sv_2mortal(metaclass_name);