tests: Avoid nonsensical classes and methods in deprecation.impure.lisp
[sbcl.git] / src / pcl / ctor.lisp
blob7f2a717830a45af7149669a41625abb719d2057e
1 ;;;; This file contains the optimization machinery for make-instance.
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
6 ;;;; This software is derived from software originally released by
7 ;;;; Gerd Moellmann. Copyright and release statements follow. Later
8 ;;;; modifications to the software are in the public domain and are
9 ;;;; provided with absolutely no warranty. See the COPYING and
10 ;;;; CREDITS files for more information.
12 ;;; Copyright (C) 2002 Gerd Moellmann <gerd.moellmann@t-online.de>
13 ;;; All rights reserved.
14 ;;;
15 ;;; Redistribution and use in source and binary forms, with or without
16 ;;; modification, are permitted provided that the following conditions
17 ;;; are met:
18 ;;;
19 ;;; 1. Redistributions of source code must retain the above copyright
20 ;;; notice, this list of conditions and the following disclaimer.
21 ;;; 2. Redistributions in binary form must reproduce the above copyright
22 ;;; notice, this list of conditions and the following disclaimer in the
23 ;;; documentation and/or other materials provided with the distribution.
24 ;;; 3. The name of the author may not be used to endorse or promote
25 ;;; products derived from this software without specific prior written
26 ;;; permission.
27 ;;;
28 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
29 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
32 ;;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 ;;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
34 ;;; OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35 ;;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
36 ;;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 ;;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 ;;; USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39 ;;; DAMAGE.
41 ;;; ***************
42 ;;; Overview *****
43 ;;; ***************
44 ;;;
45 ;;; Compiler macro for MAKE-INSTANCE, and load-time generation of
46 ;;; optimized instance constructor functions.
47 ;;;
48 ;;; ********************
49 ;;; Entry Points ******
50 ;;; ********************
51 ;;;
52 ;;; UPDATE-CTORS must be called when methods are added/removed,
53 ;;; classes are changed, etc., which affect instance creation.
54 ;;;
55 ;;; PRECOMPILE-CTORS can be called to precompile constructor functions
56 ;;; for classes whose definitions are known at the time the function
57 ;;; is called.
59 (in-package "SB-PCL")
61 ;;; ******************
62 ;;; Utilities *******
63 ;;; ******************
65 (defun quote-plist-keys (plist)
66 (loop for (key . more) on plist by #'cddr
67 if (null more) do
68 (error "Not a property list: ~S" plist)
69 else
70 collect `(quote ,key)
71 and collect (car more)))
73 (defun plist-keys (plist &key test)
74 (loop for (key . more) on plist by #'cddr
75 if (null more) do
76 (error "Not a property list: ~S" plist)
77 else if (or (null test) (funcall test key))
78 collect key))
80 (defun plist-values (plist &key test)
81 (loop for (key . more) on plist by #'cddr
82 if (null more) do
83 (error "Not a property list: ~S" plist)
84 else if (or (null test) (funcall test (car more)))
85 collect (car more)))
87 (defun constant-class-arg-p (form)
88 (and (constantp form)
89 (let ((constant (constant-form-value form)))
90 (or (and (symbolp constant)
91 (not (null (symbol-package constant))))
92 (classp form)))))
94 (defun constant-symbol-p (form)
95 (and (constantp form)
96 (let ((constant (constant-form-value form)))
97 (and (symbolp constant)
98 (not (null (symbol-package constant)))))))
100 ;;; Somewhat akin to DEFAULT-INITARGS, but just collecting the defaulted
101 ;;; initargs for the call.
102 (defun ctor-default-initkeys (supplied-initargs class-default-initargs)
103 (loop for (key) in class-default-initargs
104 when (eq (getf supplied-initargs key '.not-there.) '.not-there.)
105 collect key))
107 ;;; Like DEFAULT-INITARGS, but return a list that can be spliced into source,
108 ;;; instead of a list with values already evaluated.
109 (defun ctor-default-initargs (supplied-initargs class-default-initargs)
110 (loop for (key form fun) in class-default-initargs
111 when (eq (getf supplied-initargs key '.not-there.) '.not-there.)
112 append (list key (if (constantp form) form `(funcall ,fun)))
113 into default-initargs
114 finally
115 (return (append supplied-initargs default-initargs))))
117 ;;; *****************
118 ;;; CTORS *********
119 ;;; *****************
121 ;;; Ctors are funcallable instances whose initial function is a
122 ;;; function computing an optimized constructor function when called.
123 ;;; When the optimized function is computed, the function of the
124 ;;; funcallable instance is set to it.
127 ;;; Type is either CTOR, for MAKE-INSTANCE, or ALLOCATOR, for ALLOCATE-INSTANCE
128 (!defstruct-with-alternate-metaclass ctor
129 :slot-names (type class-or-name class initargs state safe-p)
130 :boa-constructor %make-ctor
131 :superclass-name function
132 :metaclass-name static-classoid
133 :metaclass-constructor make-static-classoid
134 :dd-type funcallable-structure
135 :runtime-type-checks-p nil)
137 ;;; All defined ctors.
138 (defglobal *all-ctors* (make-hash-table :test #'equal
139 :weakness :value))
140 (declaim (hash-table *all-ctors*))
142 (defun make-ctor-parameter-list (ctor)
143 (plist-values (ctor-initargs ctor) :test (complement #'constantp)))
145 ;;; Reset CTOR to use a default function that will compute an
146 ;;; optimized constructor function when called.
147 (defun install-initial-constructor (ctor &key force-p)
148 (when (or force-p (ctor-class ctor))
149 (setf (ctor-class ctor) nil
150 (ctor-state ctor) 'initial)
151 (setf (funcallable-instance-fun ctor)
152 (ecase (ctor-type ctor)
153 (ctor
154 (lambda (&rest args)
155 (install-optimized-constructor ctor)
156 (apply ctor args)))
157 (allocator
158 (lambda ()
159 (install-optimized-allocator ctor)
160 (funcall ctor)))))))
162 (defun make-ctor-function-name (class-name initargs safe-code-p)
163 (labels ((arg-name (x)
164 (typecase x
165 ;; this list of types might look arbitrary but it is
166 ;; exactly the set of types descended into by EQUAL,
167 ;; which is the predicate used by globaldb to test for
168 ;; name equality.
169 (null nil)
170 (list (gensym "LIST-INITARG-"))
171 (string (gensym "STRING-INITARG-"))
172 (bit-vector (gensym "BIT-VECTOR-INITARG-"))
173 (pathname (gensym "PATHNAME-INITARG-"))
174 (t x)))
175 (munge (list)
176 (let ((*gensym-counter* 0))
177 (mapcar #'arg-name list))))
178 (list* 'ctor class-name safe-code-p (munge initargs))))
180 (declaim (ftype (sfunction * function)
181 ensure-ctor ensure-allocator))
183 ;;; Keep this a separate function for testing.
184 (defun ensure-ctor (function-name class-name initargs safe-code-p)
185 (with-world-lock ()
186 (or (gethash function-name *all-ctors*)
187 (make-ctor function-name class-name initargs safe-code-p))))
189 ;;; Keep this a separate function for testing.
190 (defun make-ctor (function-name class-name initargs safe-p)
191 (let ((ctor (%make-ctor 'ctor class-name nil initargs nil safe-p)))
192 (install-initial-constructor ctor :force-p t)
193 (setf (gethash function-name *all-ctors*) ctor)
194 ctor))
196 (defun ensure-allocator (function-name class-name)
197 (with-world-lock ()
198 (or (gethash function-name *all-ctors*)
199 (make-allocator function-name class-name))))
201 (defun make-allocator (function-name class-name)
202 (let ((ctor (%make-ctor 'allocator class-name nil nil nil nil)))
203 (install-initial-constructor ctor :force-p t)
204 (setf (gethash function-name *all-ctors*) ctor)
205 ctor))
207 ;;; *****************
208 ;;; Inline CTOR cache
209 ;;; *****************
211 ;;; The cache starts out as a list of CTORs, sorted with the most recently
212 ;;; used CTORs near the head. If it expands too much, we switch to a vector
213 ;;; with a simple hashing scheme.
215 ;;; Find CTOR for KEY (which is a class or class name) in a list. If the CTOR
216 ;;; is in the list but not one of the 4 first ones, return a new list with the
217 ;;; found CTOR at the head. Thread-safe: the new list shares structure with
218 ;;; the old, but is not desctructively modified. Returning the old list for
219 ;;; hits close to the head reduces ping-ponging with multiple threads seeking
220 ;;; the same list.
221 (defun find-ctor (key list)
222 (labels ((walk (tail from-head depth)
223 (declare (fixnum depth))
224 (if tail
225 (let ((ctor (car tail)))
226 (if (eq (ctor-class-or-name ctor) key)
227 (if (> depth 3)
228 (values ctor
229 (nconc (list ctor) (nreverse from-head) (cdr tail)))
230 (values ctor
231 list))
232 (walk (cdr tail)
233 (cons ctor from-head)
234 (logand #xf (1+ depth)))))
235 (values nil list))))
236 (walk list nil 0)))
238 (declaim (inline sxhash-symbol-or-class))
239 (defun sxhash-symbol-or-class (x)
240 (cond ((symbolp x) (sxhash x))
241 ((std-instance-p x) (sb-impl::std-instance-hash x))
242 ((fsc-instance-p x) (sb-impl::fsc-instance-hash x))
244 (bug "Something strange where symbol or class expected."))))
246 ;;; Max number of CTORs kept in an inline list cache. Once this is
247 ;;; exceeded we switch to a table.
248 (defconstant +ctor-list-max-size+ 12)
249 ;;; Max table size for CTOR cache. If the table fills up at this size
250 ;;; we keep the same size and drop 50% of the old entries.
251 (defconstant +ctor-table-max-size+ (expt 2 8))
252 ;;; Even if there is space in the cache, if we cannot fit a new entry
253 ;;; with max this number of collisions we expand the table (if possible)
254 ;;; and rehash.
255 (defconstant +ctor-table-max-probe-depth+ 5)
257 (defun make-ctor-table (size)
258 (declare (index size))
259 (let ((real-size (power-of-two-ceiling size)))
260 (if (< real-size +ctor-table-max-size+)
261 (values (make-array real-size :initial-element nil) nil)
262 (values (make-array +ctor-table-max-size+ :initial-element nil) t))))
264 (declaim (inline mix-ctor-hash))
265 (defun mix-ctor-hash (hash base)
266 (logand most-positive-fixnum (+ hash base 1)))
268 (defun put-ctor (ctor table)
269 (cond ((try-put-ctor ctor table)
270 (values ctor table))
272 (expand-ctor-table ctor table))))
274 ;;; Thread-safe: if two threads write to the same index in parallel, the other
275 ;;; result is just lost. This is not an issue as the CTORs are used as their
276 ;;; own keys. If both were EQ, we're good. If non-EQ, the next time the other
277 ;;; one is needed we just cache it again -- hopefully not getting stomped on
278 ;;; that time.
279 (defun try-put-ctor (ctor table)
280 (declare (simple-vector table) (optimize speed))
281 (let* ((class (ctor-class-or-name ctor))
282 (base (sxhash-symbol-or-class class))
283 (hash base)
284 (mask (1- (length table))))
285 (declare (fixnum base hash mask))
286 (loop repeat +ctor-table-max-probe-depth+
287 do (let* ((index (logand mask hash))
288 (old (aref table index)))
289 (cond ((and old (neq class (ctor-class-or-name old)))
290 (setf hash (mix-ctor-hash hash base)))
292 (setf (aref table index) ctor)
293 (return-from try-put-ctor t)))))
294 ;; Didn't fit, must expand
295 nil))
297 (defun get-ctor (class table)
298 (declare (simple-vector table) (optimize speed))
299 (let* ((base (sxhash-symbol-or-class class))
300 (hash base)
301 (mask (1- (length table))))
302 (declare (fixnum base hash mask))
303 (loop repeat +ctor-table-max-probe-depth+
304 do (let* ((index (logand mask hash))
305 (old (aref table index)))
306 (if (and old (eq class (ctor-class-or-name old)))
307 (return-from get-ctor old)
308 (setf hash (mix-ctor-hash hash base)))))
309 ;; Nothing.
310 nil))
312 ;;; Thread safe: the old table is read, but if another thread mutates
313 ;;; it while we're reading we still get a sane result -- either the old
314 ;;; or the new entry. The new table is locally allocated, so that's ok
315 ;;; too.
316 (defun expand-ctor-table (ctor old)
317 (declare (simple-vector old))
318 (let* ((old-size (length old))
319 (new-size (* 2 old-size))
320 (drop-random-entries nil))
321 (tagbody
322 :again
323 (multiple-value-bind (new max-size-p) (make-ctor-table new-size)
324 (let ((action (if drop-random-entries
325 ;; Same logic as in method caches -- see comment
326 ;; there.
327 (randomly-punting-lambda (old-ctor)
328 (try-put-ctor old-ctor new))
329 (lambda (old-ctor)
330 (unless (try-put-ctor old-ctor new)
331 (if max-size-p
332 (setf drop-random-entries t)
333 (setf new-size (* 2 new-size)))
334 (go :again))))))
335 (aver (try-put-ctor ctor new))
336 (dotimes (i old-size)
337 (let ((old-ctor (aref old i)))
338 (when old-ctor
339 (funcall action old-ctor))))
340 (return-from expand-ctor-table (values ctor new)))))))
342 (defun ctor-list-to-table (list)
343 (let ((table (make-ctor-table (length list))))
344 (dolist (ctor list)
345 (setf table (nth-value 1 (put-ctor ctor table))))
346 table))
348 (declaim (ftype (function * (values function t &optional))
349 ensure-cached-ctor ensure-cached-allocator))
351 (flet ((get-or-put-ctor (class store thunk)
352 (declare (type function thunk))
353 (if (listp store)
354 (multiple-value-bind (ctor list) (find-ctor class store)
355 (if ctor
356 (values ctor list)
357 (let ((ctor (funcall thunk)))
358 (if (< (length list) +ctor-list-max-size+)
359 (values ctor (cons ctor list))
360 (values ctor (ctor-list-to-table list))))))
361 (let ((ctor (get-ctor class store)))
362 (if ctor
363 (values ctor store)
364 (put-ctor (funcall thunk) store))))))
366 (defun ensure-cached-ctor (class-name store initargs safe-code-p)
367 (get-or-put-ctor
368 class-name store
369 (lambda ()
370 (if (typep class-name '(or symbol class))
371 (let ((name (make-ctor-function-name class-name initargs safe-code-p)))
372 (ensure-ctor name class-name initargs safe-code-p))
373 ;; Invalid first argument: let MAKE-INSTANCE worry about it.
374 (return-from ensure-cached-ctor
375 (values (lambda (&rest ctor-parameters)
376 (collect ((initargs))
377 (doplist (key value) initargs
378 (initargs key)
379 (initargs (if (constantp value)
380 value
381 (pop ctor-parameters))))
382 (apply #'make-instance class-name (initargs))))
383 store))))))
385 (defun ensure-cached-allocator (class store)
386 (get-or-put-ctor
387 class store
388 (lambda ()
389 (if (classp class)
390 (let ((function-name (list 'ctor 'allocator class)))
391 (declare (dynamic-extent function-name))
392 (with-world-lock ()
393 (or (gethash function-name *all-ctors*)
394 (make-allocator (copy-list function-name) class))))
395 ;; Invalid first argument: let ALLOCATE-INSTANCE worry about it.
396 (return-from ensure-cached-allocator
397 (values (lambda ()
398 (declare (notinline allocate-instance))
399 (allocate-instance class))
400 store)))))))
402 ;;; ***********************************************
403 ;;; Compile-Time Expansion of MAKE-INSTANCE *******
404 ;;; ***********************************************
406 (defvar *compiling-optimized-constructor* nil)
408 ;;; There are some MAKE-INSTANCE calls compiled prior to this macro definition.
409 ;;; While it would be trivial to move earlier, I'm not sure that it would
410 ;;; actually work.
412 ;;; This used to be a compiler macro but compiler macros are invoked
413 ;;; before FOP compilation, while source transforms aren't, there's no
414 ;;; reason to optimize make-instance for top-level forms
415 (sb-c:define-source-transform make-instance (&whole form &rest args &environment env)
416 ;; Compiling an optimized constructor for a non-standard class means
417 ;; compiling a lambda with (MAKE-INSTANCE #<SOME-CLASS X> ...) in it
418 ;; -- need to make sure we don't recurse there.
419 (or (unless (or *compiling-optimized-constructor*
420 (not args))
421 (make-instance->constructor-call form (safe-code-p env)))
422 (values nil t)))
424 (sb-c:define-source-transform allocate-instance (class &rest initargs)
425 (if (or *compiling-optimized-constructor*
426 initargs)
427 (values nil t)
428 (allocate-instance->constructor-call class)))
430 ;;; Build an inline cache: a CONS, with the actual cache in the CDR.
431 (defun make-ctor-inline-cache-form
432 (ensure-ctor-name class-arg &optional ensure-ctor-args ctor-args)
433 `(locally (declare (disable-package-locks .cache. .class-arg. .store. .fun.))
434 (binding* ((.cache. (load-time-value (cons 'ctor-cache nil)))
435 (.store. (cdr .cache.))
436 (.class-arg. ,class-arg)
437 ((.fun. .new-store.)
438 (,ensure-ctor-name .class-arg. .store. ,@ensure-ctor-args)))
439 ;; Thread safe: if multiple threads hit this in parallel, the
440 ;; update from the other one is just lost -- no harm done,
441 ;; except for the need to redo the work next time.
442 (unless (eq .store. .new-store.)
443 (setf (cdr .cache.) .new-store.))
444 (funcall .fun. ,@ctor-args))))
446 (defun allocate-instance->constructor-call (class-arg)
447 (flet ((make-allocator-form (class-or-name)
448 (sb-int:check-deprecated-type class-or-name)
449 (let ((function-name (list 'ctor 'allocator class-or-name)))
450 ;; Return code constructing a ctor at load time, which,
451 ;; when called, will set its funcallable instance
452 ;; function to an optimized constructor function.
453 `(funcall (load-time-value
454 (ensure-allocator ',function-name ',class-or-name) t)))))
455 (cond
456 ((classp class-arg)
457 (make-allocator-form class-arg))
458 ((typep class-arg '(cons (eql find-class)
459 (cons (cons (eql quote) (cons symbol null)) null)))
460 (let ((class-name (second (second class-arg))))
461 (make-allocator-form class-name)))
463 (make-ctor-inline-cache-form 'ensure-cached-allocator class-arg)))))
465 (defun make-instance->constructor-call (form safe-code-p)
466 (destructuring-bind (class-arg &rest args) (cdr form)
467 (flet (;; Return the name of parameter number I of a constructor
468 ;; function.
469 (parameter-name (i)
470 (format-symbol *pcl-package* ".P~D." i))
471 ;; Check if CLASS-ARG is a constant symbol. Give up if
472 ;; not.
473 (constant-class-p ()
474 (and class-arg (constant-class-arg-p class-arg)))
475 ;; Check if ARGS are suitable for an optimized constructor.
476 ;; Return NIL from the outer function if not.
477 (check-args ()
478 (loop for (key . more) on args by #'cddr do
479 (when (or (null more)
480 (not (constant-symbol-p key))
481 (eq :allow-other-keys (constant-form-value key)))
482 (return-from make-instance->constructor-call nil))))
483 (maybe-expand-constant (value)
484 (if (symbolp value)
485 (constant-form-value value)
486 value)))
487 (check-args)
488 ;; Collect a plist of initargs and constant values/parameter names
489 ;; in INITARGS. Collect non-constant initialization forms in
490 ;; VALUE-FORMS.
491 (multiple-value-bind (keys initargs value-forms)
492 (loop for (key value) on args by #'cddr and i from 0
493 ;; Initarg key
494 collect (constant-form-value key) into keys
495 collect (constant-form-value key) into initargs
496 ;; Initarg value
497 if (constantp value)
498 collect (maybe-expand-constant value) into keys
499 and collect value into initargs
500 else
501 collect (parameter-name i) into keys
502 and collect (parameter-name i) into initargs
503 and collect value into value-forms
504 finally
505 (return (values keys initargs value-forms)))
506 (cond
507 ((constant-class-p)
508 (let* ((class-or-name (constant-form-value class-arg))
509 (function-name (make-ctor-function-name class-or-name keys
510 safe-code-p)))
511 (sb-int:check-deprecated-type class-or-name)
512 ;; Return code constructing a ctor at load time, which,
513 ;; when called, will set its funcallable instance
514 ;; function to an optimized constructor function.
515 `(funcall (load-time-value
516 (ensure-ctor ',function-name ',class-or-name ',initargs
517 ',safe-code-p)
519 ,@value-forms)))
520 ((and class-arg (not (constantp class-arg)))
521 (make-ctor-inline-cache-form
522 'ensure-cached-ctor class-arg `(',initargs ',safe-code-p) value-forms)))))))
524 ;;; **************************************************
525 ;;; Load-Time Constructor Function Generation *******
526 ;;; **************************************************
528 ;;; The system-supplied primary INITIALIZE-INSTANCE and
529 ;;; SHARED-INITIALIZE methods. One cannot initialize these variables
530 ;;; to the right values here because said functions don't exist yet
531 ;;; when this file is first loaded.
532 (defvar *the-system-ii-method* nil)
533 (defvar *the-system-si-method* nil)
535 (defun install-optimized-constructor (ctor)
536 (with-world-lock ()
537 (let* ((class-or-name (ctor-class-or-name ctor))
538 (class (ensure-class-finalized
539 (if (symbolp class-or-name)
540 (find-class class-or-name)
541 class-or-name))))
542 ;; We can have a class with an invalid layout here. Such a class
543 ;; cannot have a LAYOUT-INVALID of (:FLUSH ...) or (:OBSOLETE
544 ;; ...), because part of the deal is that those only happen from
545 ;; FORCE-CACHE-FLUSHES, which create a new valid wrapper for the
546 ;; class. An invalid layout of T needs to be flushed, however.
547 (when (eq (layout-invalid (class-wrapper class)) t)
548 (%force-cache-flushes class))
549 (setf (ctor-class ctor) class)
550 (pushnew (make-weak-pointer ctor) (plist-value class 'ctors)
551 :test #'eq :key #'weak-pointer-value)
552 (multiple-value-bind (form locations names optimizedp)
553 (constructor-function-form ctor)
554 (setf (funcallable-instance-fun ctor)
555 (apply
556 (let ((*compiling-optimized-constructor* t))
557 (handler-bind ((compiler-note #'muffle-warning))
558 (compile nil `(lambda ,names (declare #.*optimize-speed*)
559 ,form))))
560 locations)
561 (ctor-state ctor) (if optimizedp 'optimized 'fallback))))))
563 (defun install-optimized-allocator (ctor)
564 (with-world-lock ()
565 (let* ((class-or-name (ctor-class-or-name ctor))
566 (class (ensure-class-finalized
567 (if (symbolp class-or-name)
568 (find-class class-or-name)
569 class-or-name))))
570 ;; We can have a class with an invalid layout here. Such a class
571 ;; cannot have a LAYOUT-INVALID of (:FLUSH ...) or (:OBSOLETE
572 ;; ...), because part of the deal is that those only happen from
573 ;; FORCE-CACHE-FLUSHES, which create a new valid wrapper for the
574 ;; class. An invalid layout of T needs to be flushed, however.
575 (when (eq (layout-invalid (class-wrapper class)) t)
576 (%force-cache-flushes class))
577 (setf (ctor-class ctor) class)
578 (pushnew (make-weak-pointer ctor) (plist-value class 'ctors)
579 :test #'eq :key #'weak-pointer-value)
580 (multiple-value-bind (form optimizedp)
581 (allocator-function-form ctor)
582 (setf (funcallable-instance-fun ctor)
583 (let ((*compiling-optimized-constructor* t))
584 (handler-bind ((compiler-note #'muffle-warning))
585 (compile nil form)))
586 (ctor-state ctor) (if optimizedp 'optimized 'fallback))))))
588 (defun allocator-function-form (ctor)
589 (let ((class (ctor-class ctor)))
590 (if (and (not (structure-class-p class))
591 (not (condition-class-p class))
592 (singleton-p (compute-applicable-methods #'allocate-instance
593 (list class)))
594 (every (lambda (x)
595 (member (slot-definition-allocation x)
596 '(:instance :class)))
597 (class-slots class)))
598 (values (optimizing-allocator-generator ctor) t)
599 (values `(lambda ()
600 (declare #.*optimize-speed*
601 (notinline allocate-instance))
602 (allocate-instance ,class))
603 nil))))
605 (defun constructor-function-form (ctor)
606 (let* ((class (ctor-class ctor))
607 (proto (class-prototype class))
608 (make-instance-methods
609 (compute-applicable-methods #'make-instance (list class)))
610 (allocate-instance-methods
611 (compute-applicable-methods #'allocate-instance (list class)))
612 ;; I stared at this in confusion for a while, thinking
613 ;; carefully about the possibility of the class prototype not
614 ;; being of sufficient discrimiating power, given the
615 ;; possibility of EQL-specialized methods on
616 ;; INITIALIZE-INSTANCE or SHARED-INITIALIZE. However, given
617 ;; that this is a constructor optimization, the user doesn't
618 ;; yet have the instance to create a method with such an EQL
619 ;; specializer.
621 ;; There remains the (theoretical) possibility of someone
622 ;; coming along with code of the form
624 ;; (defmethod initialize-instance :before ((o foo) ...)
625 ;; (eval `(defmethod shared-initialize :before ((o foo) ...) ...)))
627 ;; but probably we can afford not to worry about this too
628 ;; much for now. -- CSR, 2004-07-12
629 (ii-methods
630 (compute-applicable-methods #'initialize-instance (list proto)))
631 (si-methods
632 (compute-applicable-methods #'shared-initialize (list proto t)))
633 (setf-svuc-slots
634 (loop for slot in (class-slots class)
635 when (cdr (compute-applicable-methods
636 #'(setf slot-value-using-class)
637 (list nil class proto slot)))
638 collect slot))
639 (sbuc-slots
640 (loop for slot in (class-slots class)
641 when (cdr (compute-applicable-methods
642 #'slot-boundp-using-class
643 (list class proto slot)))
644 collect slot)))
645 ;; Cannot initialize these variables earlier because the generic
646 ;; functions don't exist when PCL is built.
647 (when (null *the-system-si-method*)
648 (setq *the-system-si-method*
649 (find-method #'shared-initialize
650 () (list *the-class-slot-object* *the-class-t*)))
651 (setq *the-system-ii-method*
652 (find-method #'initialize-instance
653 () (list *the-class-slot-object*))))
654 ;; Note that when there are user-defined applicable methods on
655 ;; MAKE-INSTANCE and/or ALLOCATE-INSTANCE, these will show up
656 ;; together with the system-defined ones in what
657 ;; COMPUTE-APPLICABLE-METHODS returns.
658 (let ((maybe-invalid-initargs
659 (check-initargs-1
660 class
661 (append
662 (ctor-default-initkeys
663 (ctor-initargs ctor) (class-default-initargs class))
664 (plist-keys (ctor-initargs ctor)))
665 (append ii-methods si-methods) nil nil))
666 (custom-make-instance
667 (not (null (cdr make-instance-methods)))))
668 (if (and (not (structure-class-p class))
669 (not (condition-class-p class))
670 (not custom-make-instance)
671 (null (cdr allocate-instance-methods))
672 (every (lambda (x)
673 (member (slot-definition-allocation x)
674 '(:instance :class)))
675 (class-slots class))
676 (not maybe-invalid-initargs)
677 (not (hairy-around-or-nonstandard-primary-method-p
678 ii-methods *the-system-ii-method*))
679 (not (around-or-nonstandard-primary-method-p
680 si-methods *the-system-si-method*)))
681 (optimizing-generator ctor ii-methods si-methods setf-svuc-slots sbuc-slots)
682 (fallback-generator ctor ii-methods si-methods
683 (or maybe-invalid-initargs custom-make-instance))))))
685 (defun around-or-nonstandard-primary-method-p
686 (methods &optional standard-method)
687 (loop with primary-checked-p = nil
688 for method in methods
689 as qualifiers = (if (consp method)
690 (early-method-qualifiers method)
691 (safe-method-qualifiers method))
692 when (or (eq :around (car qualifiers))
693 (and (null qualifiers)
694 (not primary-checked-p)
695 (not (null standard-method))
696 (not (eq standard-method method))))
697 return t
698 when (null qualifiers) do
699 (setq primary-checked-p t)))
701 (defun hairy-around-or-nonstandard-primary-method-p
702 (methods &optional standard-method)
703 (loop with primary-checked-p = nil
704 for method in methods
705 as qualifiers = (if (consp method)
706 (early-method-qualifiers method)
707 (safe-method-qualifiers method))
708 when (or (and (eq :around (car qualifiers))
709 (not (simple-next-method-call-p method)))
710 (and (null qualifiers)
711 (not primary-checked-p)
712 (not (null standard-method))
713 (not (eq standard-method method))))
714 return t
715 when (null qualifiers) do
716 (setq primary-checked-p t)))
718 (defun fallback-generator (ctor ii-methods si-methods use-make-instance)
719 (declare (ignore ii-methods si-methods))
720 (let ((class (ctor-class ctor))
721 (lambda-list (make-ctor-parameter-list ctor))
722 (initargs (ctor-initargs ctor)))
723 (if use-make-instance
724 `(lambda ,lambda-list
725 (declare #.*optimize-speed*)
726 ;; The CTOR MAKE-INSTANCE optimization checks for
727 ;; *COMPILING-OPTIMIZED-CONSTRUCTOR* which is bound around
728 ;; compilation of the constructor, hence avoiding the
729 ;; possibility of endless recursion.
730 (make-instance ,class ,@(quote-plist-keys initargs)))
731 (let ((defaults (class-default-initargs class)))
732 (when defaults
733 (setf initargs (ctor-default-initargs initargs defaults)))
734 `(lambda ,lambda-list
735 (declare #.*optimize-speed*)
736 (fast-make-instance ,class ,@(quote-plist-keys initargs)))))))
738 ;;; Not as good as the real optimizing generator, but faster than going
739 ;;; via MAKE-INSTANCE: 1 GF call less, and no need to check initargs.
740 (defun fast-make-instance (class &rest initargs)
741 (declare #.*optimize-speed*)
742 (declare (dynamic-extent initargs))
743 (let ((.instance. (apply #'allocate-instance class initargs)))
744 (apply #'initialize-instance .instance. initargs)
745 .instance.))
747 (defun optimizing-generator
748 (ctor ii-methods si-methods setf-svuc-slots sbuc-slots)
749 (multiple-value-bind (locations names body early-unbound-markers-p)
750 (fake-initialization-emf ctor ii-methods si-methods
751 setf-svuc-slots sbuc-slots)
752 (let ((wrapper (class-wrapper (ctor-class ctor))))
753 (values
754 `(lambda ,(make-ctor-parameter-list ctor)
755 (declare #.*optimize-speed*)
756 (block nil
757 (when (layout-invalid ,wrapper)
758 (install-initial-constructor ,ctor)
759 (return (funcall ,ctor ,@(make-ctor-parameter-list ctor))))
760 ,(wrap-in-allocate-forms ctor body early-unbound-markers-p)))
761 locations
762 names
763 t))))
765 (defun optimizing-allocator-generator
766 (ctor)
767 (let ((wrapper (class-wrapper (ctor-class ctor))))
768 `(lambda ()
769 (declare #.*optimize-speed*)
770 (block nil
771 (when (layout-invalid ,wrapper)
772 (install-initial-constructor ,ctor)
773 (return (funcall ,ctor)))
774 ,(wrap-in-allocate-forms ctor nil t)))))
776 ;;; Return a form wrapped around BODY that allocates an instance constructed
777 ;;; by CTOR. EARLY-UNBOUND-MARKERS-P means slots may be accessed before we
778 ;;; have explicitly initialized them, requiring all slots to start as
779 ;;; +SLOT-UNBOUND+. The resulting form binds the local variables .INSTANCE. to
780 ;;; the instance, and .SLOTS. to the instance's slot vector around BODY.
781 (defun wrap-in-allocate-forms (ctor body early-unbound-markers-p)
782 (let* ((class (ctor-class ctor))
783 (wrapper (class-wrapper class))
784 (allocation-function (raw-instance-allocator class))
785 (slots-fetcher (slots-fetcher class)))
786 (if (eq allocation-function 'allocate-standard-instance)
787 `(let ((.instance. (%make-standard-instance nil #-compact-instance-header 0))
788 (.slots. (make-array
789 ,(layout-length wrapper)
790 ,@(when early-unbound-markers-p
791 '(:initial-element +slot-unbound+)))))
792 (setf (%instance-layout .instance.) ,wrapper)
793 (setf (std-instance-slots .instance.) .slots.)
794 ,body
795 .instance.)
796 `(let* ((.instance. (,allocation-function ,wrapper))
797 (.slots. (,slots-fetcher .instance.)))
798 (declare (ignorable .slots.))
799 ,body
800 .instance.))))
802 ;;; Return a form for invoking METHOD with arguments from ARGS. As
803 ;;; can be seen in METHOD-FUNCTION-FROM-FAST-FUNCTION, method
804 ;;; functions look like (LAMBDA (ARGS NEXT-METHODS) ...). We could
805 ;;; call fast method functions directly here, but benchmarks show that
806 ;;; there's no speed to gain, so lets avoid the hair here.
807 (defmacro invoke-method (method args &optional next-methods)
808 `(funcall ,(the function (method-function method)) ,args ,next-methods))
810 ;;; Return a form that is sort of an effective method comprising all
811 ;;; calls to INITIALIZE-INSTANCE and SHARED-INITIALIZE that would
812 ;;; normally have taken place when calling MAKE-INSTANCE.
813 (defun fake-initialization-emf
814 (ctor ii-methods si-methods setf-svuc-slots sbuc-slots)
815 (multiple-value-bind (ii-around ii-before ii-primary ii-after)
816 (standard-sort-methods ii-methods)
817 (declare (ignore ii-primary))
818 (multiple-value-bind (si-around si-before si-primary si-after)
819 (standard-sort-methods si-methods)
820 (declare (ignore si-primary))
821 (aver (null si-around))
822 (let ((initargs (ctor-initargs ctor))
823 ;; :BEFORE and :AROUND initialization methods, and SETF SVUC and
824 ;; SBUC methods can cause slots to be accessed before the we have
825 ;; touched them here, which requires the instance-vector to be
826 ;; initialized with +SLOT-UNBOUND+ to start with.
827 (early-unbound-markers-p (or ii-before si-before ii-around
828 setf-svuc-slots sbuc-slots)))
829 (multiple-value-bind
830 (locations names bindings vars defaulting-initargs body)
831 (slot-init-forms ctor
832 early-unbound-markers-p
833 setf-svuc-slots sbuc-slots)
834 (values
835 locations
836 names
837 `(let ,bindings
838 (declare (ignorable ,@vars))
839 (flet ((initialize-it (.ii-args. .next-methods.)
840 ;; This has all the :BEFORE and :AFTER methods,
841 ;; and BODY does what primary SI method would do.
842 (declare (ignore .next-methods.))
843 (let* ((.instance. (car .ii-args.))
844 ,@(when (or si-before si-after)
845 `((.si-args.
846 (list* .instance. t (cdr .ii-args.))))))
847 ,@(loop for method in ii-before
848 collect `(invoke-method ,method .ii-args.))
849 ,@(loop for method in si-before
850 collect `(invoke-method ,method .si-args.))
851 ,@body
852 ,@(loop for method in si-after
853 collect `(invoke-method ,method .si-args.))
854 ,@(loop for method in ii-after
855 collect `(invoke-method ,method .ii-args.))
856 .instance.)))
857 (declare (dynamic-extent #'initialize-it))
858 (let ((.ii-args.
859 ,@(if (or ii-before ii-after ii-around si-before si-after)
860 `((list .instance. ,@(quote-plist-keys initargs)
861 ,@defaulting-initargs))
862 `((list .instance.)))))
863 ,(if ii-around
864 ;; If there are :AROUND methods, call them first -- they get
865 ;; the normal chaining, with #'INITIALIZE-IT standing in for
866 ;; the rest.
867 `(let ((.next-methods.
868 (list ,@(cdr ii-around) #'initialize-it)))
869 (declare (dynamic-extent .next-methods.))
870 (invoke-method ,(car ii-around) .ii-args. .next-methods.))
871 ;; The simple case.
872 `(initialize-it .ii-args. nil)))))
873 early-unbound-markers-p))))))
875 ;;; Return four values from APPLICABLE-METHODS: around methods, before
876 ;;; methods, the applicable primary method, and applicable after
877 ;;; methods. Before and after methods are sorted in the order they
878 ;;; must be called.
879 (defun standard-sort-methods (applicable-methods)
880 (loop for method in applicable-methods
881 as qualifiers = (if (consp method)
882 (early-method-qualifiers method)
883 (safe-method-qualifiers method))
884 if (null qualifiers)
885 collect method into primary
886 else if (eq :around (car qualifiers))
887 collect method into around
888 else if (eq :after (car qualifiers))
889 collect method into after
890 else if (eq :before (car qualifiers))
891 collect method into before
892 finally
893 (return (values around before (first primary) (reverse after)))))
895 (defmacro with-type-checked ((type safe-p) &body body)
896 (if safe-p
897 ;; To handle FUNCTION types reasonable, we use SAFETY 3 and
898 ;; THE instead of e.g. CHECK-TYPE.
899 `(locally
900 (declare (optimize (safety 3)))
901 (the ,type (progn ,@body)))
902 `(progn ,@body)))
904 ;;; Return as multiple values bindings for default initialization arguments,
905 ;;; variable names, defaulting initargs and a body for initializing instance
906 ;;; and class slots of an object costructed by CTOR. The variable .SLOTS. is
907 ;;; assumed to bound to the instance's slot vector. EARLY-UNBOUND-MARKERS-P
908 ;;; means other code will initialize instance slots to +SLOT-UNBOUND+, and we
909 ;;; have to check if something has already set slots before we initialize
910 ;;; them.
911 (defun slot-init-forms (ctor early-unbound-markers-p setf-svuc-slots sbuc-slots)
912 (let* ((class (ctor-class ctor))
913 (initargs (ctor-initargs ctor))
914 (initkeys (plist-keys initargs))
915 (safe-p (ctor-safe-p ctor))
916 (wrapper (class-wrapper class))
917 (slot-vector
918 (make-array (layout-length wrapper) :initial-element nil))
919 (class-inits ())
920 (default-inits ())
921 (defaulting-initargs ())
922 (default-initargs (class-default-initargs class))
923 (initarg-locations
924 (compute-initarg-locations
925 class (append initkeys (mapcar #'car default-initargs)))))
926 (labels ((initarg-locations (initarg)
927 (cdr (assoc initarg initarg-locations :test #'eq)))
928 (initializedp (location)
929 (cond
930 ((consp location)
931 (assoc location class-inits :test #'eq))
932 ((integerp location)
933 (not (null (aref slot-vector location))))
934 (t (bug "Weird location in ~S" 'slot-init-forms))))
935 (class-init (location kind val type slotd)
936 (aver (consp location))
937 (unless (initializedp location)
938 (push (list location kind val type slotd) class-inits)))
939 (instance-init (location kind val type slotd)
940 (aver (integerp location))
941 (unless (initializedp location)
942 (setf (aref slot-vector location)
943 (list kind val type slotd))))
944 (default-init-var-name (i)
945 (format-symbol *pcl-package* ".D~D." i))
946 (location-var-name (i)
947 (format-symbol *pcl-package* ".L~D." i)))
948 ;; Loop over supplied initargs and values and record which
949 ;; instance and class slots they initialize.
950 (loop for (key value) on initargs by #'cddr
951 as kind = (if (constantp value) 'constant 'param)
952 as locations = (initarg-locations key)
953 do (loop for (location type slotd) in locations
954 do (if (consp location)
955 (class-init location kind value type slotd)
956 (instance-init location kind value type slotd))))
957 ;; Loop over default initargs of the class, recording
958 ;; initializations of slots that have not been initialized
959 ;; above. Default initargs which are not in the supplied
960 ;; initargs are treated as if they were appended to supplied
961 ;; initargs, that is, their values must be evaluated even
962 ;; if not actually used for initializing a slot.
963 (loop for (key initform initfn) in default-initargs and i from 0
964 unless (member key initkeys :test #'eq)
965 do (let* ((kind (if (constantp initform) 'constant 'var))
966 (init (if (eq kind 'var) initfn initform)))
967 (ecase kind
968 (constant
969 (push (list 'quote key) defaulting-initargs)
970 (push initform defaulting-initargs))
971 (var
972 (push (list 'quote key) defaulting-initargs)
973 (push (default-init-var-name i) defaulting-initargs)))
974 (when (eq kind 'var)
975 (let ((init-var (default-init-var-name i)))
976 (setq init init-var)
977 (push (cons init-var initfn) default-inits)))
978 (loop for (location type slotd) in (initarg-locations key)
979 do (if (consp location)
980 (class-init location kind init type slotd)
981 (instance-init location kind init type slotd)))))
982 ;; Loop over all slots of the class, filling in the rest from
983 ;; slot initforms.
984 (loop for slotd in (class-slots class)
985 as location = (slot-definition-location slotd)
986 as type = (slot-definition-type slotd)
987 as allocation = (slot-definition-allocation slotd)
988 as initfn = (slot-definition-initfunction slotd)
989 as initform = (slot-definition-initform slotd) do
990 (unless (or (eq allocation :class)
991 (null initfn)
992 (initializedp location))
993 (if (constantp initform)
994 (instance-init location 'initform initform type slotd)
995 (instance-init location
996 'initform/initfn initfn type slotd))))
997 ;; Generate the forms for initializing instance and class slots.
998 (let ((instance-init-forms
999 (loop for slot-entry across slot-vector and i from 0
1000 as (kind value type slotd) = slot-entry
1001 collect
1002 (flet ((setf-form (value-form)
1003 (if (member slotd setf-svuc-slots :test #'eq)
1004 `(setf (slot-value-using-class
1005 ,class .instance. ,slotd)
1006 ,value-form)
1007 `(setf (clos-slots-ref .slots. ,i)
1008 (with-type-checked (,type ,safe-p)
1009 ,value-form))))
1010 (not-boundp-form ()
1011 (if (member slotd sbuc-slots :test #'eq)
1012 `(not (slot-boundp-using-class
1013 ,class .instance. ,slotd))
1014 `(eq (clos-slots-ref .slots. ,i)
1015 +slot-unbound+))))
1016 (ecase kind
1017 ((nil)
1018 (unless early-unbound-markers-p
1019 `(setf (clos-slots-ref .slots. ,i)
1020 +slot-unbound+)))
1021 ((param var)
1022 (setf-form value))
1023 (initfn
1024 (setf-form `(funcall ,value)))
1025 (initform/initfn
1026 (if early-unbound-markers-p
1027 `(when ,(not-boundp-form)
1028 ,(setf-form `(funcall ,value)))
1029 (setf-form `(funcall ,value))))
1030 (initform
1031 (if early-unbound-markers-p
1032 `(when ,(not-boundp-form)
1033 ,(setf-form `',(constant-form-value value)))
1034 (setf-form `',(constant-form-value value))))
1035 (constant
1036 (setf-form `',(constant-form-value value))))))))
1037 ;; we are not allowed to modify QUOTEd locations, so we can't
1038 ;; generate code like (setf (cdr ',location) arg). Instead,
1039 ;; we have to do (setf (cdr .L0.) arg) and arrange for .L0. to
1040 ;; be bound to the location.
1041 (multiple-value-bind (names locations class-init-forms)
1042 (loop with names
1043 with locations
1044 with i = -1
1045 for (location kind value type slotd) in class-inits
1046 for init-form
1047 = (case kind
1048 (constant `',(constant-form-value value))
1049 ((param var) `,value)
1050 (initfn `(funcall ,value)))
1051 when (member slotd setf-svuc-slots :test #'eq)
1052 collect `(setf (slot-value-using-class
1053 ,class .instance. ,slotd)
1054 ,init-form)
1055 into class-init-forms
1056 else collect
1057 (let ((name (location-var-name (incf i))))
1058 (push name names)
1059 (push location locations)
1060 `(setf (cdr ,name)
1061 (with-type-checked (,type ,safe-p)
1062 ,init-form)))
1063 into class-init-forms
1064 finally (return (values (nreverse names)
1065 (nreverse locations)
1066 class-init-forms)))
1067 (multiple-value-bind (vars bindings)
1068 (loop for (var . initfn) in (nreverse default-inits)
1069 collect var into vars
1070 collect `(,var (funcall ,initfn)) into bindings
1071 finally (return (values vars bindings)))
1072 (values locations names
1073 bindings vars
1074 (nreverse defaulting-initargs)
1075 `(,@(delete nil instance-init-forms)
1076 ,@class-init-forms))))))))
1078 ;;; Return an alist of lists (KEY (LOCATION . TYPE-SPECIFIER) ...)
1079 ;;; telling, for each key in INITKEYS, which locations the initarg
1080 ;;; initializes and the associated type with the location. CLASS is
1081 ;;; the class of the instance being initialized.
1082 (defun compute-initarg-locations (class initkeys)
1083 (loop with slots = (class-slots class)
1084 for key in initkeys collect
1085 (loop for slot in slots
1086 if (memq key (slot-definition-initargs slot))
1087 collect (list (slot-definition-location slot)
1088 (slot-definition-type slot)
1089 slot)
1090 into locations
1091 else
1092 collect slot into remaining-slots
1093 finally
1094 (setq slots remaining-slots)
1095 (return (cons key locations)))))
1098 ;;; *******************************
1099 ;;; External Entry Points ********
1100 ;;; *******************************
1102 (defun update-ctors (reason &key class name generic-function method)
1103 (labels ((reset (class &optional initarg-caches-p (ctorsp t))
1104 (when ctorsp
1105 (setf (plist-value class 'ctors)
1106 (delete-if
1107 (lambda (weak)
1108 (let ((ctor (weak-pointer-value weak)))
1109 (cond (ctor
1110 (install-initial-constructor ctor)
1111 nil)
1112 (t))))
1113 (plist-value class 'ctors))))
1114 (when initarg-caches-p
1115 (dolist (cache '(mi-initargs ri-initargs))
1116 (setf (plist-value class cache) ())))
1117 (dolist (subclass (class-direct-subclasses class))
1118 (reset subclass initarg-caches-p ctorsp))))
1119 (ecase reason
1120 ;; CLASS must have been specified.
1121 (finalize-inheritance
1122 (reset class t))
1123 ;; NAME must have been specified.
1124 (setf-find-class
1125 (loop for ctor being the hash-values of *all-ctors*
1126 when (eq (ctor-class-or-name ctor) name)
1128 (when (ctor-class ctor)
1129 (reset (ctor-class ctor)))
1130 (loop-finish)))
1131 ;; GENERIC-FUNCTION and METHOD must have been specified.
1132 ((add-method remove-method)
1133 (flet ((class-of-1st-method-param (method)
1134 (type-class (first (method-specializers method)))))
1135 (case (generic-function-name generic-function)
1136 ((make-instance allocate-instance)
1137 ;; FIXME: I can't see a way of working out which classes a
1138 ;; given metaclass specializer are applicable to short of
1139 ;; iterating and testing with class-of. It would be good
1140 ;; to not invalidate caches of system classes at this
1141 ;; point (where it is not legal to define a method
1142 ;; applicable to them on system functions). -- CSR,
1143 ;; 2010-07-13
1144 (reset (find-class 'standard-object) t t))
1145 ((initialize-instance shared-initialize)
1146 (reset (class-of-1st-method-param method) t t))
1147 ((reinitialize-instance)
1148 (reset (class-of-1st-method-param method) t nil))
1149 (t (when (or (eq (generic-function-name generic-function)
1150 'slot-boundp-using-class)
1151 (equal (generic-function-name generic-function)
1152 '(setf slot-value-using-class)))
1153 ;; this looks awfully expensive, but given that one
1154 ;; can specialize on the SLOTD argument, nothing is
1155 ;; safe. -- CSR, 2004-07-12
1156 (reset (find-class 'standard-object))))))))))
1158 (defun precompile-ctors ()
1159 (loop for ctor being the hash-values of *all-ctors*
1160 unless (ctor-class ctor)
1162 (let ((class (find-class (ctor-class-or-name ctor) nil)))
1163 (when (and class (class-finalized-p class))
1164 (install-optimized-constructor ctor)))))
1166 (defun maybe-call-ctor (class initargs)
1167 (flet ((frob-initargs (ctor)
1168 (do ((ctail (ctor-initargs ctor))
1169 (itail initargs)
1170 (args nil))
1171 ((or (null ctail) (null itail))
1172 (values (nreverse args) (and (null ctail) (null itail))))
1173 (unless (eq (pop ctail) (pop itail))
1174 (return nil))
1175 (let ((cval (pop ctail))
1176 (ival (pop itail)))
1177 (if (constantp cval)
1178 (unless (eql cval ival)
1179 (return nil))
1180 (push ival args))))))
1181 (dolist (weak (plist-value class 'ctors))
1182 (let ((ctor (weak-pointer-value weak)))
1183 (when (and ctor
1184 (eq (ctor-type ctor) 'ctor)
1185 (eq (ctor-state ctor) 'optimized))
1186 (multiple-value-bind (ctor-args matchp)
1187 (frob-initargs ctor)
1188 (when matchp
1189 (return (apply ctor ctor-args)))))))))
1191 ;;; FIXME: CHECK-FOO-INITARGS share most of their bodies.
1192 (defun check-mi-initargs (class initargs)
1193 (let* ((class-proto (class-prototype class))
1194 (keys (plist-keys initargs))
1195 (cache (plist-value class 'mi-initargs))
1196 (cached (assoc keys cache :test #'equal))
1197 (invalid-keys
1198 (if (consp cached)
1199 (cdr cached)
1200 (let ((invalid
1201 (check-initargs-1
1202 class initargs
1203 (list (list* 'allocate-instance class initargs)
1204 (list* 'initialize-instance class-proto initargs)
1205 (list* 'shared-initialize class-proto t initargs))
1206 t nil)))
1207 (setf (plist-value class 'mi-initargs)
1208 (acons keys invalid cache))
1209 invalid))))
1210 (when invalid-keys
1211 ;; FIXME: should have an operation here, and maybe a set of
1212 ;; valid keys.
1213 (initarg-error class invalid-keys))))
1215 (defun check-ri-initargs (instance initargs)
1216 (let* ((class (class-of instance))
1217 (keys (plist-keys initargs))
1218 (cache (plist-value class 'ri-initargs))
1219 (cached (assoc keys cache :test #'equal))
1220 (invalid-keys
1221 (if (consp cached)
1222 (cdr cached)
1223 (let ((invalid
1224 ;; FIXME: give CHECK-INITARGS-1 and friends a
1225 ;; more mnemonic name and (possibly) a nicer,
1226 ;; more orthogonal interface.
1227 (check-initargs-1
1228 class initargs
1229 (list (list* 'reinitialize-instance instance initargs)
1230 (list* 'shared-initialize instance nil initargs))
1231 t nil)))
1232 (setf (plist-value class 'ri-initargs)
1233 (acons keys invalid cache))
1234 invalid))))
1235 (when invalid-keys
1236 (initarg-error class invalid-keys))))
1238 ;;; end of ctor.lisp