0.pre7.88:
[sbcl.git] / src / pcl / construct.lisp
1 ;;;; This file defines the defconstructor and other make-instance optimization
2 ;;;; mechanisms.
3
4 ;;;; This software is part of the SBCL system. See the README file for
5 ;;;; more information.
6
7 ;;;; This software is derived from software originally released by Xerox
8 ;;;; Corporation. Copyright and release statements follow. Later modifications
9 ;;;; to the software are in the public domain and are provided with
10 ;;;; absolutely no warranty. See the COPYING and CREDITS files for more
11 ;;;; information.
12
13 ;;;; copyright information from original PCL sources:
14 ;;;;
15 ;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
16 ;;;; All rights reserved.
17 ;;;;
18 ;;;; Use and copying of this software and preparation of derivative works based
19 ;;;; upon this software are permitted. Any distribution of this software or
20 ;;;; derivative works must comply with all applicable United States export
21 ;;;; control laws.
22 ;;;;
23 ;;;; This software is made available AS IS, and Xerox Corporation makes no
24 ;;;; warranty about the software, its performance or its conformity to any
25 ;;;; specification.
26
27 (in-package "SB-PCL")
28 \f
29 ;;; defconstructor is used to define special purpose functions which just
30 ;;; call make-instance with a symbol as the first argument. The semantics
31 ;;; of defconstructor is that it is equivalent to defining a function which
32 ;;; just calls make-instance. The purpose of defconstructor is to provide
33 ;;; PCL with a way of noticing these calls to make-instance so that it can
34 ;;; optimize them. Specific ports of PCL could just have their compiler
35 ;;; spot these calls to make-instance and then call this code. Having the
36 ;;; special defconstructor facility is the best we can do portably.
37 ;;;
38 ;;; A call to defconstructor like:
39 ;;;
40 ;;;  (defconstructor make-foo foo (a b &rest r) a a :mumble b baz r)
41 ;;;
42 ;;; Is equivalent to a defun like:
43 ;;;
44 ;;;  (defun make-foo (a b &rest r)
45 ;;;    (make-instance 'foo 'a a ':mumble b 'baz r))
46 ;;;
47 ;;; Calls like the following are also legal:
48 ;;;
49 ;;;  (defconstructor make-foo foo ())
50 ;;;  (defconstructor make-bar bar () :x *x* :y *y*)
51 ;;;  (defconstructor make-baz baz (a b c) a-b (list a b) b-c (list b c))
52 ;;;
53 ;;; The general idea of this implementation is that the expansion of the
54 ;;; defconstructor form includes the creation of closure generators which
55 ;;; can be called to create constructor code for the class. The ways that
56 ;;; a constructor can be optimized depends not only on the defconstructor
57 ;;; form, but also on the state of the class and the generic functions in
58 ;;; the initialization protocol. Because of this, the determination of the
59 ;;; form of constructor code to be used is a two part process.
60 ;;;
61 ;;; At compile time, make-constructor-code-generators looks at the actual
62 ;;; defconstructor form and makes a list of appropriate constructor code
63 ;;; generators. All that is really taken into account here is whether
64 ;;; any initargs are supplied in the call to make-instance, and whether
65 ;;; any of those are constant.
66 ;;;
67 ;;; At constructor code generation time (see note about lazy evaluation)
68 ;;; compute-constructor-code calls each of the constructor code generators
69 ;;; to try to get code for this constructor. Each generator looks at the
70 ;;; state of the class and initialization protocol generic functions and
71 ;;; decides whether its type of code is appropriate. This depends on things
72 ;;; like whether there are any applicable methods on initialize-instance,
73 ;;; whether class slots are affected by initialization etc.
74 ;;;
75 ;;; Constructor objects are funcallable instances, the protocol followed to
76 ;;; to compute the constructor code for them is quite similar to the protocol
77 ;;; followed to compute the discriminator code for a generic function. When
78 ;;; the constructor is first loaded, we install as its code a function which
79 ;;; will compute the actual constructor code the first time it is called.
80 ;;;
81 ;;; If there is an update to the class structure which might invalidate the
82 ;;; optimized constructor, the special lazy constructor installer is put back
83 ;;; so that it can compute the appropriate constructor when it is called.
84 ;;; This is the same kind of lazy evaluation update strategy used elswhere
85 ;;; in PCL.
86 ;;;
87 ;;; To allow for flexibility in the PCL implementation and to allow PCL users
88 ;;; to specialize this constructor facility for their own metaclasses, there
89 ;;; is an internal protocol followed by the code which loads and installs
90 ;;; the constructors. This is documented in the comments in the code.
91 ;;;
92 ;;; This code is also designed so that one of its levels, can be used to
93 ;;; implement optimization of calls to make-instance which can't go through
94 ;;; the defconstructor facility. This has not been implemented yet, but the
95 ;;; hooks are there.
96
97 (defmacro defconstructor
98           (name class lambda-list &rest initialization-arguments)
99   (expand-defconstructor class
100                          name
101                          lambda-list
102                          (copy-list initialization-arguments)))
103
104 (defun expand-defconstructor (class-name name lambda-list supplied-initargs)
105   (let ((class (find-class class-name nil))
106         (supplied-initarg-names
107           (gathering1 (collecting)
108             (iterate ((name (*list-elements supplied-initargs :by #'cddr)))
109               (gather1 name)))))
110     (when (null class)
111       (error "defconstructor form being compiled (or evaluated) before~@
112               class ~S is defined."
113              class-name))
114     `(progn
115        ;; comments from PCL code back when it was portable:
116        ;;   In order to avoid undefined function warnings, we want to
117        ;;   tell the compile time environment that a function with this
118        ;;   name and this argument list has been defined. The portable
119        ;;   way to do this is with defun:
120        ;;   #-cmu (declaim (notinline ,name))
121        ;;   #-cmu
122        ;;   (defun ,name ,lambda-list
123        ;;     (declare (ignore ,@(extract-parameters lambda-list)))
124        ;;     (error "Constructor ~S not loaded." ',name))
125        ;;   But the derived result type for the above is wrong under CMU CL.
126        ;;   So instead:
127        (declaim (ftype ,(ftype-declaration-from-lambda-list lambda-list name)
128                        ,name))
129        (load-constructor
130         ',class-name
131         ',(class-name (class-of class))
132         ',name
133         ',supplied-initarg-names
134         ;; make-constructor-code-generators is called to return a list
135         ;; of constructor code generators. The actual interpretation
136         ;; of this list is left to compute-constructor-code, but the
137         ;; general idea is that it should be an plist where the keys
138         ;; name a kind of constructor code and the values are generator
139         ;; functions which return the actual constructor code. The
140         ;; constructor code is usually a closures over the arguments
141         ;; to the generator.
142         ,(make-constructor-code-generators class
143                                            name
144                                            lambda-list
145                                            supplied-initarg-names
146                                            supplied-initargs)))))
147
148 (defun load-constructor (class-name metaclass-name constructor-name
149                          supplied-initarg-names code-generators)
150   (let ((class (find-class class-name nil)))
151     (cond ((null class)
152            (error "defconstructor form being loaded (or evaluated) before~@
153                    class ~S is defined."
154                   class-name))
155           ((neq (class-name (class-of class)) metaclass-name)
156            (error "When defconstructor ~S was compiled, the metaclass of the~@
157                    class ~S was ~S. The metaclass is now ~S.~@
158                    The constructor must be recompiled."
159                   constructor-name
160                   class-name
161                   metaclass-name
162                   (class-name (class-of class))))
163           (t
164            (load-constructor-internal class
165                                       constructor-name
166                                       supplied-initarg-names
167                                       code-generators)
168            constructor-name))))
169
170 ;;; The actual constructor objects.
171 (defclass constructor (funcallable-standard-object)
172      ((class                                    ;The class with which this
173         :initarg :class                         ;constructor is associated.
174         :reader constructor-class)              ;The actual class object,
175                                                 ;not the class name.
176
177       (name                                     ;The name of this constructor.
178         :initform nil                           ;This is the symbol in whose
179         :initarg :name                          ;function cell the constructor
180         :reader constructor-name)               ;usually sits. Of course, this
181                                                 ;is optional. defconstructor
182                                                 ;makes named constructors, but
183                                                 ;it is possible to manipulate
184                                                 ;anonymous constructors also.
185
186       (code-type                                ;The type of code currently in
187         :initform nil                           ;use by this constructor. This
188         :accessor constructor-code-type)        ;is mostly for debugging and
189                                                 ;analysis purposes.
190                                                 ;The lazy installer sets this
191                                                 ;to LAZY. The most basic and
192                                                 ;least optimized type of code
193                                                 ;is called FALLBACK.
194
195       (supplied-initarg-names                   ;The names of the initargs this
196         :initarg :supplied-initarg-names        ;constructor supplies when it
197         :reader                                 ;"calls" make-instance.
198            constructor-supplied-initarg-names)  ;
199
200       (code-generators                          ;Generators for the different
201         :initarg :code-generators               ;types of code this constructor
202         :reader constructor-code-generators))   ;could use.
203   (:metaclass funcallable-standard-class))
204
205 ;;; Because the value in the code-type slot should always correspond
206 ;;; to the FUNCALLABLE-INSTANCE-FUN of the constructor, this function
207 ;;; should always be used to set them both at the same time.
208 (defun set-constructor-code (constructor code type)
209   (set-funcallable-instance-fun constructor code)
210   (set-fun-name constructor (constructor-name constructor))
211   (setf (constructor-code-type constructor) type))
212
213 (defmethod describe-object ((constructor constructor) stream)
214   (format stream
215           "~S is a constructor for the class ~S.~%~
216             The current code type is ~S.~%~
217             Other possible code types are ~S."
218           constructor (constructor-class constructor)
219           (constructor-code-type constructor)
220           (gathering1 (collecting)
221             (doplist (key val) (constructor-code-generators constructor)
222               (gather1 key)))))
223
224 ;;; I am not in a hairy enough mood to make this implementation be
225 ;;; metacircular enough that it can support a defconstructor for
226 ;;; constructor objects.
227 (defun make-constructor (class name supplied-initarg-names code-generators)
228   (make-instance 'constructor
229                  :class class
230                  :name name
231                  :supplied-initarg-names supplied-initarg-names
232                  :code-generators code-generators))
233
234 ; This definition actually appears in std-class.lisp.
235 ;(defmethod class-constructors ((class std-class))
236 ;  (with-slots (plist) class (getf plist 'constructors)))
237
238 (defmethod add-constructor ((class slot-class)
239                             (constructor constructor))
240   (with-slots (plist) class
241     (pushnew constructor (getf plist 'constructors))))
242
243 (defmethod remove-constructor ((class slot-class)
244                                (constructor constructor))
245   (with-slots (plist) class
246     (setf (getf plist 'constructors)
247           (delete constructor (getf plist 'constructors)))))
248
249 (defmethod get-constructor ((class slot-class) name &optional (error-p t))
250   (or (dolist (c (class-constructors class))
251         (when (eq (constructor-name c) name) (return c)))
252       (if error-p
253           (error "Couldn't find a constructor with name ~S for class ~S."
254                  name class)
255           ())))
256
257 ;;; This is called to actually load a defconstructor constructor. It
258 ;;; must install the lazy installer in the function cell of the
259 ;;; constructor name, and also add this constructor to the list of
260 ;;; constructors the class has.
261 (defmethod load-constructor-internal
262            ((class slot-class) name initargs generators)
263   (let ((constructor (make-constructor class name initargs generators))
264         (old (get-constructor class name nil)))
265     (when old (remove-constructor class old))
266     (install-lazy-constructor-installer constructor)
267     (add-constructor class constructor)
268     (setf (gdefinition name) constructor)))
269
270 (defmethod install-lazy-constructor-installer ((constructor constructor))
271   (let ((class (constructor-class constructor)))
272     (set-constructor-code constructor
273                           #'(sb-kernel:instance-lambda (&rest args)
274                               (multiple-value-bind (code type)
275                                   (compute-constructor-code class constructor)
276                                 (set-constructor-code constructor code type)
277                                 (apply constructor args)))
278                           'lazy)))
279
280 ;;; the interface to keeping the constructors updated
281 ;;;
282 ;;; add-method and remove-method (for standard-generic-function and
283 ;;; -method), promise to call maybe-update-constructors on the generic
284 ;;; function and the method.
285 ;;;
286 ;;; The class update code promises to call update-constructors
287 ;;; whenever the class is changed. That is, whenever the supers, slots
288 ;;; or options change. If user defined classes of constructor needs to
289 ;;; be updated in more than these circumstances, they should use the
290 ;;; dependent updating mechanism to make sure update-constructors is
291 ;;; called.
292 ;;;
293 ;;; Bootstrapping concerns force the definitions of
294 ;;; maybe-update-constructors and update-constructors to be in the
295 ;;; file std-class. For clarity, they also appear below. Be sure to
296 ;;; keep the definition here and there in sync.
297 ;(defvar *initialization-generic-functions*
298 ;        (list #'make-instance
299 ;              #'default-initargs
300 ;              #'allocate-instance
301 ;              #'initialize-instance
302 ;              #'shared-initialize))
303 ;
304 ;(defmethod maybe-update-constructors
305 ;          ((generic-function generic-function)
306 ;           (method method))
307 ;  (when (memq generic-function *initialization-generic-functions*)
308 ;    (labels ((recurse (class)
309 ;              (update-constructors class)
310 ;              (dolist (subclass (class-direct-subclasses class))
311 ;                (recurse subclass))))
312 ;      (when (classp (car (method-specializers method)))
313 ;       (recurse (car (method-specializers method)))))))
314 ;
315 ;(defmethod update-constructors ((class slot-class))
316 ;  (dolist (cons (class-constructors class))
317 ;    (install-lazy-constructor-installer cons)))
318 ;
319 ;(defmethod update-constructors ((class class))
320 ;  ())
321 \f
322 ;;; Here is the actual smarts for making the code generators and then trying
323 ;;; each generator to get constructor code. This extensible mechanism allows
324 ;;; new kinds of constructor code types to be added. A programmer defining a
325 ;;; specialization of the constructor class can either use this mechanism to
326 ;;; define new code types, or can override this mechanism by overriding the
327 ;;; methods on make-constructor-code-generators and compute-constructor-code.
328 ;;;
329 ;;; The function defined by define-constructor-code-type will receive the
330 ;;; class object, and the 4 original arguments to defconstructor. It can
331 ;;; return a constructor code generator, or return nil if this type of code
332 ;;; is determined to not be appropriate after looking at the defconstructor
333 ;;; arguments.
334 ;;;
335 ;;; When compute-constructor-code is called, it first performs basic checks
336 ;;; to make sure that the basic assumptions common to all the code types are
337 ;;; valid. (For details see method definition). If any of the tests fail,
338 ;;; the fallback constructor code type is used. If none of the tests fail,
339 ;;; the constructor code generators are called in order. They receive 5
340 ;;; arguments:
341 ;;;
342 ;;;   CLASS     the class the constructor is making instances of
343 ;;;   WRAPPER      that class's wrapper
344 ;;;   DEFAULTS     the result of calling class-default-initargs on class
345 ;;;   INITIALIZE   the applicable methods on initialize-instance
346 ;;;   SHARED       the applicable methosd on shared-initialize
347 ;;;
348 ;;; The first code generator to return code is used. The code generators are
349 ;;; called in reverse order of definition, so define-constructor-code-type
350 ;;; forms which define better code should appear after ones that define less
351 ;;; good code. The fallback code type appears first. Note that redefining a
352 ;;; code type does not change its position in the list. To do that,  define
353 ;;; a new type at the end with the behavior.
354
355 (defvar *constructor-code-types* ())
356
357 (defmacro define-constructor-code-type (type arglist &body body)
358   (let ((fn-name (intern (format nil
359                                  "CONSTRUCTOR-CODE-GENERATOR ~A ~A"
360                                  (package-name (symbol-package type))
361                                  (symbol-name type))
362                          *pcl-package*)))
363     `(progn
364        (defun ,fn-name ,arglist .,body)
365        (load-define-constructor-code-type ',type ',fn-name))))
366
367 (defun load-define-constructor-code-type (type generator)
368   (let ((old-entry (assq type *constructor-code-types*)))
369     (if old-entry
370         (setf (cadr old-entry) generator)
371         (push (list type generator) *constructor-code-types*))
372     type))
373
374 (defmethod make-constructor-code-generators
375            ((class slot-class)
376             name lambda-list supplied-initarg-names supplied-initargs)
377   (cons 'list
378         (gathering1 (collecting)
379           (dolist (entry *constructor-code-types*)
380             (let ((generator
381                     (funcall (cadr entry) class name lambda-list
382                                           supplied-initarg-names
383                                           supplied-initargs)))
384               (when generator
385                 (gather1 `',(car entry))
386                 (gather1 generator)))))))
387
388 (defmethod compute-constructor-code ((class slot-class)
389                                      (constructor constructor))
390   (let* ((proto (class-prototype class))
391          (wrapper (class-wrapper class))
392          (defaults (class-default-initargs class))
393          (make
394            (compute-applicable-methods (gdefinition 'make-instance) (list class)))
395          (supplied-initarg-names
396            (constructor-supplied-initarg-names constructor))
397          (default
398            (compute-applicable-methods (gdefinition 'default-initargs)
399                                        (list class supplied-initarg-names))) ;?
400          (allocate
401            (compute-applicable-methods (gdefinition 'allocate-instance)
402                                        (list class)))
403          (initialize
404            (compute-applicable-methods (gdefinition 'initialize-instance)
405                                        (list proto)))
406          (shared
407            (compute-applicable-methods (gdefinition 'shared-initialize)
408                                        (list proto t)))
409          (code-generators
410            (constructor-code-generators constructor)))
411     (flet ((call-code-generator (generator)
412              (when (null generator)
413                (unless (setq generator (getf code-generators 'fallback))
414                  (error "No FALLBACK generator?")))
415              (funcall generator class wrapper defaults initialize shared)))
416       (if (or (cdr make)
417               (cdr default)
418               (cdr allocate)
419               (not (check-initargs-1 class
420                                      supplied-initarg-names
421                                      (append initialize shared)
422                                      nil nil)))
423           ;; These are basic shared assumptions, if one of the
424           ;; has been violated, we have to resort to the fallback
425           ;; case. Any of these assumptions could be moved out
426           ;; of here and into the individual code types if there
427           ;; was a need to do so.
428           (values (call-code-generator nil) 'fallback)
429           ;; Otherwise try all the generators until one produces
430           ;; code for us.
431           (doplist (type generator) code-generators
432             (let ((code (call-code-generator generator)))
433               (when code (return (values code type)))))))))
434
435 ;;; The facilities are useful for debugging, and to measure the performance
436 ;;; boost from constructors.
437 ;;;
438 ;;; FIXME: so they should probably be #+SB-SHOW instead of unconditional
439
440 (defun map-constructors (fn)
441   (let ((nclasses 0)
442         (nconstructors 0))
443     (labels ((recurse (class)
444                (incf nclasses)
445                (dolist (constructor (class-constructors class))
446                  (incf nconstructors)
447                  (funcall fn constructor))
448                (dolist (subclass (class-direct-subclasses class))
449                  (recurse subclass))))
450       (recurse (find-class t))
451       (values nclasses nconstructors))))
452
453 (defun reset-constructors ()
454   (multiple-value-bind (nclass ncons)
455       (map-constructors #'install-lazy-constructor-installer )
456     (format t "~&~W classes, ~W constructors." nclass ncons)))
457
458 (defun disable-constructors ()
459   (multiple-value-bind (nclass ncons)
460       (map-constructors
461         #'(lambda (c)
462             (let ((gen (getf (constructor-code-generators c) 'fallback)))
463               (if (null gen)
464                   (error "No fallback constructor for ~S." c)
465                   (set-constructor-code c
466                                         (funcall gen
467                                                  (constructor-class c)
468                                                  () () () ())
469                                         'fallback)))))
470     (format t "~&~W classes, ~W constructors." nclass ncons)))
471
472 (defun enable-constructors ()
473   (reset-constructors))
474 \f
475 ;;; helper functions and utilities that are shared by all of the code types
476 ;;; and by the main compute-constructor-code method as well
477
478 (defvar *standard-initialize-instance-method*
479         (get-method #'initialize-instance
480                     ()
481                     (list *the-class-slot-object*)))
482
483 (defvar *standard-shared-initialize-method*
484         (get-method #'shared-initialize
485                     ()
486                     (list *the-class-slot-object* *the-class-t*)))
487
488 (defun non-pcl-initialize-instance-methods-p (methods)
489   (notevery #'(lambda (m) (eq m *standard-initialize-instance-method*))
490             methods))
491
492 (defun non-pcl-shared-initialize-methods-p (methods)
493   (notevery #'(lambda (m) (eq m *standard-shared-initialize-method*))
494             methods))
495
496 (defun non-pcl-or-after-initialize-instance-methods-p (methods)
497   (notevery #'(lambda (m) (or (eq m *standard-initialize-instance-method*)
498                               (equal '(:after) (method-qualifiers m))))
499             methods))
500
501 (defun non-pcl-or-after-shared-initialize-methods-p (methods)
502   (notevery #'(lambda (m) (or (eq m *standard-shared-initialize-method*)
503                               (equal '(:after) (method-qualifiers m))))
504             methods))
505
506 ;;; This returns two values. The first is a vector which can be used as the
507 ;;; initial value of the slots vector for the instance. The second is a symbol
508 ;;; describing the initforms this class has.
509 ;;;
510 ;;;  If the first value is:
511 ;;;
512 ;;;    :UNSUPPLIED    no slot has an initform
513 ;;;    :CONSTANTS     all slots have either a constant initform
514 ;;;                   or no initform at all
515 ;;;    T              there is at least one non-constant initform
516 (defun compute-constant-vector (class)
517   ;;(declare (values constants flag))
518   (let* ((wrapper (class-wrapper class))
519          (layout (wrapper-instance-slots-layout wrapper))
520          (flag :unsupplied)
521          (constants ()))
522     (dolist (slotd (class-slots class))
523       (let ((name (slot-definition-name slotd))
524             (initform (slot-definition-initform slotd))
525             (initfn (slot-definition-initfunction slotd)))
526         (cond ((null (memq name layout)))
527               ((null initfn)
528                (push (cons name +slot-unbound+) constants))
529               ((constantp initform)
530                (push (cons name (eval initform)) constants)
531                (when (eq flag ':unsupplied) (setq flag ':constants)))
532               (t
533                (push (cons name +slot-unbound+) constants)
534                (setq flag t)))))
535     (let* ((constants-alist (sort constants #'(lambda (x y)
536                                                 (memq (car y)
537                                                       (memq (car x) layout)))))
538            (constants-list (mapcar #'cdr constants-alist)))
539     (values constants-list flag))))
540
541 ;;; This takes a class and a list of initarg-names, and returns an alist
542 ;;; indicating the positions of the slots those initargs may fill. The
543 ;;; order of the initarg-names argument is important of course, since we
544 ;;; have to respect the rules about the leftmost initarg that fills a slot
545 ;;; having precedence. This function allows initarg names to appear twice
546 ;;; in the list, it only considers the first appearance.
547 (defun compute-initarg-positions (class initarg-names)
548   (let* ((layout (wrapper-instance-slots-layout (class-wrapper class)))
549          (positions
550            (gathering1 (collecting)
551              (iterate ((slot-name (list-elements layout))
552                        (position (interval :from 0)))
553                (gather1 (cons slot-name position)))))
554          (slot-initargs
555            (mapcar #'(lambda (slotd)
556                        (list (slot-definition-initargs slotd)
557                              (or (cdr (assq (slot-definition-name slotd)
558                                             positions))
559                                  ':class)))
560                    (class-slots class))))
561     ;; Go through each of the initargs, and figure out what position
562     ;; it fills by replacing the entries in slot-initargs it fills.
563     (dolist (initarg initarg-names)
564       (dolist (slot-entry slot-initargs)
565         (let ((slot-initargs (car slot-entry)))
566           (when (and (listp slot-initargs)
567                      (not (null slot-initargs))
568                      (memq initarg slot-initargs))
569             (setf (car slot-entry) initarg)))))
570     (gathering1 (collecting)
571       (dolist (initarg initarg-names)
572         (let ((positions (gathering1 (collecting)
573                            (dolist (slot-entry slot-initargs)
574                              (when (eq (car slot-entry) initarg)
575                                (gather1 (cadr slot-entry)))))))
576           (when positions
577             (gather1 (cons initarg positions))))))))
578 \f
579 ;;; The FALLBACK case allows anything. This always works, and always appears
580 ;;; as the last of the generators for a constructor. It does a full call to
581 ;;; make-instance.
582 (define-constructor-code-type fallback
583         (class name arglist supplied-initarg-names supplied-initargs)
584   (declare (ignore name supplied-initarg-names))
585   `(function
586      (lambda (&rest ignore)
587        (declare (ignore ignore))
588        (function
589          (sb-kernel:instance-lambda ,arglist
590            (make-instance
591              ',(class-name class)
592              ,@(gathering1 (collecting)
593                  (iterate ((tail (*list-tails supplied-initargs :by #'cddr)))
594                    (gather1 `',(car tail))
595                    (gather1 (cadr tail))))))))))
596 \f
597 ;;; The GENERAL case allows:
598 ;;;   constant, unsupplied or non-constant initforms
599 ;;;   constant or non-constant default initargs
600 ;;;   supplied initargs
601 ;;;   slot-filling initargs
602 ;;;   :after methods on shared-initialize and initialize-instance
603 (define-constructor-code-type general
604         (class name arglist supplied-initarg-names supplied-initargs)
605   (declare (ignore name))
606   (let ((raw-allocator (raw-instance-allocator class))
607         (slots-fetcher (slots-fetcher class)))
608     `(function
609        (lambda (class .wrapper. defaults init shared)
610          (multiple-value-bind (.constants.
611                                .constant-initargs.
612                                .initfns-initargs-and-positions.
613                                .supplied-initarg-positions.
614                                .shared-initfns.
615                                .initfns.)
616              (general-generator-internal class
617                                          defaults
618                                          init
619                                          shared
620                                          ',supplied-initarg-names
621                                          ',supplied-initargs)
622            .supplied-initarg-positions.
623            (when (and .constants.
624                       (null (non-pcl-or-after-initialize-instance-methods-p
625                               init))
626                       (null (non-pcl-or-after-shared-initialize-methods-p
627                               shared)))
628              (function
629                (sb-kernel:instance-lambda ,arglist
630                  (declare #.*optimize-speed*)
631                  (let* ((.instance. (,raw-allocator .wrapper. .constants.))
632                         (.slots. (,slots-fetcher .instance.))
633                         (.positions. .supplied-initarg-positions.)
634                         (.initargs. .constant-initargs.))
635                    .positions.
636
637                    (dolist (entry .initfns-initargs-and-positions.)
638                      (let ((val (funcall (car entry)))
639                            (initarg (cadr entry)))
640                        (when initarg
641                          (push val .initargs.)
642                          (push initarg .initargs.))
643                        (dolist (pos (cddr entry))
644                          (setf (clos-slots-ref .slots. pos) val))))
645
646                    ,@(gathering1 (collecting)
647                        (doplist (initarg value) supplied-initargs
648                          (unless (constantp value)
649                            (gather1 `(let ((.value. ,value))
650                                        (push .value. .initargs.)
651                                        (push ',initarg .initargs.)
652                                        (dolist (.p. (pop .positions.))
653                                          (setf (clos-slots-ref .slots. .p.)
654                                                .value.)))))))
655
656                    (dolist (fn .shared-initfns.)
657                      (apply fn .instance. t .initargs.))
658                    (dolist (fn .initfns.)
659                      (apply fn .instance. .initargs.))
660
661                    .instance.)))))))))
662
663 (defun general-generator-internal
664        (class defaults init shared supplied-initarg-names supplied-initargs)
665   (flet ((bail-out () (return-from general-generator-internal nil)))
666     (let* ((constants (compute-constant-vector class))
667            (layout (wrapper-instance-slots-layout (class-wrapper class)))
668            (initarg-positions
669              (compute-initarg-positions class
670                                         (append supplied-initarg-names
671                                                 (mapcar #'car defaults))))
672            (initfns-initargs-and-positions ())
673            (supplied-initarg-positions ())
674            (constant-initargs ())
675            (used-positions ()))
676
677       ;; Go through each of the supplied initargs for three reasons.
678       ;;
679       ;;   - If it fills a class slot, bail out.
680       ;;   - If its a constant form, fill the constant vector.
681       ;;   - Otherwise remember the positions no two initargs
682       ;;     will try to fill the same position, since compute
683       ;;     initarg positions already took care of that, but
684       ;;     we do need to know what initforms will and won't
685       ;;     be needed.
686       (doplist (initarg val) supplied-initargs
687         (let ((positions (cdr (assq initarg initarg-positions))))
688           (cond ((memq :class positions) (bail-out))
689                 ((constantp val)
690                  (setq val (eval val))
691                  (push val constant-initargs)
692                  (push initarg constant-initargs)
693                  (dolist (pos positions) (setf (svref constants pos) val)))
694                 (t
695                  (push positions supplied-initarg-positions)))
696           (setq used-positions (append positions used-positions))))
697
698       ;; Go through each of the default initargs, for three reasons.
699       ;;
700       ;;   - If it fills a class slot, bail out.
701       ;;   - If it is a constant, and it does fill a slot, put that
702       ;;     into the constant vector.
703       ;;   - If it isn't a constant, record its initfn and position.
704       (dolist (default defaults)
705         (let* ((name (car default))
706                (initfn (cadr default))
707                (form (caddr default))
708                (value ())
709                (positions (cdr (assq name initarg-positions))))
710           (unless (memq name supplied-initarg-names)
711             (cond ((memq :class positions) (bail-out))
712                   ((constantp form)
713                    (setq value (eval form))
714                    (push value constant-initargs)
715                    (push name constant-initargs)
716                    (dolist (pos positions)
717                      (setf (svref constants pos) value)))
718                   (t
719                    (push (list* initfn name positions)
720                          initfns-initargs-and-positions)))
721             (setq used-positions (append positions used-positions)))))
722
723       ;; Go through each of the slot initforms:
724       ;;
725       ;;    - If its position has already been filled, do nothing.
726       ;;      The initfn won't need to be called, and the slot won't
727       ;;      need to be touched.
728       ;;    - If it is a class slot, and has an initform, bail out.
729       ;;    - If its a constant or unsupplied, ignore it, it is
730       ;;      already in the constant vector.
731       ;;    - Otherwise, record its initfn and position
732       (dolist (slotd (class-slots class))
733         (let* ((alloc (slot-definition-allocation slotd))
734                (name (slot-definition-name slotd))
735                (form (slot-definition-initform slotd))
736                (initfn (slot-definition-initfunction slotd))
737                (position (position name layout)))
738           (cond ((neq alloc :instance)
739                  (unless (null initfn)
740                    (bail-out)))
741                 ((member position used-positions))
742                 ((or (constantp form)
743                      (null initfn)))
744                 (t
745                  (push (list initfn nil position)
746                        initfns-initargs-and-positions)))))
747
748       (values constants
749               constant-initargs
750               (nreverse initfns-initargs-and-positions)
751               (nreverse supplied-initarg-positions)
752               (mapcar #'method-function
753                       (remove *standard-shared-initialize-method* shared))
754               (mapcar #'method-function
755                       (remove *standard-initialize-instance-method* init))))))
756 \f
757 ;;; The NO-METHODS case allows:
758 ;;;   constant, unsupplied or non-constant initforms
759 ;;;   constant or non-constant default initargs
760 ;;;   supplied initargs that are arguments to constructor, or constants
761 ;;;   slot-filling initargs
762 (define-constructor-code-type no-methods
763         (class name arglist supplied-initarg-names supplied-initargs)
764   (declare (ignore name))
765   (let ((raw-allocator (raw-instance-allocator class))
766         (slots-fetcher (slots-fetcher class)))
767     `(function
768        (lambda (class .wrapper. defaults init shared)
769          (multiple-value-bind (.constants.
770                                .initfns-and-positions.
771                                .supplied-initarg-positions.)
772              (no-methods-generator-internal class
773                                             defaults
774                                             ',supplied-initarg-names
775                                             ',supplied-initargs)
776            .initfns-and-positions.
777            .supplied-initarg-positions.
778            (when (and .constants.
779                       (null (non-pcl-initialize-instance-methods-p init))
780                       (null (non-pcl-shared-initialize-methods-p shared)))
781              #'(sb-kernel:instance-lambda ,arglist
782                  (declare #.*optimize-speed*)
783                  (let* ((.instance. (,raw-allocator .wrapper. .constants.))
784                         (.slots. (,slots-fetcher .instance.))
785                         (.positions. .supplied-initarg-positions.))
786                    .positions.
787
788                    (dolist (entry .initfns-and-positions.)
789                      (let ((val (funcall (car entry))))
790                        (dolist (pos (cdr entry))
791                          (setf (clos-slots-ref .slots. pos) val))))
792
793                    ,@(gathering1 (collecting)
794                        (doplist (initarg value) supplied-initargs
795                          (unless (constantp value)
796                            (gather1
797                              `(let ((.value. ,value))
798                                 (dolist (.p. (pop .positions.))
799                                   (setf (clos-slots-ref .slots. .p.)
800                                         .value.)))))))
801
802                    .instance.))))))))
803
804 (defun no-methods-generator-internal
805        (class defaults supplied-initarg-names supplied-initargs)
806   (flet ((bail-out () (return-from no-methods-generator-internal nil)))
807     (let* ((constants   (compute-constant-vector class))
808            (layout (wrapper-instance-slots-layout (class-wrapper class)))
809            (initarg-positions
810              (compute-initarg-positions class
811                                         (append supplied-initarg-names
812                                                 (mapcar #'car defaults))))
813            (initfns-and-positions ())
814            (supplied-initarg-positions ())
815            (used-positions ()))
816
817       ;; Go through each of the supplied initargs for three reasons.
818       ;;
819       ;;   - If it fills a class slot, bail out.
820       ;;   - If its a constant form, fill the constant vector.
821       ;;   - Otherwise remember the positions, no two initargs
822       ;;     will try to fill the same position, since compute
823       ;;     initarg positions already took care of that, but
824       ;;     we do need to know what initforms will and won't
825       ;;     be needed.
826       (doplist (initarg val) supplied-initargs
827         (let ((positions (cdr (assq initarg initarg-positions))))
828           (cond ((memq :class positions) (bail-out))
829                 ((constantp val)
830                  (setq val (eval val))
831                  (dolist (pos positions)
832                    (setf (svref constants pos) val)))
833                 (t
834                  (push positions supplied-initarg-positions)))
835           (setq used-positions (append positions used-positions))))
836
837       ;; Go through each of the default initargs, for three reasons.
838       ;;
839       ;;   - If it fills a class slot, bail out.
840       ;;   - If it is a constant, and it does fill a slot, put that
841       ;;     into the constant vector.
842       ;;   - If it isn't a constant, record its initfn and position.
843       (dolist (default defaults)
844         (let* ((name (car default))
845                (initfn (cadr default))
846                (form (caddr default))
847                (value ())
848                (positions (cdr (assq name initarg-positions))))
849           (unless (memq name supplied-initarg-names)
850             (cond ((memq :class positions) (bail-out))
851                   ((constantp form)
852                    (setq value (eval form))
853                    (dolist (pos positions)
854                      (setf (svref constants pos) value)))
855                   (t
856                    (push (cons initfn positions)
857                          initfns-and-positions)))
858             (setq used-positions (append positions used-positions)))))
859
860       ;; Go through each of the slot initforms:
861       ;;
862       ;;    - If its position has already been filled, do nothing.
863       ;;      The initfn won't need to be called, and the slot won't
864       ;;      need to be touched.
865       ;;    - If it is a class slot, and has an initform, bail out.
866       ;;    - If its a constant or unsupplied, do nothing, we know
867       ;;      that it is already in the constant vector.
868       ;;    - Otherwise, record its initfn and position
869       (dolist (slotd (class-slots class))
870         (let* ((alloc (slot-definition-allocation slotd))
871                (name (slot-definition-name slotd))
872                (form (slot-definition-initform slotd))
873                (initfn (slot-definition-initfunction slotd))
874                (position (position name layout)))
875           (cond ((neq alloc :instance)
876                  (unless (null initfn)
877                    (bail-out)))
878                 ((member position used-positions))
879                 ((or (constantp form)
880                      (null initfn)))
881                 (t
882                  (push (list initfn position) initfns-and-positions)))))
883
884       (values constants
885               (nreverse initfns-and-positions)
886               (nreverse supplied-initarg-positions)))))
887 \f
888 ;;; The SIMPLE-SLOTS case allows:
889 ;;;   constant or unsupplied initforms
890 ;;;   constant default initargs
891 ;;;   supplied initargs
892 ;;;   slot filling initargs
893 (define-constructor-code-type simple-slots
894         (class name arglist supplied-initarg-names supplied-initargs)
895   (declare (ignore name))
896   (let ((raw-allocator (raw-instance-allocator class))
897         (slots-fetcher (slots-fetcher class)))
898     `(function
899        (lambda (class .wrapper. defaults init shared)
900          (when (and (null (non-pcl-initialize-instance-methods-p init))
901                     (null (non-pcl-shared-initialize-methods-p shared)))
902            (multiple-value-bind (.constants. .supplied-initarg-positions.)
903                (simple-slots-generator-internal class
904                                                 defaults
905                                                 ',supplied-initarg-names
906                                                 ',supplied-initargs)
907              (when .constants.
908                (function
909                  (sb-kernel:instance-lambda ,arglist
910                    (declare #.*optimize-speed*)
911                    (let* ((.instance. (,raw-allocator .wrapper. .constants.))
912                           (.slots. (,slots-fetcher .instance.))
913                           (.positions. .supplied-initarg-positions.))
914                      .positions.
915
916                      ,@(gathering1 (collecting)
917                          (doplist (initarg value) supplied-initargs
918                            (unless (constantp value)
919                              (gather1
920                                `(let ((.value. ,value))
921                                   (dolist (.p. (pop .positions.))
922                                     (setf (clos-slots-ref .slots. .p.)
923                                           .value.)))))))
924
925                      .instance.))))))))))
926
927 (defun simple-slots-generator-internal
928        (class defaults supplied-initarg-names supplied-initargs)
929   (flet ((bail-out () (return-from simple-slots-generator-internal nil)))
930     (let* ((constants (compute-constant-vector class))
931            (layout (wrapper-instance-slots-layout (class-wrapper class)))
932            (initarg-positions
933              (compute-initarg-positions class
934                                         (append supplied-initarg-names
935                                                 (mapcar #'car defaults))))
936            (supplied-initarg-positions ())
937            (used-positions ()))
938
939       ;; Go through each of the supplied initargs for three reasons.
940       ;;
941       ;;   - If it fills a class slot, bail out.
942       ;;   - If its a constant form, fill the constant vector.
943       ;;   - Otherwise remember the positions, no two initargs
944       ;;     will try to fill the same position, since compute
945       ;;     initarg positions already took care of that, but
946       ;;     we do need to know what initforms will and won't
947       ;;     be needed.
948       (doplist (initarg val) supplied-initargs
949         (let ((positions (cdr (assq initarg initarg-positions))))
950           (cond ((memq :class positions) (bail-out))
951                 ((constantp val)
952                  (setq val (eval val))
953                  (dolist (pos positions)
954                    (setf (svref constants pos) val)))
955                 (t
956                  (push positions supplied-initarg-positions)))
957           (setq used-positions (append used-positions positions))))
958
959       ;; Go through each of the default initargs for three reasons.
960       ;;
961       ;;   - If it isn't a constant form, bail out.
962       ;;   - If it fills a class slot, bail out.
963       ;;   - If it is a constant, and it does fill a slot, put that
964       ;;     into the constant vector.
965       (dolist (default defaults)
966         (let* ((name (car default))
967                (form (caddr default))
968                (value ())
969                (positions (cdr (assq name initarg-positions))))
970           (unless (memq name supplied-initarg-names)
971             (cond ((memq :class positions) (bail-out))
972                   ((not (constantp form))
973                    (bail-out))
974                   (t
975                    (setq value (eval form))
976                    (dolist (pos positions)
977                      (setf (svref constants pos) value)))))))
978
979       ;; Go through each of the slot initforms:
980       ;;
981       ;;    - If its position has already been filled, do nothing.
982       ;;      The initfn won't need to be called, and the slot won't
983       ;;      need to be touched, we are OK.
984       ;;    - If it has a non-constant initform, bail-out. This
985       ;;      case doesn't handle those.
986       ;;    - If it has a constant or unsupplied initform we don't
987       ;;      really need to do anything, the value is in the
988       ;;      constants vector.
989       (dolist (slotd (class-slots class))
990         (let* ((alloc (slot-definition-allocation slotd))
991                (name (slot-definition-name slotd))
992                (form (slot-definition-initform slotd))
993                (initfn (slot-definition-initfunction slotd))
994                (position (position name layout)))
995           (cond ((neq alloc :instance)
996                  (unless (null initfn)
997                    (bail-out)))
998                 ((member position used-positions))
999                 ((or (constantp form)
1000                      (null initfn)))
1001                 (t
1002                  (bail-out)))))
1003
1004       (values constants (nreverse supplied-initarg-positions)))))