0.pre7.98:
[sbcl.git] / src / pcl / construct.lisp
index 3fc122b..501ff2d 100644 (file)
@@ -1,5 +1,10 @@
-;;;; This file defines the defconstructor and other make-instance optimization
-;;;; mechanisms.
+;;;; This file defines MAKE-INSTANCE optimization mechanisms.
+;;;;
+;;;; KLUDGE: I removed the old DEFCONSTRUCTOR, MAKE-CONSTRUCTOR, and
+;;;; LOAD-CONSTRUCTOR families of definitions in sbcl-0.pre7.99, since
+;;;; it was clear from a few minutes with egrep that they were dead
+;;;; code, but I suspect more dead code remains in this file. (Maybe
+;;;; it's all dead?) -- WHN 2001-12-26
 
 ;;;; This software is part of the SBCL system. See the README file for
 ;;;; more information.
 
 (in-package "SB-PCL")
 \f
-;;; defconstructor is used to define special purpose functions which just
-;;; call make-instance with a symbol as the first argument. The semantics
-;;; of defconstructor is that it is equivalent to defining a function which
-;;; just calls make-instance. The purpose of defconstructor is to provide
-;;; PCL with a way of noticing these calls to make-instance so that it can
-;;; optimize them. Specific ports of PCL could just have their compiler
-;;; spot these calls to make-instance and then call this code. Having the
-;;; special defconstructor facility is the best we can do portably.
-;;;
-;;; A call to defconstructor like:
-;;;
-;;;  (defconstructor make-foo foo (a b &rest r) a a :mumble b baz r)
-;;;
-;;; Is equivalent to a defun like:
-;;;
-;;;  (defun make-foo (a b &rest r)
-;;;    (make-instance 'foo 'a a ':mumble b 'baz r))
-;;;
-;;; Calls like the following are also legal:
-;;;
-;;;  (defconstructor make-foo foo ())
-;;;  (defconstructor make-bar bar () :x *x* :y *y*)
-;;;  (defconstructor make-baz baz (a b c) a-b (list a b) b-c (list b c))
-;;;
-;;; The general idea of this implementation is that the expansion of the
-;;; defconstructor form includes the creation of closure generators which
-;;; can be called to create constructor code for the class. The ways that
-;;; a constructor can be optimized depends not only on the defconstructor
-;;; form, but also on the state of the class and the generic functions in
-;;; the initialization protocol. Because of this, the determination of the
-;;; form of constructor code to be used is a two part process.
-;;;
-;;; At compile time, make-constructor-code-generators looks at the actual
-;;; defconstructor form and makes a list of appropriate constructor code
-;;; generators. All that is really taken into account here is whether
-;;; any initargs are supplied in the call to make-instance, and whether
-;;; any of those are constant.
-;;;
-;;; At constructor code generation time (see note about lazy evaluation)
-;;; compute-constructor-code calls each of the constructor code generators
-;;; to try to get code for this constructor. Each generator looks at the
-;;; state of the class and initialization protocol generic functions and
-;;; decides whether its type of code is appropriate. This depends on things
-;;; like whether there are any applicable methods on initialize-instance,
-;;; whether class slots are affected by initialization etc.
-;;;
-;;; Constructor objects are funcallable instances, the protocol followed to
-;;; to compute the constructor code for them is quite similar to the protocol
-;;; followed to compute the discriminator code for a generic function. When
-;;; the constructor is first loaded, we install as its code a function which
-;;; will compute the actual constructor code the first time it is called.
-;;;
-;;; If there is an update to the class structure which might invalidate the
-;;; optimized constructor, the special lazy constructor installer is put back
-;;; so that it can compute the appropriate constructor when it is called.
-;;; This is the same kind of lazy evaluation update strategy used elswhere
-;;; in PCL.
-;;;
-;;; To allow for flexibility in the PCL implementation and to allow PCL users
-;;; to specialize this constructor facility for their own metaclasses, there
-;;; is an internal protocol followed by the code which loads and installs
-;;; the constructors. This is documented in the comments in the code.
-;;;
-;;; This code is also designed so that one of its levels, can be used to
-;;; implement optimization of calls to make-instance which can't go through
-;;; the defconstructor facility. This has not been implemented yet, but the
-;;; hooks are there.
-
-(defmacro defconstructor
-         (name class lambda-list &rest initialization-arguments)
-  (expand-defconstructor class
-                        name
-                        lambda-list
-                        (copy-list initialization-arguments)))
-
-(defun expand-defconstructor (class-name name lambda-list supplied-initargs)
-  (let ((class (find-class class-name nil))
-       (supplied-initarg-names
-          (loop for name in supplied-initargs by #'cddr
-                collect name)))
-    (when (null class)
-      (error "defconstructor form being compiled (or evaluated) before~@
-             class ~S is defined."
-            class-name))
-    `(progn
-       ;; comments from PCL code back when it was portable:
-       ;;   In order to avoid undefined function warnings, we want to
-       ;;   tell the compile time environment that a function with this
-       ;;   name and this argument list has been defined. The portable
-       ;;   way to do this is with defun:
-       ;;   #-cmu (declaim (notinline ,name))
-       ;;   #-cmu
-       ;;   (defun ,name ,lambda-list
-       ;;     (declare (ignore ,@(extract-parameters lambda-list)))
-       ;;     (error "Constructor ~S not loaded." ',name))
-       ;;   But the derived result type for the above is wrong under CMU CL.
-       ;;   So instead:
-       (declaim (ftype ,(ftype-declaration-from-lambda-list lambda-list name)
-                      ,name))
-       (load-constructor
-        ',class-name
-        ',(class-name (class-of class))
-        ',name
-        ',supplied-initarg-names
-        ;; make-constructor-code-generators is called to return a list
-        ;; of constructor code generators. The actual interpretation
-        ;; of this list is left to compute-constructor-code, but the
-        ;; general idea is that it should be an plist where the keys
-        ;; name a kind of constructor code and the values are generator
-        ;; functions which return the actual constructor code. The
-        ;; constructor code is usually a closures over the arguments
-        ;; to the generator.
-        ,(make-constructor-code-generators class
-                                           name
-                                           lambda-list
-                                           supplied-initarg-names
-                                           supplied-initargs)))))
-
-(defun load-constructor (class-name metaclass-name constructor-name
-                        supplied-initarg-names code-generators)
-  (let ((class (find-class class-name nil)))
-    (cond ((null class)
-          (error "defconstructor form being loaded (or evaluated) before~@
-                  class ~S is defined."
-                 class-name))
-         ((neq (class-name (class-of class)) metaclass-name)
-          (error "When defconstructor ~S was compiled, the metaclass of the~@
-                  class ~S was ~S. The metaclass is now ~S.~@
-                  The constructor must be recompiled."
-                 constructor-name
-                 class-name
-                 metaclass-name
-                 (class-name (class-of class))))
-         (t
-          (load-constructor-internal class
-                                     constructor-name
-                                     supplied-initarg-names
-                                     code-generators)
-          constructor-name))))
-
 ;;; The actual constructor objects.
 (defclass constructor (funcallable-standard-object)
      ((class                                   ;The class with which this
        :initform nil                           ;This is the symbol in whose
        :initarg :name                          ;function cell the constructor
        :reader constructor-name)               ;usually sits. Of course, this
-                                               ;is optional. defconstructor
-                                               ;makes named constructors, but
+                                               ;is optional. The old
+                                               ;DEFCONSTRUCTOR macro made
+                                               ;named constructors, but
                                                ;it is possible to manipulate
                                                ;anonymous constructors also.
 
        :reader constructor-code-generators))   ;could use.
   (:metaclass funcallable-standard-class))
 
-;;; Because the value in the code-type slot should always correspond
-;;; to the FUNCALLABLE-INSTANCE-FUN of the constructor, this function
-;;; should always be used to set them both at the same time.
-(defun set-constructor-code (constructor code type)
-  (set-funcallable-instance-fun constructor code)
-  (set-fun-name constructor (constructor-name constructor))
-  (setf (constructor-code-type constructor) type))
-
 (defmethod describe-object ((constructor constructor) stream)
   (format stream
          "~S is a constructor for the class ~S.~%~
            (doplist (key val) (constructor-code-generators constructor)
               (push key collect))
             (nreverse collect))))
-
-;;; I am not in a hairy enough mood to make this implementation be
-;;; metacircular enough that it can support a defconstructor for
-;;; constructor objects.
-(defun make-constructor (class name supplied-initarg-names code-generators)
-  (make-instance 'constructor
-                :class class
-                :name name
-                :supplied-initarg-names supplied-initarg-names
-                :code-generators code-generators))
-
-; This definition actually appears in std-class.lisp.
-;(defmethod class-constructors ((class std-class))
-;  (with-slots (plist) class (getf plist 'constructors)))
-
-(defmethod add-constructor ((class slot-class)
-                           (constructor constructor))
-  (with-slots (plist) class
-    (pushnew constructor (getf plist 'constructors))))
-
-(defmethod remove-constructor ((class slot-class)
-                              (constructor constructor))
-  (with-slots (plist) class
-    (setf (getf plist 'constructors)
-         (delete constructor (getf plist 'constructors)))))
-
-(defmethod get-constructor ((class slot-class) name &optional (error-p t))
-  (or (dolist (c (class-constructors class))
-       (when (eq (constructor-name c) name) (return c)))
-      (if error-p
-         (error "Couldn't find a constructor with name ~S for class ~S."
-                name class)
-         ())))
-
-;;; This is called to actually load a defconstructor constructor. It
-;;; must install the lazy installer in the function cell of the
-;;; constructor name, and also add this constructor to the list of
-;;; constructors the class has.
-(defmethod load-constructor-internal
-          ((class slot-class) name initargs generators)
-  (let ((constructor (make-constructor class name initargs generators))
-       (old (get-constructor class name nil)))
-    (when old (remove-constructor class old))
-    (install-lazy-constructor-installer constructor)
-    (add-constructor class constructor)
-    (setf (gdefinition name) constructor)))
-
-(defmethod install-lazy-constructor-installer ((constructor constructor))
-  (let ((class (constructor-class constructor)))
-    (set-constructor-code constructor
-                         #'(sb-kernel:instance-lambda (&rest args)
-                             (multiple-value-bind (code type)
-                                 (compute-constructor-code class constructor)
-                               (set-constructor-code constructor code type)
-                               (apply constructor args)))
-                         'lazy)))
-
-;;; the interface to keeping the constructors updated
-;;;
-;;; add-method and remove-method (for standard-generic-function and
-;;; -method), promise to call maybe-update-constructors on the generic
-;;; function and the method.
-;;;
-;;; The class update code promises to call update-constructors
-;;; whenever the class is changed. That is, whenever the supers, slots
-;;; or options change. If user defined classes of constructor needs to
-;;; be updated in more than these circumstances, they should use the
-;;; dependent updating mechanism to make sure update-constructors is
-;;; called.
-;;;
-;;; Bootstrapping concerns force the definitions of
-;;; maybe-update-constructors and update-constructors to be in the
-;;; file std-class. For clarity, they also appear below. Be sure to
-;;; keep the definition here and there in sync.
-;(defvar *initialization-generic-functions*
-;       (list #'make-instance
-;             #'default-initargs
-;             #'allocate-instance
-;             #'initialize-instance
-;             #'shared-initialize))
-;
-;(defmethod maybe-update-constructors
-;         ((generic-function generic-function)
-;          (method method))
-;  (when (memq generic-function *initialization-generic-functions*)
-;    (labels ((recurse (class)
-;             (update-constructors class)
-;             (dolist (subclass (class-direct-subclasses class))
-;               (recurse subclass))))
-;      (when (classp (car (method-specializers method)))
-;      (recurse (car (method-specializers method)))))))
-;
-;(defmethod update-constructors ((class slot-class))
-;  (dolist (cons (class-constructors class))
-;    (install-lazy-constructor-installer cons)))
-;
-;(defmethod update-constructors ((class class))
-;  ())
 \f
-;;; Here is the actual smarts for making the code generators and then trying
-;;; each generator to get constructor code. This extensible mechanism allows
-;;; new kinds of constructor code types to be added. A programmer defining a
-;;; specialization of the constructor class can either use this mechanism to
-;;; define new code types, or can override this mechanism by overriding the
-;;; methods on make-constructor-code-generators and compute-constructor-code.
-;;;
-;;; The function defined by define-constructor-code-type will receive the
-;;; class object, and the 4 original arguments to defconstructor. It can
-;;; return a constructor code generator, or return nil if this type of code
-;;; is determined to not be appropriate after looking at the defconstructor
-;;; arguments.
-;;;
-;;; When compute-constructor-code is called, it first performs basic checks
-;;; to make sure that the basic assumptions common to all the code types are
-;;; valid. (For details see method definition). If any of the tests fail,
-;;; the fallback constructor code type is used. If none of the tests fail,
-;;; the constructor code generators are called in order. They receive 5
-;;; arguments:
-;;;
-;;;   CLASS    the class the constructor is making instances of
-;;;   WRAPPER      that class's wrapper
-;;;   DEFAULTS     the result of calling class-default-initargs on class
-;;;   INITIALIZE   the applicable methods on initialize-instance
-;;;   SHARED       the applicable methosd on shared-initialize
-;;;
-;;; The first code generator to return code is used. The code generators are
-;;; called in reverse order of definition, so define-constructor-code-type
-;;; forms which define better code should appear after ones that define less
-;;; good code. The fallback code type appears first. Note that redefining a
-;;; code type does not change its position in the list. To do that,  define
-;;; a new type at the end with the behavior.
+;;;; Here is the actual smarts for making the code generators and then
+;;;; trying each generator to get constructor code. This extensible
+;;;; mechanism allows new kinds of constructor code types to be added.
+;;;; A programmer defining a specialization of the constructor class
+;;;; can use this mechanism to define new code types.
+;;;;
+;;;; original PCL comment from before dead DEFCONSTRUCTOR was deleted:
+;;;;   The function defined by define-constructor-code-type will receive
+;;;;   the class object, and the 4 original arguments to DEFCONSTRUCTOR.
+;;;;   It can return a constructor code generator, or return NIL if this
+;;;;   type of code is determined to not be appropriate after looking at
+;;;;   the DEFCONSTRUCTOR arguments.
+;;;;
+;;;; original PCL comment from before dead COMPUTE-CONSTRUCTOR-CODE
+;;;; was deleted:
+;;;;    When compute-constructor-code is called, it first performs
+;;;;    basic checks to make sure that the basic assumptions common to
+;;;;    all the code types are valid. (For details see method
+;;;;    definition). If any of the tests fail, the fallback
+;;;;    constructor code type is used. If none of the tests fail, the
+;;;;    constructor code generators are called in order. They receive
+;;;;    5 arguments:
+;;;;
+;;;;   CLASS   the class the constructor is making instances of
+;;;;   WRAPPER      that class's wrapper
+;;;;   DEFAULTS     the result of calling class-default-initargs on class
+;;;;   INITIALIZE   the applicable methods on initialize-instance
+;;;;   SHARED       the applicable methosd on shared-initialize
+;;;;
+;;;; The first code generator to return code is used. The code
+;;;; generators are called in reverse order of definition, so
+;;;; DEFINE-CONSTRUCTOR-CODE-TYPE forms which define better code
+;;;; should appear after ones that define less good code. The fallback
+;;;; code type appears first. Note that redefining a code type does
+;;;; not change its position in the list. To do that, define a new
+;;;; type at the end with the behavior.
 
 (defvar *constructor-code-types* ())
 
        (setf (cadr old-entry) generator)
        (push (list type generator) *constructor-code-types*))
     type))
-
-(defmethod make-constructor-code-generators
-          ((class slot-class)
-           name lambda-list supplied-initarg-names supplied-initargs)
-  (cons 'list
-        (let ((collect nil))
-         (dolist (entry *constructor-code-types*)
-           (let ((generator
-                   (funcall (cadr entry) class name lambda-list
-                                         supplied-initarg-names
-                                         supplied-initargs)))
-             (when generator
-               (push `',(car entry) collect)
-               (push generator collect))))
-          (nreverse collect))))
-
-(defmethod compute-constructor-code ((class slot-class)
-                                    (constructor constructor))
-  (let* ((proto (class-prototype class))
-        (wrapper (class-wrapper class))
-        (defaults (class-default-initargs class))
-        (make
-          (compute-applicable-methods (gdefinition 'make-instance) (list class)))
-        (supplied-initarg-names
-          (constructor-supplied-initarg-names constructor))
-        (default
-          (compute-applicable-methods (gdefinition 'default-initargs)
-                                      (list class supplied-initarg-names))) ;?
-        (allocate
-          (compute-applicable-methods (gdefinition 'allocate-instance)
-                                      (list class)))
-        (initialize
-          (compute-applicable-methods (gdefinition 'initialize-instance)
-                                      (list proto)))
-        (shared
-          (compute-applicable-methods (gdefinition 'shared-initialize)
-                                      (list proto t)))
-        (code-generators
-          (constructor-code-generators constructor)))
-    (flet ((call-code-generator (generator)
-            (when (null generator)
-              (unless (setq generator (getf code-generators 'fallback))
-                (error "No FALLBACK generator?")))
-            (funcall generator class wrapper defaults initialize shared)))
-      (if (or (cdr make)
-             (cdr default)
-             (cdr allocate)
-             (not (check-initargs-1 class
-                                    supplied-initarg-names
-                                    (append initialize shared)
-                                    nil nil)))
-         ;; These are basic shared assumptions, if one of the
-         ;; has been violated, we have to resort to the fallback
-         ;; case. Any of these assumptions could be moved out
-         ;; of here and into the individual code types if there
-         ;; was a need to do so.
-         (values (call-code-generator nil) 'fallback)
-         ;; Otherwise try all the generators until one produces
-         ;; code for us.
-         (doplist (type generator) code-generators
-           (let ((code (call-code-generator generator)))
-             (when code (return (values code type)))))))))
-
-;;; The facilities are useful for debugging, and to measure the performance
-;;; boost from constructors.
-;;;
-;;; FIXME: so they should probably be #+SB-SHOW instead of unconditional
-
-(defun map-constructors (fn)
-  (let ((nclasses 0)
-       (nconstructors 0))
-    (labels ((recurse (class)
-              (incf nclasses)
-              (dolist (constructor (class-constructors class))
-                (incf nconstructors)
-                (funcall fn constructor))
-              (dolist (subclass (class-direct-subclasses class))
-                (recurse subclass))))
-      (recurse (find-class t))
-      (values nclasses nconstructors))))
-
-(defun reset-constructors ()
-  (multiple-value-bind (nclass ncons)
-      (map-constructors #'install-lazy-constructor-installer )
-    (format t "~&~W classes, ~W constructors." nclass ncons)))
-
-(defun disable-constructors ()
-  (multiple-value-bind (nclass ncons)
-      (map-constructors
-       #'(lambda (c)
-           (let ((gen (getf (constructor-code-generators c) 'fallback)))
-             (if (null gen)
-                 (error "No fallback constructor for ~S." c)
-                 (set-constructor-code c
-                                       (funcall gen
-                                                (constructor-class c)
-                                                () () () ())
-                                       'fallback)))))
-    (format t "~&~W classes, ~W constructors." nclass ncons)))
-
-(defun enable-constructors ()
-  (reset-constructors))
 \f
-;;; helper functions and utilities that are shared by all of the code types
-;;; and by the main compute-constructor-code method as well
+;;;; helper functions and utilities that are shared by all of the code
+;;;; types
 
 (defvar *standard-initialize-instance-method*
        (get-method #'initialize-instance
            (push (cons initarg positions) collect))))
       (nreverse collect))))
 \f
-;;; The FALLBACK case allows anything. This always works, and always appears
-;;; as the last of the generators for a constructor. It does a full call to
-;;; make-instance.
+;;; The FALLBACK case allows anything. This always works, and always
+;;; appears as the last of the generators for a constructor. It does a
+;;; full call to make-instance.
 (define-constructor-code-type fallback
        (class name arglist supplied-initarg-names supplied-initargs)
   (declare (ignore name supplied-initarg-names))