3fc122b50c3ff4839e302530923067fccb662d15
[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           (loop for name in supplied-initargs by #'cddr
108                 collect name)))
109     (when (null class)
110       (error "defconstructor form being compiled (or evaluated) before~@
111               class ~S is defined."
112              class-name))
113     `(progn
114        ;; comments from PCL code back when it was portable:
115        ;;   In order to avoid undefined function warnings, we want to
116        ;;   tell the compile time environment that a function with this
117        ;;   name and this argument list has been defined. The portable
118        ;;   way to do this is with defun:
119        ;;   #-cmu (declaim (notinline ,name))
120        ;;   #-cmu
121        ;;   (defun ,name ,lambda-list
122        ;;     (declare (ignore ,@(extract-parameters lambda-list)))
123        ;;     (error "Constructor ~S not loaded." ',name))
124        ;;   But the derived result type for the above is wrong under CMU CL.
125        ;;   So instead:
126        (declaim (ftype ,(ftype-declaration-from-lambda-list lambda-list name)
127                        ,name))
128        (load-constructor
129         ',class-name
130         ',(class-name (class-of class))
131         ',name
132         ',supplied-initarg-names
133         ;; make-constructor-code-generators is called to return a list
134         ;; of constructor code generators. The actual interpretation
135         ;; of this list is left to compute-constructor-code, but the
136         ;; general idea is that it should be an plist where the keys
137         ;; name a kind of constructor code and the values are generator
138         ;; functions which return the actual constructor code. The
139         ;; constructor code is usually a closures over the arguments
140         ;; to the generator.
141         ,(make-constructor-code-generators class
142                                            name
143                                            lambda-list
144                                            supplied-initarg-names
145                                            supplied-initargs)))))
146
147 (defun load-constructor (class-name metaclass-name constructor-name
148                          supplied-initarg-names code-generators)
149   (let ((class (find-class class-name nil)))
150     (cond ((null class)
151            (error "defconstructor form being loaded (or evaluated) before~@
152                    class ~S is defined."
153                   class-name))
154           ((neq (class-name (class-of class)) metaclass-name)
155            (error "When defconstructor ~S was compiled, the metaclass of the~@
156                    class ~S was ~S. The metaclass is now ~S.~@
157                    The constructor must be recompiled."
158                   constructor-name
159                   class-name
160                   metaclass-name
161                   (class-name (class-of class))))
162           (t
163            (load-constructor-internal class
164                                       constructor-name
165                                       supplied-initarg-names
166                                       code-generators)
167            constructor-name))))
168
169 ;;; The actual constructor objects.
170 (defclass constructor (funcallable-standard-object)
171      ((class                                    ;The class with which this
172         :initarg :class                         ;constructor is associated.
173         :reader constructor-class)              ;The actual class object,
174                                                 ;not the class name.
175
176       (name                                     ;The name of this constructor.
177         :initform nil                           ;This is the symbol in whose
178         :initarg :name                          ;function cell the constructor
179         :reader constructor-name)               ;usually sits. Of course, this
180                                                 ;is optional. defconstructor
181                                                 ;makes named constructors, but
182                                                 ;it is possible to manipulate
183                                                 ;anonymous constructors also.
184
185       (code-type                                ;The type of code currently in
186         :initform nil                           ;use by this constructor. This
187         :accessor constructor-code-type)        ;is mostly for debugging and
188                                                 ;analysis purposes.
189                                                 ;The lazy installer sets this
190                                                 ;to LAZY. The most basic and
191                                                 ;least optimized type of code
192                                                 ;is called FALLBACK.
193
194       (supplied-initarg-names                   ;The names of the initargs this
195         :initarg :supplied-initarg-names        ;constructor supplies when it
196         :reader                                 ;"calls" make-instance.
197            constructor-supplied-initarg-names)  ;
198
199       (code-generators                          ;Generators for the different
200         :initarg :code-generators               ;types of code this constructor
201         :reader constructor-code-generators))   ;could use.
202   (:metaclass funcallable-standard-class))
203
204 ;;; Because the value in the code-type slot should always correspond
205 ;;; to the FUNCALLABLE-INSTANCE-FUN of the constructor, this function
206 ;;; should always be used to set them both at the same time.
207 (defun set-constructor-code (constructor code type)
208   (set-funcallable-instance-fun constructor code)
209   (set-fun-name constructor (constructor-name constructor))
210   (setf (constructor-code-type constructor) type))
211
212 (defmethod describe-object ((constructor constructor) stream)
213   (format stream
214           "~S is a constructor for the class ~S.~%~
215             The current code type is ~S.~%~
216             Other possible code types are ~S."
217           constructor (constructor-class constructor)
218           (constructor-code-type constructor)
219           (let ((collect nil))
220             (doplist (key val) (constructor-code-generators constructor)
221               (push key collect))
222             (nreverse collect))))
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         (let ((collect nil))
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                 (push `',(car entry) collect)
386                 (push generator collect))))
387           (nreverse collect))))
388
389 (defmethod compute-constructor-code ((class slot-class)
390                                      (constructor constructor))
391   (let* ((proto (class-prototype class))
392          (wrapper (class-wrapper class))
393          (defaults (class-default-initargs class))
394          (make
395            (compute-applicable-methods (gdefinition 'make-instance) (list class)))
396          (supplied-initarg-names
397            (constructor-supplied-initarg-names constructor))
398          (default
399            (compute-applicable-methods (gdefinition 'default-initargs)
400                                        (list class supplied-initarg-names))) ;?
401          (allocate
402            (compute-applicable-methods (gdefinition 'allocate-instance)
403                                        (list class)))
404          (initialize
405            (compute-applicable-methods (gdefinition 'initialize-instance)
406                                        (list proto)))
407          (shared
408            (compute-applicable-methods (gdefinition 'shared-initialize)
409                                        (list proto t)))
410          (code-generators
411            (constructor-code-generators constructor)))
412     (flet ((call-code-generator (generator)
413              (when (null generator)
414                (unless (setq generator (getf code-generators 'fallback))
415                  (error "No FALLBACK generator?")))
416              (funcall generator class wrapper defaults initialize shared)))
417       (if (or (cdr make)
418               (cdr default)
419               (cdr allocate)
420               (not (check-initargs-1 class
421                                      supplied-initarg-names
422                                      (append initialize shared)
423                                      nil nil)))
424           ;; These are basic shared assumptions, if one of the
425           ;; has been violated, we have to resort to the fallback
426           ;; case. Any of these assumptions could be moved out
427           ;; of here and into the individual code types if there
428           ;; was a need to do so.
429           (values (call-code-generator nil) 'fallback)
430           ;; Otherwise try all the generators until one produces
431           ;; code for us.
432           (doplist (type generator) code-generators
433             (let ((code (call-code-generator generator)))
434               (when code (return (values code type)))))))))
435
436 ;;; The facilities are useful for debugging, and to measure the performance
437 ;;; boost from constructors.
438 ;;;
439 ;;; FIXME: so they should probably be #+SB-SHOW instead of unconditional
440
441 (defun map-constructors (fn)
442   (let ((nclasses 0)
443         (nconstructors 0))
444     (labels ((recurse (class)
445                (incf nclasses)
446                (dolist (constructor (class-constructors class))
447                  (incf nconstructors)
448                  (funcall fn constructor))
449                (dolist (subclass (class-direct-subclasses class))
450                  (recurse subclass))))
451       (recurse (find-class t))
452       (values nclasses nconstructors))))
453
454 (defun reset-constructors ()
455   (multiple-value-bind (nclass ncons)
456       (map-constructors #'install-lazy-constructor-installer )
457     (format t "~&~W classes, ~W constructors." nclass ncons)))
458
459 (defun disable-constructors ()
460   (multiple-value-bind (nclass ncons)
461       (map-constructors
462         #'(lambda (c)
463             (let ((gen (getf (constructor-code-generators c) 'fallback)))
464               (if (null gen)
465                   (error "No fallback constructor for ~S." c)
466                   (set-constructor-code c
467                                         (funcall gen
468                                                  (constructor-class c)
469                                                  () () () ())
470                                         'fallback)))))
471     (format t "~&~W classes, ~W constructors." nclass ncons)))
472
473 (defun enable-constructors ()
474   (reset-constructors))
475 \f
476 ;;; helper functions and utilities that are shared by all of the code types
477 ;;; and by the main compute-constructor-code method as well
478
479 (defvar *standard-initialize-instance-method*
480         (get-method #'initialize-instance
481                     ()
482                     (list *the-class-slot-object*)))
483
484 (defvar *standard-shared-initialize-method*
485         (get-method #'shared-initialize
486                     ()
487                     (list *the-class-slot-object* *the-class-t*)))
488
489 (defun non-pcl-initialize-instance-methods-p (methods)
490   (notevery #'(lambda (m) (eq m *standard-initialize-instance-method*))
491             methods))
492
493 (defun non-pcl-shared-initialize-methods-p (methods)
494   (notevery #'(lambda (m) (eq m *standard-shared-initialize-method*))
495             methods))
496
497 (defun non-pcl-or-after-initialize-instance-methods-p (methods)
498   (notevery #'(lambda (m) (or (eq m *standard-initialize-instance-method*)
499                               (equal '(:after) (method-qualifiers m))))
500             methods))
501
502 (defun non-pcl-or-after-shared-initialize-methods-p (methods)
503   (notevery #'(lambda (m) (or (eq m *standard-shared-initialize-method*)
504                               (equal '(:after) (method-qualifiers m))))
505             methods))
506
507 ;;; This returns two values. The first is a vector which can be used as the
508 ;;; initial value of the slots vector for the instance. The second is a symbol
509 ;;; describing the initforms this class has.
510 ;;;
511 ;;;  If the first value is:
512 ;;;
513 ;;;    :UNSUPPLIED    no slot has an initform
514 ;;;    :CONSTANTS     all slots have either a constant initform
515 ;;;                   or no initform at all
516 ;;;    T              there is at least one non-constant initform
517 (defun compute-constant-vector (class)
518   ;;(declare (values constants flag))
519   (let* ((wrapper (class-wrapper class))
520          (layout (wrapper-instance-slots-layout wrapper))
521          (flag :unsupplied)
522          (constants ()))
523     (dolist (slotd (class-slots class))
524       (let ((name (slot-definition-name slotd))
525             (initform (slot-definition-initform slotd))
526             (initfn (slot-definition-initfunction slotd)))
527         (cond ((null (memq name layout)))
528               ((null initfn)
529                (push (cons name +slot-unbound+) constants))
530               ((constantp initform)
531                (push (cons name (eval initform)) constants)
532                (when (eq flag ':unsupplied) (setq flag ':constants)))
533               (t
534                (push (cons name +slot-unbound+) constants)
535                (setq flag t)))))
536     (let* ((constants-alist (sort constants #'(lambda (x y)
537                                                 (memq (car y)
538                                                       (memq (car x) layout)))))
539            (constants-list (mapcar #'cdr constants-alist)))
540     (values constants-list flag))))
541
542 ;;; This takes a class and a list of initarg-names, and returns an alist
543 ;;; indicating the positions of the slots those initargs may fill. The
544 ;;; order of the initarg-names argument is important of course, since we
545 ;;; have to respect the rules about the leftmost initarg that fills a slot
546 ;;; having precedence. This function allows initarg names to appear twice
547 ;;; in the list, it only considers the first appearance.
548 (defun compute-initarg-positions (class initarg-names)
549   (let* ((layout (wrapper-instance-slots-layout (class-wrapper class)))
550          (positions
551            (loop for slot-name in layout
552                  for position from 0
553                  collect (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     (let (collect)
571       (dolist (initarg initarg-names)
572         (let ((positions (let (collect)
573                            (dolist (slot-entry slot-initargs)
574                              (when (eq (car slot-entry) initarg)
575                                (push (cadr slot-entry) collect)))
576                            (nreverse collect))))
577           (when positions
578             (push (cons initarg positions) collect))))
579       (nreverse collect))))
580 \f
581 ;;; The FALLBACK case allows anything. This always works, and always appears
582 ;;; as the last of the generators for a constructor. It does a full call to
583 ;;; make-instance.
584 (define-constructor-code-type fallback
585         (class name arglist supplied-initarg-names supplied-initargs)
586   (declare (ignore name supplied-initarg-names))
587   `(function
588      (lambda (&rest ignore)
589        (declare (ignore ignore))
590        (function
591          (sb-kernel:instance-lambda ,arglist
592            (make-instance
593              ',(class-name class)
594              ,@(let (collect)
595                  (loop for tail on supplied-initargs by #'cddr
596                        do (push `',(car tail) collect)
597                           (push (cadr tail) collect))
598                  (nreverse collect))))))))
599 \f
600 ;;; The GENERAL case allows:
601 ;;;   constant, unsupplied or non-constant initforms
602 ;;;   constant or non-constant default initargs
603 ;;;   supplied initargs
604 ;;;   slot-filling initargs
605 ;;;   :after methods on shared-initialize and initialize-instance
606 (define-constructor-code-type general
607         (class name arglist supplied-initarg-names supplied-initargs)
608   (declare (ignore name))
609   (let ((raw-allocator (raw-instance-allocator class))
610         (slots-fetcher (slots-fetcher class)))
611     `(function
612        (lambda (class .wrapper. defaults init shared)
613          (multiple-value-bind (.constants.
614                                .constant-initargs.
615                                .initfns-initargs-and-positions.
616                                .supplied-initarg-positions.
617                                .shared-initfns.
618                                .initfns.)
619              (general-generator-internal class
620                                          defaults
621                                          init
622                                          shared
623                                          ',supplied-initarg-names
624                                          ',supplied-initargs)
625            .supplied-initarg-positions.
626            (when (and .constants.
627                       (null (non-pcl-or-after-initialize-instance-methods-p
628                               init))
629                       (null (non-pcl-or-after-shared-initialize-methods-p
630                               shared)))
631              (function
632                (sb-kernel:instance-lambda ,arglist
633                  (declare #.*optimize-speed*)
634                  (let* ((.instance. (,raw-allocator .wrapper. .constants.))
635                         (.slots. (,slots-fetcher .instance.))
636                         (.positions. .supplied-initarg-positions.)
637                         (.initargs. .constant-initargs.))
638                    .positions.
639
640                    (dolist (entry .initfns-initargs-and-positions.)
641                      (let ((val (funcall (car entry)))
642                            (initarg (cadr entry)))
643                        (when initarg
644                          (push val .initargs.)
645                          (push initarg .initargs.))
646                        (dolist (pos (cddr entry))
647                          (setf (clos-slots-ref .slots. pos) val))))
648
649                    ,@(let (collect)
650                        (doplist (initarg value) supplied-initargs
651                          (unless (constantp value)
652                            (push `(let ((.value. ,value))
653                                    (push .value. .initargs.)
654                                    (push ',initarg .initargs.)
655                                    (dolist (.p. (pop .positions.))
656                                      (setf (clos-slots-ref .slots. .p.)
657                                            .value.)))
658                                  collect)))
659                        (nreverse collect))
660
661                    (dolist (fn .shared-initfns.)
662                      (apply fn .instance. t .initargs.))
663                    (dolist (fn .initfns.)
664                      (apply fn .instance. .initargs.))
665
666                    .instance.)))))))))
667
668 (defun general-generator-internal
669        (class defaults init shared supplied-initarg-names supplied-initargs)
670   (flet ((bail-out () (return-from general-generator-internal nil)))
671     (let* ((constants (compute-constant-vector class))
672            (layout (wrapper-instance-slots-layout (class-wrapper class)))
673            (initarg-positions
674              (compute-initarg-positions class
675                                         (append supplied-initarg-names
676                                                 (mapcar #'car defaults))))
677            (initfns-initargs-and-positions ())
678            (supplied-initarg-positions ())
679            (constant-initargs ())
680            (used-positions ()))
681
682       ;; Go through each of the supplied initargs for three reasons.
683       ;;
684       ;;   - If it fills a class slot, bail out.
685       ;;   - If its a constant form, fill the constant vector.
686       ;;   - Otherwise remember the positions no two initargs
687       ;;     will try to fill the same position, since compute
688       ;;     initarg positions already took care of that, but
689       ;;     we do need to know what initforms will and won't
690       ;;     be needed.
691       (doplist (initarg val) supplied-initargs
692         (let ((positions (cdr (assq initarg initarg-positions))))
693           (cond ((memq :class positions) (bail-out))
694                 ((constantp val)
695                  (setq val (eval val))
696                  (push val constant-initargs)
697                  (push initarg constant-initargs)
698                  (dolist (pos positions) (setf (svref constants pos) val)))
699                 (t
700                  (push positions supplied-initarg-positions)))
701           (setq used-positions (append positions used-positions))))
702
703       ;; Go through each of the default initargs, for three reasons.
704       ;;
705       ;;   - If it fills a class slot, bail out.
706       ;;   - If it is a constant, and it does fill a slot, put that
707       ;;     into the constant vector.
708       ;;   - If it isn't a constant, record its initfn and position.
709       (dolist (default defaults)
710         (let* ((name (car default))
711                (initfn (cadr default))
712                (form (caddr default))
713                (value ())
714                (positions (cdr (assq name initarg-positions))))
715           (unless (memq name supplied-initarg-names)
716             (cond ((memq :class positions) (bail-out))
717                   ((constantp form)
718                    (setq value (eval form))
719                    (push value constant-initargs)
720                    (push name constant-initargs)
721                    (dolist (pos positions)
722                      (setf (svref constants pos) value)))
723                   (t
724                    (push (list* initfn name positions)
725                          initfns-initargs-and-positions)))
726             (setq used-positions (append positions used-positions)))))
727
728       ;; Go through each of the slot initforms:
729       ;;
730       ;;    - If its position has already been filled, do nothing.
731       ;;      The initfn won't need to be called, and the slot won't
732       ;;      need to be touched.
733       ;;    - If it is a class slot, and has an initform, bail out.
734       ;;    - If its a constant or unsupplied, ignore it, it is
735       ;;      already in the constant vector.
736       ;;    - Otherwise, record its initfn and position
737       (dolist (slotd (class-slots class))
738         (let* ((alloc (slot-definition-allocation slotd))
739                (name (slot-definition-name slotd))
740                (form (slot-definition-initform slotd))
741                (initfn (slot-definition-initfunction slotd))
742                (position (position name layout)))
743           (cond ((neq alloc :instance)
744                  (unless (null initfn)
745                    (bail-out)))
746                 ((member position used-positions))
747                 ((or (constantp form)
748                      (null initfn)))
749                 (t
750                  (push (list initfn nil position)
751                        initfns-initargs-and-positions)))))
752
753       (values constants
754               constant-initargs
755               (nreverse initfns-initargs-and-positions)
756               (nreverse supplied-initarg-positions)
757               (mapcar #'method-function
758                       (remove *standard-shared-initialize-method* shared))
759               (mapcar #'method-function
760                       (remove *standard-initialize-instance-method* init))))))
761 \f
762 ;;; The NO-METHODS case allows:
763 ;;;   constant, unsupplied or non-constant initforms
764 ;;;   constant or non-constant default initargs
765 ;;;   supplied initargs that are arguments to constructor, or constants
766 ;;;   slot-filling initargs
767 (define-constructor-code-type no-methods
768         (class name arglist supplied-initarg-names supplied-initargs)
769   (declare (ignore name))
770   (let ((raw-allocator (raw-instance-allocator class))
771         (slots-fetcher (slots-fetcher class)))
772     `(function
773        (lambda (class .wrapper. defaults init shared)
774          (multiple-value-bind (.constants.
775                                .initfns-and-positions.
776                                .supplied-initarg-positions.)
777              (no-methods-generator-internal class
778                                             defaults
779                                             ',supplied-initarg-names
780                                             ',supplied-initargs)
781            .initfns-and-positions.
782            .supplied-initarg-positions.
783            (when (and .constants.
784                       (null (non-pcl-initialize-instance-methods-p init))
785                       (null (non-pcl-shared-initialize-methods-p shared)))
786              #'(sb-kernel:instance-lambda ,arglist
787                  (declare #.*optimize-speed*)
788                  (let* ((.instance. (,raw-allocator .wrapper. .constants.))
789                         (.slots. (,slots-fetcher .instance.))
790                         (.positions. .supplied-initarg-positions.))
791                    .positions.
792
793                    (dolist (entry .initfns-and-positions.)
794                      (let ((val (funcall (car entry))))
795                        (dolist (pos (cdr entry))
796                          (setf (clos-slots-ref .slots. pos) val))))
797
798                    ,@(let (collect)
799                        (doplist (initarg value) supplied-initargs
800                          (unless (constantp value)
801                            (push
802                              `(let ((.value. ,value))
803                                 (dolist (.p. (pop .positions.))
804                                   (setf (clos-slots-ref .slots. .p.)
805                                         .value.)))
806                              collect)))
807                        (nreverse collect))
808
809                    .instance.))))))))
810
811 (defun no-methods-generator-internal
812        (class defaults supplied-initarg-names supplied-initargs)
813   (flet ((bail-out () (return-from no-methods-generator-internal nil)))
814     (let* ((constants   (compute-constant-vector class))
815            (layout (wrapper-instance-slots-layout (class-wrapper class)))
816            (initarg-positions
817              (compute-initarg-positions class
818                                         (append supplied-initarg-names
819                                                 (mapcar #'car defaults))))
820            (initfns-and-positions ())
821            (supplied-initarg-positions ())
822            (used-positions ()))
823
824       ;; Go through each of the supplied initargs for three reasons.
825       ;;
826       ;;   - If it fills a class slot, bail out.
827       ;;   - If its a constant form, fill the constant vector.
828       ;;   - Otherwise remember the positions, no two initargs
829       ;;     will try to fill the same position, since compute
830       ;;     initarg positions already took care of that, but
831       ;;     we do need to know what initforms will and won't
832       ;;     be needed.
833       (doplist (initarg val) supplied-initargs
834         (let ((positions (cdr (assq initarg initarg-positions))))
835           (cond ((memq :class positions) (bail-out))
836                 ((constantp val)
837                  (setq val (eval val))
838                  (dolist (pos positions)
839                    (setf (svref constants pos) val)))
840                 (t
841                  (push positions supplied-initarg-positions)))
842           (setq used-positions (append positions used-positions))))
843
844       ;; Go through each of the default initargs, for three reasons.
845       ;;
846       ;;   - If it fills a class slot, bail out.
847       ;;   - If it is a constant, and it does fill a slot, put that
848       ;;     into the constant vector.
849       ;;   - If it isn't a constant, record its initfn and position.
850       (dolist (default defaults)
851         (let* ((name (car default))
852                (initfn (cadr default))
853                (form (caddr default))
854                (value ())
855                (positions (cdr (assq name initarg-positions))))
856           (unless (memq name supplied-initarg-names)
857             (cond ((memq :class positions) (bail-out))
858                   ((constantp form)
859                    (setq value (eval form))
860                    (dolist (pos positions)
861                      (setf (svref constants pos) value)))
862                   (t
863                    (push (cons initfn positions)
864                          initfns-and-positions)))
865             (setq used-positions (append positions used-positions)))))
866
867       ;; Go through each of the slot initforms:
868       ;;
869       ;;    - If its position has already been filled, do nothing.
870       ;;      The initfn won't need to be called, and the slot won't
871       ;;      need to be touched.
872       ;;    - If it is a class slot, and has an initform, bail out.
873       ;;    - If its a constant or unsupplied, do nothing, we know
874       ;;      that it is already in the constant vector.
875       ;;    - Otherwise, record its initfn and position
876       (dolist (slotd (class-slots class))
877         (let* ((alloc (slot-definition-allocation slotd))
878                (name (slot-definition-name slotd))
879                (form (slot-definition-initform slotd))
880                (initfn (slot-definition-initfunction slotd))
881                (position (position name layout)))
882           (cond ((neq alloc :instance)
883                  (unless (null initfn)
884                    (bail-out)))
885                 ((member position used-positions))
886                 ((or (constantp form)
887                      (null initfn)))
888                 (t
889                  (push (list initfn position) initfns-and-positions)))))
890
891       (values constants
892               (nreverse initfns-and-positions)
893               (nreverse supplied-initarg-positions)))))
894 \f
895 ;;; The SIMPLE-SLOTS case allows:
896 ;;;   constant or unsupplied initforms
897 ;;;   constant default initargs
898 ;;;   supplied initargs
899 ;;;   slot filling initargs
900 (define-constructor-code-type simple-slots
901         (class name arglist supplied-initarg-names supplied-initargs)
902   (declare (ignore name))
903   (let ((raw-allocator (raw-instance-allocator class))
904         (slots-fetcher (slots-fetcher class)))
905     `(function
906        (lambda (class .wrapper. defaults init shared)
907          (when (and (null (non-pcl-initialize-instance-methods-p init))
908                     (null (non-pcl-shared-initialize-methods-p shared)))
909            (multiple-value-bind (.constants. .supplied-initarg-positions.)
910                (simple-slots-generator-internal class
911                                                 defaults
912                                                 ',supplied-initarg-names
913                                                 ',supplied-initargs)
914              (when .constants.
915                (function
916                  (sb-kernel:instance-lambda ,arglist
917                    (declare #.*optimize-speed*)
918                    (let* ((.instance. (,raw-allocator .wrapper. .constants.))
919                           (.slots. (,slots-fetcher .instance.))
920                           (.positions. .supplied-initarg-positions.))
921                      .positions.
922
923                      ,@(let (collect)
924                          (doplist (initarg value) supplied-initargs
925                            (unless (constantp value)
926                              (push
927                                `(let ((.value. ,value))
928                                   (dolist (.p. (pop .positions.))
929                                     (setf (clos-slots-ref .slots. .p.)
930                                           .value.)))
931                                collect)))
932                          (nreverse collect))
933
934                      .instance.))))))))))
935
936 (defun simple-slots-generator-internal
937        (class defaults supplied-initarg-names supplied-initargs)
938   (flet ((bail-out () (return-from simple-slots-generator-internal nil)))
939     (let* ((constants (compute-constant-vector class))
940            (layout (wrapper-instance-slots-layout (class-wrapper class)))
941            (initarg-positions
942              (compute-initarg-positions class
943                                         (append supplied-initarg-names
944                                                 (mapcar #'car defaults))))
945            (supplied-initarg-positions ())
946            (used-positions ()))
947
948       ;; Go through each of the supplied initargs for three reasons.
949       ;;
950       ;;   - If it fills a class slot, bail out.
951       ;;   - If its a constant form, fill the constant vector.
952       ;;   - Otherwise remember the positions, no two initargs
953       ;;     will try to fill the same position, since compute
954       ;;     initarg positions already took care of that, but
955       ;;     we do need to know what initforms will and won't
956       ;;     be needed.
957       (doplist (initarg val) supplied-initargs
958         (let ((positions (cdr (assq initarg initarg-positions))))
959           (cond ((memq :class positions) (bail-out))
960                 ((constantp val)
961                  (setq val (eval val))
962                  (dolist (pos positions)
963                    (setf (svref constants pos) val)))
964                 (t
965                  (push positions supplied-initarg-positions)))
966           (setq used-positions (append used-positions positions))))
967
968       ;; Go through each of the default initargs for three reasons.
969       ;;
970       ;;   - If it isn't a constant form, bail out.
971       ;;   - If it fills a class slot, bail out.
972       ;;   - If it is a constant, and it does fill a slot, put that
973       ;;     into the constant vector.
974       (dolist (default defaults)
975         (let* ((name (car default))
976                (form (caddr default))
977                (value ())
978                (positions (cdr (assq name initarg-positions))))
979           (unless (memq name supplied-initarg-names)
980             (cond ((memq :class positions) (bail-out))
981                   ((not (constantp form))
982                    (bail-out))
983                   (t
984                    (setq value (eval form))
985                    (dolist (pos positions)
986                      (setf (svref constants pos) value)))))))
987
988       ;; Go through each of the slot initforms:
989       ;;
990       ;;    - If its position has already been filled, do nothing.
991       ;;      The initfn won't need to be called, and the slot won't
992       ;;      need to be touched, we are OK.
993       ;;    - If it has a non-constant initform, bail-out. This
994       ;;      case doesn't handle those.
995       ;;    - If it has a constant or unsupplied initform we don't
996       ;;      really need to do anything, the value is in the
997       ;;      constants vector.
998       (dolist (slotd (class-slots class))
999         (let* ((alloc (slot-definition-allocation slotd))
1000                (name (slot-definition-name slotd))
1001                (form (slot-definition-initform slotd))
1002                (initfn (slot-definition-initfunction slotd))
1003                (position (position name layout)))
1004           (cond ((neq alloc :instance)
1005                  (unless (null initfn)
1006                    (bail-out)))
1007                 ((member position used-positions))
1008                 ((or (constantp form)
1009                      (null initfn)))
1010                 (t
1011                  (bail-out)))))
1012
1013       (values constants (nreverse supplied-initarg-positions)))))