From: John F. <jf...@ms...> - 2009-09-04 12:55:22
|
We (MSI) have just released a development version of our memory mapped MOP database. There's a lot that can be improved with it but it has a test suite and has been bashing stuff out for a while. http://github.com/ilitirit/manardb/tree/master Object instantiation seems a little slow on SBCL (just my impression compared to Allegro 8.1 -- could be completely wrong) and I wonder if there is something I'm doing wrong? Basically each mm-object of a class descended from mm-metaclass has a normal instance %ptr slot which gives an index into our mmap'd regions. I guess should play more with allocate-instance and avoid doing initialize-instance. Any wisdom appreciated! Unfortunately as all mmap slots are always boundp, we have to munge the general initialize-instance to set default slot values. This is quite unfortunate. Is there a more sensible way of doing this (along the lines of the way structure slots are handled)? The normal slots are mmap'd, which are persistently stored in the mapped regions and are accessed via overridden slot-value-using-class. This is just (defmethod slot-value-using-class ((class mm-metaclass) (object mm-object) (slotd mm-effective-slot-definition)) (declare (ignorable class)) (funcall (the mm-slot-definition-reader (slot-definition-reader-function slotd)) object)) (defmethod (setf slot-value-using-class) (new-value (class mm-metaclass) (object mm-object) (slotd mm-effective-slot-definition)) (declare (ignorable class)) (funcall (the mm-slot-definition-writer (slot-definition-writer-function slotd)) new-value object)) I notice that SBCL does a similar thing with its normal slots, but when I tried to hook my compiled lambdas into sb-pcl::slot-definition-writer-function, it crashes. Is that because I am doing it wrong(tm) or is there some magic to follow? |
From: Pascal C. <pc...@p-...> - 2009-09-04 13:56:05
|
On 4 Sep 2009, at 13:59, John Fremlin wrote: > We (MSI) have just released a development version of our memory mapped > MOP database. There's a lot that can be improved with it but it has a > test suite and has been bashing stuff out for a while. > > http://github.com/ilitirit/manardb/tree/master > > Object instantiation seems a little slow on SBCL (just my impression > compared to Allegro 8.1 -- could be completely wrong) and I wonder if > there is something I'm doing wrong? Not sure, there could be many reasons. However, I can notice a few issues from taking a first look at the code: + You define a method on shared-initialize for your metaclass. According to the CLOS MOP specification, you are not allowed to do that, your program is thus not portable. You have to define methods on initialize-instance and reinitialize-instance instead. + What compilation settings do you use? Maybe SBCL just performs more checks that you may want to switch off? (Just guessing here.) + Your slot-xyz-using-class methods specalize not only on the metaclass and the slot definition class, but also on the object. That's redundant, it doesn't buy you anything, since you want instances of the metaclass to inherit from the object class anyway. Leaving out the specialize may allow SBCL to use faster caches. > Basically each mm-object of a class descended from mm-metaclass has a > normal instance %ptr slot which gives an index into our mmap'd > regions. I guess should play more with allocate-instance and avoid > doing > initialize-instance. Any wisdom appreciated! > > Unfortunately as all mmap slots are always boundp, we have to munge > the > general initialize-instance to set default slot values. This is quite > unfortunate. Is there a more sensible way of doing this (along the > lines > of the way structure slots are handled)? What do you mean by 'munge' (sorry, I'm not a native speaker)? Note that you can also define methods on make-instance and allocate- instance, if that helps. Pascal -- Pascal Costanza, mailto:pc...@p-..., http://p-cos.net Vrije Universiteit Brussel Software Languages Lab Pleinlaan 2, B-1050 Brussel, Belgium |
From: Nicolas N. <ne...@ma...> - 2009-09-05 11:06:33
|
John Fremlin <jf...@ms...> writes: > Object instantiation seems a little slow on SBCL (just my impression > compared to Allegro 8.1 -- could be completely wrong) and I wonder if > there is something I'm doing wrong? Calling make-instance with initargs turned out to be quite slow for me. Replacing it by a call without arguments and setting the slots afterwards helped me. (Of course, you should do such ugly optimizations only if really necessary.) Nicolas |
From: John F. <jf...@ms...> - 2009-09-07 06:16:38
|
Hi Pascal, Pascal Costanza <pc...@p-...> writes: > On 4 Sep 2009, at 13:59, John Fremlin wrote: > >> We (MSI) have just released a development version of our memory mapped >> MOP database. There's a lot that can be improved with it but it has a >> test suite and has been bashing stuff out for a while. >> >> http://github.com/ilitirit/manardb/tree/master >> >> Object instantiation seems a little slow on SBCL (just my impression >> compared to Allegro 8.1 -- could be completely wrong) and I wonder if >> there is something I'm doing wrong? > > Not sure, there could be many reasons. > > However, I can notice a few issues from taking a first look at the code: > > + You define a method on shared-initialize for your > metaclass. According to the CLOS MOP specification, you are not > allowed to do that, your program is thus not portable. You have to > define methods on initialize-instance and reinitialize-instance > instead. Thanks for this input. I wasn't aware of that (it isn't covered in AMOP as far as I can see). I cargo culted the idea from Elephant. But you are quite correct according to http://clisp.cons.org/impnotes/mop-classes.html#mop-cl-init-mo It is now fixed and I've pushed the updates. Thanks! > + What compilation settings do you use? Maybe SBCL just performs more > checks that you may want to switch off? (Just guessing here.) Not sure to be honest, I'm starting with a general (proclaim '(optimize speed)) before the project is loaded ;-) > + Your slot-xyz-using-class methods specalize not only on the > metaclass and the slot definition class, but also on the object. > That's redundant, it doesn't buy you anything, since you want > instances of the metaclass to inherit from the object class anyway. > Leaving out the specialize may allow SBCL to use faster caches. That makes sense, I'll do that. [...] >> Unfortunately as all mmap slots are always boundp, we have to munge >> the general initialize-instance to set default slot values. This is >> quite unfortunate. Is there a more sensible way of doing this (along >> the lines of the way structure slots are handled)? > > What do you mean by 'munge' (sorry, I'm not a native speaker)? I mean that the way I do it is not at all nice and pretty. I think it is probably clearer to show the code (defmethod initialize-instance :before ((instance mm-object) &rest initargs) (declare (optimize speed) (dynamic-extent initargs)) (cond ((eq '%ptr (first initargs)) ;;; XXX this is for speed; if %ptr is given it must be first (setf (%ptr instance) (second initargs))) (t (let ((class (class-of instance))) (setf (%ptr instance) (mm-metaclass-alloc class)) ;;; XXX this is a horrible hack because we don't support unbound slots ;;; not in shared-initialize because that is more likely to destroy the system's optimizations???? (let ((slot-definitions (class-slots class))) (loop for s in slot-definitions do (when (and (slot-definition-memory-mapped s) (slot-definition-initfunction s)) (unless (get-properties initargs (slot-definition-initargs s)) (setf (slot-value-using-class class instance s) (funcall (slot-definition-initfunction s)))))))))) instance) > Note that you can also define methods on make-instance and allocate- > instance, if that helps. The situation when most instance creation occurs is when an object is instantiated from the database into a Lisp object (generally with one slot, (hopefully) a fixnum "mptr"). It is possible for the object to have normal instance slots (caches or temporary slots). Those should be initialized according to the normal rules. It would be possible to generate an compiled function to do this explicitly for all such slots -- firstly calling allocate-instance(?) directly and then the init-functions for each slot. One approach I was considering was to inherit from structure-class instead of standard-class, etc. This would finesse the initialisation as structure slots are also never unbound. But I think that is not really portable? (And perhaps not sensible) [...] |
From: John F. <jf...@ms...> - 2009-09-07 06:19:53
|
Nicolas Neuss <ne...@ma...> writes: > John Fremlin <jf...@ms...> writes: > >> Object instantiation seems a little slow on SBCL (just my impression >> compared to Allegro 8.1 -- could be completely wrong) and I wonder if >> there is something I'm doing wrong? > > Calling make-instance with initargs turned out to be quite slow for me. > Replacing it by a call without arguments and setting the slots > afterwards helped me. (Of course, you should do such ugly optimizations > only if really necessary.) This makes sense I guess. At the moment we make an object-instantiator function like this (compile nil `(lambda (index) (declare (optimize speed) (type mindex index)) (make-instance ,class '%ptr (make-mptr ,(mm-metaclass-tag class) index)))))) And changing it to setf the %ptr instead is not any more ugly . . . We could easily call allocate-instance and setf all the normal slots to their defined initfunctions too . . . |
From: Pascal C. <pc...@p-...> - 2009-09-07 06:38:56
|
On 7 Sep 2009, at 08:16, John Fremlin wrote: > Hi Pascal, > > Pascal Costanza <pc...@p-...> writes: > >> On 4 Sep 2009, at 13:59, John Fremlin wrote: >> >>> We (MSI) have just released a development version of our memory >>> mapped >>> MOP database. There's a lot that can be improved with it but it >>> has a >>> test suite and has been bashing stuff out for a while. >>> >>> http://github.com/ilitirit/manardb/tree/master >>> >>> Object instantiation seems a little slow on SBCL (just my impression >>> compared to Allegro 8.1 -- could be completely wrong) and I wonder >>> if >>> there is something I'm doing wrong? >> >> Not sure, there could be many reasons. >> >> However, I can notice a few issues from taking a first look at the >> code: >> >> + You define a method on shared-initialize for your >> metaclass. According to the CLOS MOP specification, you are not >> allowed to do that, your program is thus not portable. You have to >> define methods on initialize-instance and reinitialize-instance >> instead. > > Thanks for this input. I wasn't aware of that (it isn't covered in > AMOP > as far as I can see). It is, in the section "Initialization of Class Metaobjects", where it explicitly states that "portable programs must not define methods on shared-initialize." > I cargo culted the idea from Elephant. But you are > quite correct according to > http://clisp.cons.org/impnotes/mop-classes.html#mop-cl-init-mo > > It is now fixed and I've pushed the updates. Make sure that these are :before/:after/:around methods, because the spec also states that you must not define primary methods on those functions. ;) >>> Unfortunately as all mmap slots are always boundp, we have to munge >>> the general initialize-instance to set default slot values. This is >>> quite unfortunate. Is there a more sensible way of doing this (along >>> the lines of the way structure slots are handled)? >> >> What do you mean by 'munge' (sorry, I'm not a native speaker)? > > I mean that the way I do it is not at all nice and pretty. I think > it is > probably clearer to show the code > > (defmethod initialize-instance :before ((instance mm-object) &rest > initargs) > (declare (optimize speed) (dynamic-extent initargs)) > (cond ((eq '%ptr (first initargs)) ;;; XXX this is for speed; if > %ptr is given it must be first > (setf (%ptr instance) > (second initargs))) > (t > (let ((class (class-of instance))) > (setf (%ptr instance) (mm-metaclass-alloc class)) > > ;;; XXX this is a horrible hack because we don't support unbound > slots > ;;; not in shared-initialize because that is more likely to > destroy the system's optimizations???? > (let ((slot-definitions (class-slots class))) > (loop for s in slot-definitions do > (when (and (slot-definition-memory-mapped s) > (slot-definition-initfunction s)) > (unless (get-properties initargs (slot-definition-initargs s)) > (setf (slot-value-using-class class instance s) > (funcall (slot-definition-initfunction s)))))))))) > instance) I guess this is where the overhead comes from. I don't see an obvious way how to avoid the overhead. (Sorry.) You could try to support unbound slots nonetheless, but this would still lead to slower initializations because it would bypass certain optimizations a CLOS implementations is allowed to do without your own slot-xyz-using-class methods. >> Note that you can also define methods on make-instance and allocate- >> instance, if that helps. > > The situation when most instance creation occurs is when an object is > instantiated from the database into a Lisp object (generally with one > slot, (hopefully) a fixnum "mptr"). > > It is possible for the object to have normal instance slots (caches or > temporary slots). Those should be initialized according to the normal > rules. It would be possible to generate an compiled function to do > this > explicitly for all such slots -- firstly calling allocate-instance(?) > directly and then the init-functions for each slot. > > One approach I was considering was to inherit from structure-class > instead of standard-class, etc. This would finesse the > initialisation as > structure slots are also never unbound. But I think that is not really > portable? (And perhaps not sensible) Maybe you could initialize the memory in some other way (by writing 0's, for example), and then not use CLOS initialization at all for such slots. Instead, invoke another generic function 'initialize- memory-mapped-slots that can be specialized by a user as an :after method on initialize-instance. Then you could at least bypass the iteration through the slot definition metaobjects. Just an idea... Pascal -- Pascal Costanza, mailto:pc...@p-..., http://p-cos.net Vrije Universiteit Brussel Software Languages Lab Pleinlaan 2, B-1050 Brussel, Belgium |
From: Christophe R. <cs...@ca...> - 2009-09-07 07:36:19
|
John Fremlin <jf...@ms...> writes: > This makes sense I guess. At the moment we make an object-instantiator > function like this > > (compile nil > `(lambda (index) > (declare (optimize speed) (type mindex index)) > (make-instance ,class '%ptr (make-mptr ,(mm-metaclass-tag class) index)))))) You haven't said which version of SBCL you're measuring... but just in case it's not newish: the optimization of make-instance used to give up entirely if the MAKE-INSTANCE call's class argument was a literal CLASS (as opposed to a class name). That's changed in the last few months, so that's one possibility. > And changing it to setf the %ptr instead is not any more ugly . . . > > We could easily call allocate-instance and setf all the normal slots to > their defined initfunctions too . . . SBCL has an aggressive and fairly (but not entirely) general make-instance optimization when the class and initarg-plist-keywords are constant, implemented in src/pcl/ctor.lisp. Unfortunately for you, the optimization it performs isn't valid if there are custom methods on slot-boundp-using-class or (setf slot-value-using-class) -- as well as various other cases; see CONSTRUCTOR-FUNCTION-FORM for the gory details. If initialization is truly too slow for you, you might want to consider effectively extending or specializing the ctor optimization (which basically precomputes the association between keyword initargs and slots) for your case, which I think is probably the conclusion you've reached too. Good luck, Christophe |
From: Leslie P. P. <sk...@vi...> - 2009-09-07 08:16:30
|
John Fremlin wrote: >> + You define a method on shared-initialize for your >> metaclass. According to the CLOS MOP specification, you are not >> allowed to do that, your program is thus not portable. You have to >> define methods on initialize-instance and reinitialize-instance >> instead. > > Thanks for this input. I wasn't aware of that (it isn't covered in AMOP > as far as I can see). I cargo culted the idea from Elephant. Note that Elephant only defines auxiliary methods on SHARED-INITIALIZE, which is allowed IIRC. Leslie -- http://www.linkedin.com/in/polzer |
From: Pascal C. <pc...@p-...> - 2009-09-07 09:47:55
|
On 7 Sep 2009, at 10:16, Leslie P. Polzer wrote: > > John Fremlin wrote: >>> + You define a method on shared-initialize for your >>> metaclass. According to the CLOS MOP specification, you are not >>> allowed to do that, your program is thus not portable. You have to >>> define methods on initialize-instance and reinitialize-instance >>> instead. >> >> Thanks for this input. I wasn't aware of that (it isn't covered in >> AMOP >> as far as I can see). I cargo culted the idea from Elephant. > > Note that Elephant only defines auxiliary methods on SHARED- > INITIALIZE, > which is allowed IIRC. Nope, also not. Pascal -- Pascal Costanza, mailto:pc...@p-..., http://p-cos.net Vrije Universiteit Brussel Software Languages Lab Pleinlaan 2, B-1050 Brussel, Belgium |
From: John F. <jf...@ms...> - 2009-09-08 08:51:23
|
Pascal Costanza <pc...@p-...> writes: > On 7 Sep 2009, at 08:16, John Fremlin wrote: >> Pascal Costanza <pc...@p-...> writes: >>> On 4 Sep 2009, at 13:59, John Fremlin wrote: [...] >>> + You define a method on shared-initialize for your >>> metaclass. According to the CLOS MOP specification, you are not >>> allowed to do that, your program is thus not portable. You have to >>> define methods on initialize-instance and reinitialize-instance >>> instead. >> >> Thanks for this input. I wasn't aware of that (it isn't covered in >> AMOP as far as I can see). > > It is, in the section "Initialization of Class Metaobjects", where it > explicitly states that "portable programs must not define methods on > shared-initialize." Mr Kuroda just mentioned to me that he didn't remember this, so I checked up in more detail. That passage is not in the AMOP I looked at but it is a physical copy so maybe I am missing it? However, there is such a section in http://www.lisp.org/mop/dictionary.html But it only says, "Portable programs must not call shared-initialize directly to initialize or reinitialize a class metaobject. " Maybe you are talking about slot-definition objects? >> I cargo culted the idea from Elephant. But you are >> quite correct according to >> http://clisp.cons.org/impnotes/mop-classes.html#mop-cl-init-mo >> >> It is now fixed and I've pushed the updates. > > Make sure that these are :before/:after/:around methods, because the > spec also states that you must not define primary methods on those > functions. ;) I have done this (defmethod initialize-instance :around ((class mm-metaclass) &rest all-keys) (ensure-inherits-from-mm-object class #'call-next-method all-keys)) (defmethod reinitialize-instance :around ((class mm-metaclass) &rest all-keys) (ensure-inherits-from-mm-object class #'call-next-method all-keys)) [...] > I guess this is where the overhead comes from. I don't see an obvious > way how to avoid the overhead. (Sorry.) In the hope of getting back to SBCL, I was kind of wondering how naughty it would be to set the sb-pcl::slot-reader-function or the sb-pcl::slot-writer-function? Secondly, is there some way to override the generation of accessors like readers and writers so that they directly call my fast functions instead of going through slot-value-using-class? I had some strange errors (function not of type method??) when I did this and wonder if it was because my magic too weak, or it would in fact be reasonable. > You could try to support unbound slots nonetheless, but this would > still lead to slower initializations because it would bypass certain > optimizations a CLOS implementations is allowed to do without your own > slot-xyz-using-class methods. That would also require a more complex slot access and persistent format (to store the boundedness). [...] |
From: Pascal C. <pc...@p-...> - 2009-09-08 09:08:12
|
On 8 Sep 2009, at 10:51, John Fremlin wrote: > Pascal Costanza <pc...@p-...> writes: >> On 7 Sep 2009, at 08:16, John Fremlin wrote: >>> Pascal Costanza <pc...@p-...> writes: >>>> On 4 Sep 2009, at 13:59, John Fremlin wrote: > [...] >>>> + You define a method on shared-initialize for your >>>> metaclass. According to the CLOS MOP specification, you are not >>>> allowed to do that, your program is thus not portable. You have to >>>> define methods on initialize-instance and reinitialize-instance >>>> instead. >>> >>> Thanks for this input. I wasn't aware of that (it isn't covered in >>> AMOP as far as I can see). >> >> It is, in the section "Initialization of Class Metaobjects", where it >> explicitly states that "portable programs must not define methods on >> shared-initialize." > > Mr Kuroda just mentioned to me that he didn't remember this, so I > checked up in more detail. That passage is not in the AMOP I looked > at but it is a physical copy so maybe I am missing it? > > However, there is such a section in http://www.lisp.org/mop/dictionary.html > > But it only says, "Portable programs must not call shared-initialize > directly to initialize or reinitialize a class metaobject. " Yes, it's easy to miss all the details that are spread around in the specification (just like in ANSI CL as well). The relevant section is "Initialization of Class Metaobjects", right at the end in the bullet list. (Page 196 in "The Art of the Metaobject Protocol". >>> I cargo culted the idea from Elephant. But you are >>> quite correct according to >>> http://clisp.cons.org/impnotes/mop-classes.html#mop-cl-init-mo >>> >>> It is now fixed and I've pushed the updates. >> >> Make sure that these are :before/:after/:around methods, because the >> spec also states that you must not define primary methods on those >> functions. ;) > > I have done this > > (defmethod initialize-instance :around ((class mm-metaclass) > &rest all-keys) > (ensure-inherits-from-mm-object class #'call-next-method all-keys)) > (defmethod reinitialize-instance :around ((class mm-metaclass) > &rest all-keys) > (ensure-inherits-from-mm-object class #'call-next-method all-keys)) > > [...] This looks good. >> I guess this is where the overhead comes from. I don't see an obvious >> way how to avoid the overhead. (Sorry.) > > In the hope of getting back to SBCL, I was kind of wondering how > naughty > it would be to set the sb-pcl::slot-reader-function or the > sb-pcl::slot-writer-function? I don't know the SBCL internals well, so I cannot comment on this. > Secondly, is there some way to override the generation of accessors > like > readers and writers so that they directly call my fast functions > instead > of going through slot-value-using-class? > > I had some strange errors (function not of type method??) when I did > this > and wonder if it was because my magic too weak, or it would in fact be > reasonable. Yes, it should be possible: Just do this in an :around method on (re)initialize-instance, remove the already generated accessor methods and replace them with your own. >> You could try to support unbound slots nonetheless, but this would >> still lead to slower initializations because it would bypass certain >> optimizations a CLOS implementations is allowed to do without your >> own >> slot-xyz-using-class methods. > > That would also require a more complex slot access and persistent > format (to store the boundedness). True. Pascal -- Pascal Costanza, mailto:pc...@p-..., http://p-cos.net Vrije Universiteit Brussel Software Languages Lab Pleinlaan 2, B-1050 Brussel, Belgium |
From: Attila L. <att...@gm...> - 2009-09-09 08:30:00
|
> If initialization is truly too slow for you, you might want to consider > effectively extending or specializing the ctor optimization (which > basically precomputes the association between keyword initargs and > slots) for your case, which I think is probably the conclusion you've > reached too. http://common-lisp.net/cgi-bin/darcsweb/darcsweb.cgi/darcsweb.cgi?r=cl-dwim-wui;a=headblob;f=/src/component/sbcl-ctor-kludge.lisp as a reference, we've done that, extended sbcl ctor optimizations. it's ugly, because the sbcl ctor code does not provide customization hooks as of now, so we ended up redefining two sbcl functions with some extra if's to handle a special-case (all that with tons of KLUDGE comments to warn for the laid mines... :) for us this results in iirc a 10-fold speedup in instantiating gui components. (they have a special meta-class to keep a special 'parent slot updated) hth, -- attila ps: the code at the link does not work with sbcl head. the rebase patch is not pushed in that repo, but it's the very much the same modulo some extra args for those sbcl functions... ps2: we have a proof of concept CL partial evaluator that Levy successfully applied to make-instance and it spits out results that are in par with the hand-made ctor optimizations of sbcl, but covers a much broader area of optimizations than that. |
From: Christophe R. <cs...@ca...> - 2009-09-09 10:56:15
|
Attila Lendvai <att...@gm...> writes: >> If initialization is truly too slow for you, you might want to consider >> effectively extending or specializing the ctor optimization (which >> basically precomputes the association between keyword initargs and >> slots) for your case, which I think is probably the conclusion you've >> reached too. > > > http://common-lisp.net/cgi-bin/darcsweb/darcsweb.cgi/darcsweb.cgi?r=cl-dwim-wui;a=headblob;f=/src/component/sbcl-ctor-kludge.lisp > > as a reference, we've done that, extended sbcl ctor optimizations. > > it's ugly, because the sbcl ctor code does not provide customization > hooks as of now [...] I doubt the sbcl ctor code will ever provide "customization hooks". What it might do is be extended to work when there are non-standard methods on (setf slot-value-using-class), which if I read your code right is your issue. It should be relatively straightforward to extend SLOT-INIT-FORMS to call (setf slot-value-using-class) rather than (setf clos-slots-ref) when setting a location whose slot definition has an applicable method on (setf slot-value-using-class) -- and similarly adapting the boundp tests (though from your code that's not immediately relevant for you). Cheers, Christophe |
From: John F. <jf...@ms...> - 2009-09-09 12:55:08
|
Christophe Rhodes <cs...@ca...> writes: [...] > I doubt the sbcl ctor code will ever provide "customization hooks". > What it might do is be extended to work when there are non-standard > methods on (setf slot-value-using-class), which if I read your code > right is your issue. It should be relatively straightforward to extend > SLOT-INIT-FORMS to call (setf slot-value-using-class) rather than > (setf clos-slots-ref) when setting a location whose slot definition has > an applicable method on (setf slot-value-using-class) -- and similarly > adapting the boundp tests (though from your code that's not immediately > relevant for you). How about if it directly calls the sb-pcl::slot-definition-writer-function and you decree that we may shove our specialised writer lambdas into that? (In the case where it was null then it could fall back to calling the generic function (setf slot-value-using-class).) PS. On the initialisation side, I'm quite happy with the new make-instance slot-defaulting lambdas I generate now, following your advice, and the test suite runs nearly twice as fast, so something must be right (defmmclass tree () ((numval :type (unsigned-byte 50) :initform 666 :initarg :numval) (general-val :initform 'gen-val :initarg :general-val :accessor tree-general-val) (id :initform (random (ash 1 40)) :type (unsigned-byte 40) :accessor tree-id) (val :initarg :val :accessor tree-val) (left :type tree :initform nil :accessor tree-left) (right :type tree :initform nil :accessor tree-right) (parent :initarg :parent :initform nil :accessor tree-parent) (temporary-slot :persistent nil))) (manardb::metaclass-allocator-form (find-class 'manardb.test::tree)) (LAMBDA (INSTANCE INITARGS) (DECLARE (DYNAMIC-EXTENT INITARGS) (OPTIMIZE SPEED) (IGNORABLE INITARGS)) (SETF (%PTR INSTANCE) (MAKE-MPTR 29 (MTAGMAP-ALLOC (MTAGMAP 29) 56))) (LET (#:NUMVAL132601 #:GENERAL-VAL132602) (LOOP FOR ARG IN INITARGS BY #'CDDR DO (CASE ARG (:NUMVAL (SETF #:NUMVAL132601 T)) (:GENERAL-VAL (SETF #:GENERAL-VAL132602 T)))) (UNLESS #:NUMVAL132601 (FUNCALL (THE MM-SLOT-DEFINITION-WRITER #<Function (:ANONYMOUS-LAMBDA 4433) @ #x1006078e22>) (FUNCALL #<Closure (:INTERNAL CONSTANTLY 0) @ #x1006078df2>) INSTANCE)) (UNLESS #:GENERAL-VAL132602 (FUNCALL (THE MM-SLOT-DEFINITION-WRITER #<Function (:ANONYMOUS-LAMBDA 4435) @ #x1006078eb2>) (FUNCALL #<Closure (:INTERNAL CONSTANTLY 0) [GEN-VAL] @ #x1006078e82>) INSTANCE))) INSTANCE) (The slots that are initform'd to zero are left alone). |
From: Nikodemus S. <nik...@ra...> - 2009-09-16 09:54:11
Attachments:
0001-initial-sketch.patch
|
2009/9/9 Christophe Rhodes <cs...@ca...>: > I doubt the sbcl ctor code will ever provide "customization hooks". > What it might do is be extended to work when there are non-standard > methods on (setf slot-value-using-class), which if I read your code > right is your issue. It should be relatively straightforward to extend > SLOT-INIT-FORMS to call (setf slot-value-using-class) rather than > (setf clos-slots-ref) when setting a location whose slot definition has > an applicable method on (setf slot-value-using-class) -- and similarly > adapting the boundp tests (though from your code that's not immediately > relevant for you). Attached patch is a sketch that does just that (for the SETF SLOT-VALUE-USING-CLASS case.) Utterly untested. I believe this could be further optimized using an INVOKE-METHOD strategy similar to that used in the body of OPTIMIZING-GENERATOR. Cheers, -- Nikodemus |
From: Christophe R. <cs...@ca...> - 2009-09-16 15:26:27
|
Nikodemus Siivola <nik...@ra...> writes: > 2009/9/9 Christophe Rhodes <cs...@ca...>: > >> I doubt the sbcl ctor code will ever provide "customization hooks". >> What it might do is be extended to work when there are non-standard >> methods on (setf slot-value-using-class), which if I read your code >> right is your issue. It should be relatively straightforward to extend >> SLOT-INIT-FORMS to call (setf slot-value-using-class) rather than >> (setf clos-slots-ref) when setting a location whose slot definition has >> an applicable method on (setf slot-value-using-class) -- and similarly >> adapting the boundp tests (though from your code that's not immediately >> relevant for you). > > Attached patch is a sketch that does just that (for the SETF > SLOT-VALUE-USING-CLASS case.) Utterly untested. I believe this could > be further optimized using an INVOKE-METHOD strategy similar to that > used in the body of OPTIMIZING-GENERATOR. That's the right idea. For extra style points, though, we don't have to go through (SETF SLOT-VALUE-USING-CLASS) for _all_ slot initializations: only those where there is an applicable method for the class and slot-definition pair -- as we already forbid users (it's in the documentation) from specializing on the NEW-VALUE, and the INSTANCE doesn't exist yet to be EQL-SPECIALIZED on. Then of course if we're going to go to this bother we might as well polish off the SLOT-BOUNDP-USING-CLASS case too. Cheers, Christophe |