1 ;;;; This file defines the defconstructor and other make-instance optimization
4 ;;;; This software is part of the SBCL system. See the README file for
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
13 ;;;; copyright information from original PCL sources:
15 ;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
16 ;;;; All rights reserved.
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
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
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.
38 ;;; A call to defconstructor like:
40 ;;; (defconstructor make-foo foo (a b &rest r) a a :mumble b baz r)
42 ;;; Is equivalent to a defun like:
44 ;;; (defun make-foo (a b &rest r)
45 ;;; (make-instance 'foo 'a a ':mumble b 'baz r))
47 ;;; Calls like the following are also legal:
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))
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.
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.
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.
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.
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
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.
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
97 (defmacro defconstructor
98 (name class lambda-list &rest initialization-arguments)
99 (expand-defconstructor class
102 (copy-list initialization-arguments)))
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)))
111 (error "defconstructor form being compiled (or evaluated) before~@
112 class ~S is defined."
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))
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.
127 (declaim (ftype ,(ftype-declaration-from-lambda-list lambda-list name)
131 ',(class-name (class-of class))
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
142 ,(make-constructor-code-generators class
145 supplied-initarg-names
146 supplied-initargs)))))
148 (defun load-constructor (class-name metaclass-name constructor-name
149 supplied-initarg-names code-generators)
150 (let ((class (find-class class-name nil)))
152 (error "defconstructor form being loaded (or evaluated) before~@
153 class ~S is defined."
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."
162 (class-name (class-of class))))
164 (load-constructor-internal class
166 supplied-initarg-names
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,
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.
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
190 ;The lazy installer sets this
191 ;to LAZY. The most basic and
192 ;least optimized type of code
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) ;
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))
205 ;;; Because the value in the code-type slot should always correspond to the
206 ;;; funcallable-instance-function of the constructor, this function should
207 ;;; always be used to set the both at the same time.
208 (defun set-constructor-code (constructor code type)
209 (set-funcallable-instance-function constructor code)
210 (set-function-name constructor (constructor-name constructor))
211 (setf (constructor-code-type constructor) type))
213 (defmethod describe-object ((constructor constructor) 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)
224 ;;; I am not in a hairy enough mood to make this implementation be metacircular
225 ;;; enough that it can support a defconstructor for constructor objects.
226 (defun make-constructor (class name supplied-initarg-names code-generators)
227 (make-instance 'constructor
230 :supplied-initarg-names supplied-initarg-names
231 :code-generators code-generators))
233 ; This definition actually appears in std-class.lisp.
234 ;(defmethod class-constructors ((class std-class))
235 ; (with-slots (plist) class (getf plist 'constructors)))
237 (defmethod add-constructor ((class slot-class)
238 (constructor constructor))
239 (with-slots (plist) class
240 (pushnew constructor (getf plist 'constructors))))
242 (defmethod remove-constructor ((class slot-class)
243 (constructor constructor))
244 (with-slots (plist) class
245 (setf (getf plist 'constructors)
246 (delete constructor (getf plist 'constructors)))))
248 (defmethod get-constructor ((class slot-class) name &optional (error-p t))
249 (or (dolist (c (class-constructors class))
250 (when (eq (constructor-name c) name) (return c)))
252 (error "Couldn't find a constructor with name ~S for class ~S."
256 ;;; This is called to actually load a defconstructor constructor. It must
257 ;;; install the lazy installer in the function cell of the constructor name,
258 ;;; and also add this constructor to the list of constructors the class has.
259 (defmethod load-constructor-internal
260 ((class slot-class) name initargs generators)
261 (let ((constructor (make-constructor class name initargs generators))
262 (old (get-constructor class name nil)))
263 (when old (remove-constructor class old))
264 (install-lazy-constructor-installer constructor)
265 (add-constructor class constructor)
266 (setf (gdefinition name) constructor)))
268 (defmethod install-lazy-constructor-installer ((constructor constructor))
269 (let ((class (constructor-class constructor)))
270 (set-constructor-code constructor
271 #'(sb-kernel:instance-lambda (&rest args)
272 (multiple-value-bind (code type)
273 (compute-constructor-code class constructor)
274 (set-constructor-code constructor code type)
275 (apply constructor args)))
278 ;;; The interface to keeping the constructors updated.
280 ;;; add-method and remove-method (for standard-generic-function and -method),
281 ;;; promise to call maybe-update-constructors on the generic function and
284 ;;; The class update code promises to call update-constructors whenever the
285 ;;; class is changed. That is, whenever the supers, slots or options change.
286 ;;; If user defined classes of constructor needs to be updated in more than
287 ;;; these circumstances, they should use the dependent updating mechanism to
288 ;;; make sure update-constructors is called.
290 ;;; Bootstrapping concerns force the definitions of maybe-update-constructors
291 ;;; and update-constructors to be in the file std-class. For clarity, they
292 ;;; also appear below. Be sure to keep the definition here and there in sync.
293 ;(defvar *initialization-generic-functions*
294 ; (list #'make-instance
296 ; #'allocate-instance
297 ; #'initialize-instance
298 ; #'shared-initialize))
300 ;(defmethod maybe-update-constructors
301 ; ((generic-function generic-function)
303 ; (when (memq generic-function *initialization-generic-functions*)
304 ; (labels ((recurse (class)
305 ; (update-constructors class)
306 ; (dolist (subclass (class-direct-subclasses class))
307 ; (recurse subclass))))
308 ; (when (classp (car (method-specializers method)))
309 ; (recurse (car (method-specializers method)))))))
311 ;(defmethod update-constructors ((class slot-class))
312 ; (dolist (cons (class-constructors class))
313 ; (install-lazy-constructor-installer cons)))
315 ;(defmethod update-constructors ((class class))
318 ;;; Here is the actual smarts for making the code generators and then trying
319 ;;; each generator to get constructor code. This extensible mechanism allows
320 ;;; new kinds of constructor code types to be added. A programmer defining a
321 ;;; specialization of the constructor class can either use this mechanism to
322 ;;; define new code types, or can override this mechanism by overriding the
323 ;;; methods on make-constructor-code-generators and compute-constructor-code.
325 ;;; The function defined by define-constructor-code-type will receive the
326 ;;; class object, and the 4 original arguments to defconstructor. It can
327 ;;; return a constructor code generator, or return nil if this type of code
328 ;;; is determined to not be appropriate after looking at the defconstructor
331 ;;; When compute-constructor-code is called, it first performs basic checks
332 ;;; to make sure that the basic assumptions common to all the code types are
333 ;;; valid. (For details see method definition). If any of the tests fail,
334 ;;; the fallback constructor code type is used. If none of the tests fail,
335 ;;; the constructor code generators are called in order. They receive 5
338 ;;; CLASS the class the constructor is making instances of
339 ;;; WRAPPER that class's wrapper
340 ;;; DEFAULTS the result of calling class-default-initargs on class
341 ;;; INITIALIZE the applicable methods on initialize-instance
342 ;;; SHARED the applicable methosd on shared-initialize
344 ;;; The first code generator to return code is used. The code generators are
345 ;;; called in reverse order of definition, so define-constructor-code-type
346 ;;; forms which define better code should appear after ones that define less
347 ;;; good code. The fallback code type appears first. Note that redefining a
348 ;;; code type does not change its position in the list. To do that, define
349 ;;; a new type at the end with the behavior.
351 (defvar *constructor-code-types* ())
353 (defmacro define-constructor-code-type (type arglist &body body)
354 (let ((fn-name (intern (format nil
355 "CONSTRUCTOR-CODE-GENERATOR ~A ~A"
356 (package-name (symbol-package type))
360 (defun ,fn-name ,arglist .,body)
361 (load-define-constructor-code-type ',type ',fn-name))))
363 (defun load-define-constructor-code-type (type generator)
364 (let ((old-entry (assq type *constructor-code-types*)))
366 (setf (cadr old-entry) generator)
367 (push (list type generator) *constructor-code-types*))
370 (defmethod make-constructor-code-generators
372 name lambda-list supplied-initarg-names supplied-initargs)
374 (gathering1 (collecting)
375 (dolist (entry *constructor-code-types*)
377 (funcall (cadr entry) class name lambda-list
378 supplied-initarg-names
381 (gather1 `',(car entry))
382 (gather1 generator)))))))
384 (defmethod compute-constructor-code ((class slot-class)
385 (constructor constructor))
386 (let* ((proto (class-prototype class))
387 (wrapper (class-wrapper class))
388 (defaults (class-default-initargs class))
390 (compute-applicable-methods (gdefinition 'make-instance) (list class)))
391 (supplied-initarg-names
392 (constructor-supplied-initarg-names constructor))
394 (compute-applicable-methods (gdefinition 'default-initargs)
395 (list class supplied-initarg-names))) ;?
397 (compute-applicable-methods (gdefinition 'allocate-instance)
400 (compute-applicable-methods (gdefinition 'initialize-instance)
403 (compute-applicable-methods (gdefinition 'shared-initialize)
406 (constructor-code-generators constructor)))
407 (flet ((call-code-generator (generator)
408 (when (null generator)
409 (unless (setq generator (getf code-generators 'fallback))
410 (error "No FALLBACK generator?")))
411 (funcall generator class wrapper defaults initialize shared)))
415 (not (check-initargs-1 class
416 supplied-initarg-names
417 (append initialize shared)
419 ;; These are basic shared assumptions, if one of the
420 ;; has been violated, we have to resort to the fallback
421 ;; case. Any of these assumptions could be moved out
422 ;; of here and into the individual code types if there
423 ;; was a need to do so.
424 (values (call-code-generator nil) 'fallback)
425 ;; Otherwise try all the generators until one produces
427 (doplist (type generator) code-generators
428 (let ((code (call-code-generator generator)))
429 (when code (return (values code type)))))))))
431 ;;; The facilities are useful for debugging, and to measure the performance
432 ;;; boost from constructors.
434 ;;; FIXME: so they should probably be #+SB-SHOW instead of unconditional
436 (defun map-constructors (fn)
439 (labels ((recurse (class)
441 (dolist (constructor (class-constructors class))
443 (funcall fn constructor))
444 (dolist (subclass (class-direct-subclasses class))
445 (recurse subclass))))
446 (recurse (find-class t))
447 (values nclasses nconstructors))))
449 (defun reset-constructors ()
450 (multiple-value-bind (nclass ncons)
451 (map-constructors #'install-lazy-constructor-installer )
452 (format t "~&~D classes, ~D constructors." nclass ncons)))
454 (defun disable-constructors ()
455 (multiple-value-bind (nclass ncons)
458 (let ((gen (getf (constructor-code-generators c) 'fallback)))
460 (error "No fallback constructor for ~S." c)
461 (set-constructor-code c
463 (constructor-class c)
466 (format t "~&~D classes, ~D constructors." nclass ncons)))
468 (defun enable-constructors ()
469 (reset-constructors))
471 ;;; helper functions and utilities that are shared by all of the code types
472 ;;; and by the main compute-constructor-code method as well
474 (defvar *standard-initialize-instance-method*
475 (get-method #'initialize-instance
477 (list *the-class-slot-object*)))
479 (defvar *standard-shared-initialize-method*
480 (get-method #'shared-initialize
482 (list *the-class-slot-object* *the-class-t*)))
484 (defun non-pcl-initialize-instance-methods-p (methods)
485 (notevery #'(lambda (m) (eq m *standard-initialize-instance-method*))
488 (defun non-pcl-shared-initialize-methods-p (methods)
489 (notevery #'(lambda (m) (eq m *standard-shared-initialize-method*))
492 (defun non-pcl-or-after-initialize-instance-methods-p (methods)
493 (notevery #'(lambda (m) (or (eq m *standard-initialize-instance-method*)
494 (equal '(:after) (method-qualifiers m))))
497 (defun non-pcl-or-after-shared-initialize-methods-p (methods)
498 (notevery #'(lambda (m) (or (eq m *standard-shared-initialize-method*)
499 (equal '(:after) (method-qualifiers m))))
502 ;;; This returns two values. The first is a vector which can be used as the
503 ;;; initial value of the slots vector for the instance. The second is a symbol
504 ;;; describing the initforms this class has.
506 ;;; If the first value is:
508 ;;; :UNSUPPLIED no slot has an initform
509 ;;; :CONSTANTS all slots have either a constant initform
510 ;;; or no initform at all
511 ;;; T there is at least one non-constant initform
512 (defun compute-constant-vector (class)
513 ;;(declare (values constants flag))
514 (let* ((wrapper (class-wrapper class))
515 (layout (wrapper-instance-slots-layout wrapper))
518 (dolist (slotd (class-slots class))
519 (let ((name (slot-definition-name slotd))
520 (initform (slot-definition-initform slotd))
521 (initfn (slot-definition-initfunction slotd)))
522 (cond ((null (memq name layout)))
524 (push (cons name +slot-unbound+) constants))
525 ((constantp initform)
526 (push (cons name (eval initform)) constants)
527 (when (eq flag ':unsupplied) (setq flag ':constants)))
529 (push (cons name +slot-unbound+) constants)
531 (let* ((constants-alist (sort constants #'(lambda (x y)
533 (memq (car x) layout)))))
534 (constants-list (mapcar #'cdr constants-alist)))
535 (values constants-list flag))))
537 ;;; This takes a class and a list of initarg-names, and returns an alist
538 ;;; indicating the positions of the slots those initargs may fill. The
539 ;;; order of the initarg-names argument is important of course, since we
540 ;;; have to respect the rules about the leftmost initarg that fills a slot
541 ;;; having precedence. This function allows initarg names to appear twice
542 ;;; in the list, it only considers the first appearance.
543 (defun compute-initarg-positions (class initarg-names)
544 (let* ((layout (wrapper-instance-slots-layout (class-wrapper class)))
546 (gathering1 (collecting)
547 (iterate ((slot-name (list-elements layout))
548 (position (interval :from 0)))
549 (gather1 (cons slot-name position)))))
551 (mapcar #'(lambda (slotd)
552 (list (slot-definition-initargs slotd)
553 (or (cdr (assq (slot-definition-name slotd)
556 (class-slots class))))
557 ;; Go through each of the initargs, and figure out what position
558 ;; it fills by replacing the entries in slot-initargs it fills.
559 (dolist (initarg initarg-names)
560 (dolist (slot-entry slot-initargs)
561 (let ((slot-initargs (car slot-entry)))
562 (when (and (listp slot-initargs)
563 (not (null slot-initargs))
564 (memq initarg slot-initargs))
565 (setf (car slot-entry) initarg)))))
566 (gathering1 (collecting)
567 (dolist (initarg initarg-names)
568 (let ((positions (gathering1 (collecting)
569 (dolist (slot-entry slot-initargs)
570 (when (eq (car slot-entry) initarg)
571 (gather1 (cadr slot-entry)))))))
573 (gather1 (cons initarg positions))))))))
575 ;;; The FALLBACK case allows anything. This always works, and always appears
576 ;;; as the last of the generators for a constructor. It does a full call to
578 (define-constructor-code-type fallback
579 (class name arglist supplied-initarg-names supplied-initargs)
580 (declare (ignore name supplied-initarg-names))
582 (lambda (&rest ignore)
583 (declare (ignore ignore))
585 (sb-kernel:instance-lambda ,arglist
588 ,@(gathering1 (collecting)
589 (iterate ((tail (*list-tails supplied-initargs :by #'cddr)))
590 (gather1 `',(car tail))
591 (gather1 (cadr tail))))))))))
593 ;;; The GENERAL case allows:
594 ;;; constant, unsupplied or non-constant initforms
595 ;;; constant or non-constant default initargs
596 ;;; supplied initargs
597 ;;; slot-filling initargs
598 ;;; :after methods on shared-initialize and initialize-instance
599 (define-constructor-code-type general
600 (class name arglist supplied-initarg-names supplied-initargs)
601 (declare (ignore name))
602 (let ((raw-allocator (raw-instance-allocator class))
603 (slots-fetcher (slots-fetcher class)))
605 (lambda (class .wrapper. defaults init shared)
606 (multiple-value-bind (.constants.
608 .initfns-initargs-and-positions.
609 .supplied-initarg-positions.
612 (general-generator-internal class
616 ',supplied-initarg-names
618 .supplied-initarg-positions.
619 (when (and .constants.
620 (null (non-pcl-or-after-initialize-instance-methods-p
622 (null (non-pcl-or-after-shared-initialize-methods-p
625 (sb-kernel:instance-lambda ,arglist
626 (declare #.*optimize-speed*)
627 (let* ((.instance. (,raw-allocator .wrapper. .constants.))
628 (.slots. (,slots-fetcher .instance.))
629 (.positions. .supplied-initarg-positions.)
630 (.initargs. .constant-initargs.))
633 (dolist (entry .initfns-initargs-and-positions.)
634 (let ((val (funcall (car entry)))
635 (initarg (cadr entry)))
637 (push val .initargs.)
638 (push initarg .initargs.))
639 (dolist (pos (cddr entry))
640 (setf (clos-slots-ref .slots. pos) val))))
642 ,@(gathering1 (collecting)
643 (doplist (initarg value) supplied-initargs
644 (unless (constantp value)
645 (gather1 `(let ((.value. ,value))
646 (push .value. .initargs.)
647 (push ',initarg .initargs.)
648 (dolist (.p. (pop .positions.))
649 (setf (clos-slots-ref .slots. .p.)
652 (dolist (fn .shared-initfns.)
653 (apply fn .instance. t .initargs.))
654 (dolist (fn .initfns.)
655 (apply fn .instance. .initargs.))
659 (defun general-generator-internal
660 (class defaults init shared supplied-initarg-names supplied-initargs)
661 (flet ((bail-out () (return-from general-generator-internal nil)))
662 (let* ((constants (compute-constant-vector class))
663 (layout (wrapper-instance-slots-layout (class-wrapper class)))
665 (compute-initarg-positions class
666 (append supplied-initarg-names
667 (mapcar #'car defaults))))
668 (initfns-initargs-and-positions ())
669 (supplied-initarg-positions ())
670 (constant-initargs ())
673 ;; Go through each of the supplied initargs for three reasons.
675 ;; - If it fills a class slot, bail out.
676 ;; - If its a constant form, fill the constant vector.
677 ;; - Otherwise remember the positions no two initargs
678 ;; will try to fill the same position, since compute
679 ;; initarg positions already took care of that, but
680 ;; we do need to know what initforms will and won't
682 (doplist (initarg val) supplied-initargs
683 (let ((positions (cdr (assq initarg initarg-positions))))
684 (cond ((memq :class positions) (bail-out))
686 (setq val (eval val))
687 (push val constant-initargs)
688 (push initarg constant-initargs)
689 (dolist (pos positions) (setf (svref constants pos) val)))
691 (push positions supplied-initarg-positions)))
692 (setq used-positions (append positions used-positions))))
694 ;; Go through each of the default initargs, for three reasons.
696 ;; - If it fills a class slot, bail out.
697 ;; - If it is a constant, and it does fill a slot, put that
698 ;; into the constant vector.
699 ;; - If it isn't a constant, record its initfn and position.
700 (dolist (default defaults)
701 (let* ((name (car default))
702 (initfn (cadr default))
703 (form (caddr default))
705 (positions (cdr (assq name initarg-positions))))
706 (unless (memq name supplied-initarg-names)
707 (cond ((memq :class positions) (bail-out))
709 (setq value (eval form))
710 (push value constant-initargs)
711 (push name constant-initargs)
712 (dolist (pos positions)
713 (setf (svref constants pos) value)))
715 (push (list* initfn name positions)
716 initfns-initargs-and-positions)))
717 (setq used-positions (append positions used-positions)))))
719 ;; Go through each of the slot initforms:
721 ;; - If its position has already been filled, do nothing.
722 ;; The initfn won't need to be called, and the slot won't
723 ;; need to be touched.
724 ;; - If it is a class slot, and has an initform, bail out.
725 ;; - If its a constant or unsupplied, ignore it, it is
726 ;; already in the constant vector.
727 ;; - Otherwise, record its initfn and position
728 (dolist (slotd (class-slots class))
729 (let* ((alloc (slot-definition-allocation slotd))
730 (name (slot-definition-name slotd))
731 (form (slot-definition-initform slotd))
732 (initfn (slot-definition-initfunction slotd))
733 (position (position name layout)))
734 (cond ((neq alloc :instance)
735 (unless (null initfn)
737 ((member position used-positions))
738 ((or (constantp form)
741 (push (list initfn nil position)
742 initfns-initargs-and-positions)))))
746 (nreverse initfns-initargs-and-positions)
747 (nreverse supplied-initarg-positions)
748 (mapcar #'method-function
749 (remove *standard-shared-initialize-method* shared))
750 (mapcar #'method-function
751 (remove *standard-initialize-instance-method* init))))))
753 ;;; The NO-METHODS case allows:
754 ;;; constant, unsupplied or non-constant initforms
755 ;;; constant or non-constant default initargs
756 ;;; supplied initargs that are arguments to constructor, or constants
757 ;;; slot-filling initargs
758 (define-constructor-code-type no-methods
759 (class name arglist supplied-initarg-names supplied-initargs)
760 (declare (ignore name))
761 (let ((raw-allocator (raw-instance-allocator class))
762 (slots-fetcher (slots-fetcher class)))
764 (lambda (class .wrapper. defaults init shared)
765 (multiple-value-bind (.constants.
766 .initfns-and-positions.
767 .supplied-initarg-positions.)
768 (no-methods-generator-internal class
770 ',supplied-initarg-names
772 .initfns-and-positions.
773 .supplied-initarg-positions.
774 (when (and .constants.
775 (null (non-pcl-initialize-instance-methods-p init))
776 (null (non-pcl-shared-initialize-methods-p shared)))
777 #'(sb-kernel:instance-lambda ,arglist
778 (declare #.*optimize-speed*)
779 (let* ((.instance. (,raw-allocator .wrapper. .constants.))
780 (.slots. (,slots-fetcher .instance.))
781 (.positions. .supplied-initarg-positions.))
784 (dolist (entry .initfns-and-positions.)
785 (let ((val (funcall (car entry))))
786 (dolist (pos (cdr entry))
787 (setf (clos-slots-ref .slots. pos) val))))
789 ,@(gathering1 (collecting)
790 (doplist (initarg value) supplied-initargs
791 (unless (constantp value)
793 `(let ((.value. ,value))
794 (dolist (.p. (pop .positions.))
795 (setf (clos-slots-ref .slots. .p.)
800 (defun no-methods-generator-internal
801 (class defaults supplied-initarg-names supplied-initargs)
802 (flet ((bail-out () (return-from no-methods-generator-internal nil)))
803 (let* ((constants (compute-constant-vector class))
804 (layout (wrapper-instance-slots-layout (class-wrapper class)))
806 (compute-initarg-positions class
807 (append supplied-initarg-names
808 (mapcar #'car defaults))))
809 (initfns-and-positions ())
810 (supplied-initarg-positions ())
813 ;; Go through each of the supplied initargs for three reasons.
815 ;; - If it fills a class slot, bail out.
816 ;; - If its a constant form, fill the constant vector.
817 ;; - Otherwise remember the positions, no two initargs
818 ;; will try to fill the same position, since compute
819 ;; initarg positions already took care of that, but
820 ;; we do need to know what initforms will and won't
822 (doplist (initarg val) supplied-initargs
823 (let ((positions (cdr (assq initarg initarg-positions))))
824 (cond ((memq :class positions) (bail-out))
826 (setq val (eval val))
827 (dolist (pos positions)
828 (setf (svref constants pos) val)))
830 (push positions supplied-initarg-positions)))
831 (setq used-positions (append positions used-positions))))
833 ;; Go through each of the default initargs, for three reasons.
835 ;; - If it fills a class slot, bail out.
836 ;; - If it is a constant, and it does fill a slot, put that
837 ;; into the constant vector.
838 ;; - If it isn't a constant, record its initfn and position.
839 (dolist (default defaults)
840 (let* ((name (car default))
841 (initfn (cadr default))
842 (form (caddr default))
844 (positions (cdr (assq name initarg-positions))))
845 (unless (memq name supplied-initarg-names)
846 (cond ((memq :class positions) (bail-out))
848 (setq value (eval form))
849 (dolist (pos positions)
850 (setf (svref constants pos) value)))
852 (push (cons initfn positions)
853 initfns-and-positions)))
854 (setq used-positions (append positions used-positions)))))
856 ;; Go through each of the slot initforms:
858 ;; - If its position has already been filled, do nothing.
859 ;; The initfn won't need to be called, and the slot won't
860 ;; need to be touched.
861 ;; - If it is a class slot, and has an initform, bail out.
862 ;; - If its a constant or unsupplied, do nothing, we know
863 ;; that it is already in the constant vector.
864 ;; - Otherwise, record its initfn and position
865 (dolist (slotd (class-slots class))
866 (let* ((alloc (slot-definition-allocation slotd))
867 (name (slot-definition-name slotd))
868 (form (slot-definition-initform slotd))
869 (initfn (slot-definition-initfunction slotd))
870 (position (position name layout)))
871 (cond ((neq alloc :instance)
872 (unless (null initfn)
874 ((member position used-positions))
875 ((or (constantp form)
878 (push (list initfn position) initfns-and-positions)))))
881 (nreverse initfns-and-positions)
882 (nreverse supplied-initarg-positions)))))
884 ;;; The SIMPLE-SLOTS case allows:
885 ;;; constant or unsupplied initforms
886 ;;; constant default initargs
887 ;;; supplied initargs
888 ;;; slot filling initargs
889 (define-constructor-code-type simple-slots
890 (class name arglist supplied-initarg-names supplied-initargs)
891 (declare (ignore name))
892 (let ((raw-allocator (raw-instance-allocator class))
893 (slots-fetcher (slots-fetcher class)))
895 (lambda (class .wrapper. defaults init shared)
896 (when (and (null (non-pcl-initialize-instance-methods-p init))
897 (null (non-pcl-shared-initialize-methods-p shared)))
898 (multiple-value-bind (.constants. .supplied-initarg-positions.)
899 (simple-slots-generator-internal class
901 ',supplied-initarg-names
905 (sb-kernel:instance-lambda ,arglist
906 (declare #.*optimize-speed*)
907 (let* ((.instance. (,raw-allocator .wrapper. .constants.))
908 (.slots. (,slots-fetcher .instance.))
909 (.positions. .supplied-initarg-positions.))
912 ,@(gathering1 (collecting)
913 (doplist (initarg value) supplied-initargs
914 (unless (constantp value)
916 `(let ((.value. ,value))
917 (dolist (.p. (pop .positions.))
918 (setf (clos-slots-ref .slots. .p.)
923 (defun simple-slots-generator-internal
924 (class defaults supplied-initarg-names supplied-initargs)
925 (flet ((bail-out () (return-from simple-slots-generator-internal nil)))
926 (let* ((constants (compute-constant-vector class))
927 (layout (wrapper-instance-slots-layout (class-wrapper class)))
929 (compute-initarg-positions class
930 (append supplied-initarg-names
931 (mapcar #'car defaults))))
932 (supplied-initarg-positions ())
935 ;; Go through each of the supplied initargs for three reasons.
937 ;; - If it fills a class slot, bail out.
938 ;; - If its a constant form, fill the constant vector.
939 ;; - Otherwise remember the positions, no two initargs
940 ;; will try to fill the same position, since compute
941 ;; initarg positions already took care of that, but
942 ;; we do need to know what initforms will and won't
944 (doplist (initarg val) supplied-initargs
945 (let ((positions (cdr (assq initarg initarg-positions))))
946 (cond ((memq :class positions) (bail-out))
948 (setq val (eval val))
949 (dolist (pos positions)
950 (setf (svref constants pos) val)))
952 (push positions supplied-initarg-positions)))
953 (setq used-positions (append used-positions positions))))
955 ;; Go through each of the default initargs for three reasons.
957 ;; - If it isn't a constant form, bail out.
958 ;; - If it fills a class slot, bail out.
959 ;; - If it is a constant, and it does fill a slot, put that
960 ;; into the constant vector.
961 (dolist (default defaults)
962 (let* ((name (car default))
963 (form (caddr default))
965 (positions (cdr (assq name initarg-positions))))
966 (unless (memq name supplied-initarg-names)
967 (cond ((memq :class positions) (bail-out))
968 ((not (constantp form))
971 (setq value (eval form))
972 (dolist (pos positions)
973 (setf (svref constants pos) value)))))))
975 ;; Go through each of the slot initforms:
977 ;; - If its position has already been filled, do nothing.
978 ;; The initfn won't need to be called, and the slot won't
979 ;; need to be touched, we are OK.
980 ;; - If it has a non-constant initform, bail-out. This
981 ;; case doesn't handle those.
982 ;; - If it has a constant or unsupplied initform we don't
983 ;; really need to do anything, the value is in the
985 (dolist (slotd (class-slots class))
986 (let* ((alloc (slot-definition-allocation slotd))
987 (name (slot-definition-name slotd))
988 (form (slot-definition-initform slotd))
989 (initfn (slot-definition-initfunction slotd))
990 (position (position name layout)))
991 (cond ((neq alloc :instance)
992 (unless (null initfn)
994 ((member position used-positions))
995 ((or (constantp form)
1000 (values constants (nreverse supplied-initarg-positions)))))