;;;-*-Mode:LISP; Package:(PCL (LISP WALKER) 1000); Base:10; Syntax:Common-lisp -*-
;;;
;;; *************************************************************************
;;; Copyright (c) 1985, 1986, 1987 Xerox Corporation.  All rights reserved.
;;;
;;; Use and copying of this software and preparation of derivative works
;;; based upon this software are permitted.  Any distribution of this
;;; software or derivative works must comply with all applicable United
;;; States export control laws.
;;; 
;;; This software is made available AS IS, and Xerox Corporation makes no
;;; warranty about the software, its performance or its conformity to any
;;; specification.
;;; 
;;; Any person obtaining a copy of this software is requested to send their
;;; name and post office or electronic mail address to:
;;;   CommonLoops Coordinator
;;;   Xerox Artifical Intelligence Systems
;;;   2400 Hanover St.
;;;   Palo Alto, CA 94303
;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
;;;
;;; Suggestions, comments and requests for improvements are also welcome.
;;; *************************************************************************
;;;
;;; This file contains portable versions of low-level functions and macros
;;; which are ripe for implementation specific customization.  None of the
;;; code in this file *has* to be customized for a particular Common Lisp
;;; implementation. Moreover, in some implementations it may not make any
;;; sense to customize some of this code.
;;;
;;; But, experience suggests that MOST Common Lisp implementors will want
;;; to customize some of the code in this file to make PCL run better in
;;; their implementation.  The code in this file has been separated and
;;; heavily commented to make that easier.
;;;
;;; Implementation-specific version of this file already exist for:
;;; 
;;;    Symbolics 3600 family       3600-low.lisp
;;;    Lucid Lisp                  lucid-low.lisp
;;;    Xerox 1100 family           xerox-low.lisp
;;;    ExCL (Franz)                excl-low.lisp
;;;    Kyoto Common Lisp           kcl-low.lisp
;;;    Vaxlisp                     vaxl-low.lisp
;;;    CMU Lisp                    cmu-low.lisp
;;;    H.P. Common Lisp            hp-low.lisp
;;;    Golden Common Lisp          gold-low.lisp
;;;    Ti Explorer                 ti-low.lisp
;;;    
;;;
;;; These implementation-specific files are loaded after this file.  Because
;;; none of the macros defined by this file are used in functions defined by
;;; this file the implementation-specific files can just contain the parts of
;;; this file they want to change.  They don't have to copy this whole file
;;; and then change the parts they want.
;;;
;;; If you make changes or improvements to these files, or if you need some
;;; low-level part of PCL re-modularized to make it more portable to your
;;; system please send mail to CommonLoops.pa@Xerox.com.
;;;
;;; Thanks.
;;; 

(in-package 'pcl)

  ;;   
;;;;;; without-interrupts
  ;;   
;;; OK, Common Lisp doesn't have this and for good reason.  But For all of
;;; the Common Lisp's that PCL runs on today, there is a meaningful way to
;;; implement this.  WHAT I MEAN IS:
;;;
;;; I want the body to be evaluated in such a way that no other code that is
;;; running PCL can be run during that evaluation.  I agree that the body
;;; won't take *long* to evaluate.  That is to say that I will only use
;;; without interrupts around small computations.
;;;
;;; OK?
;;;
(defmacro without-interrupts (&body body)
  `(progn ,.body))

  ;;   
;;;;;; Load Time Eval
  ;;
;;;
;;; #, is woefully inadequate.  You can't use it inside of a macro and have
;;; the expansion of part of the macro be evaluated at load-time.
;;;
;;; load-time-eval is used to provide an interface to implementation
;;; dependent implementation of load time evaluation.
;;;
;;; A compiled call to load-time-eval:
;;;   should evaluated the form at load time,
;;;   but if it is being compiled-to-core evaluate it at compile time
;;; Interpreted calls to load-time-eval:
;;;   should just evaluate form at run-time.
;;; 
;;; The portable implementation just evaluates it every time, and PCL knows
;;; this.  PCL is careful to only use load-time-eval in places where (except
;;; for performance penalty) it is OK to evaluate the form every time.
;;; 
(defmacro load-time-eval (form)
  `(progn ,form))

  ;;   
;;;;;; Memory Blocks (array-like blocks of memory)
  ;;
;;; The portable implementation of memory-blocks is as arrays.
;;;
;;; The area argument to make-memory-block is based on the area feature of
;;; LispM's.  As it is used in PCL that argument will always be an unquoted
;;; symbol.  So a call to make-memory-block will look like:
;;;     (make-memory-block 100 class-wrapper-area)
;;; This allows any particular implementation of make-memory-block to look at
;;; the symbol at compile time (macroexpand time) and know where the memory-
;;; block should be consed.  Currently the only values ever used as the area
;;; argument are:
;;; 
;;;    CLASS-WRAPPER-AREA        used when making a class-wrapper
;;;
;;; NOTE:
;;;     It is perfectly legitimate for an implementation of make-memory-block
;;;     to ignore the area argument.  It only exists to try to improve paging
;;;     performance in systems which do allow control over where memory is
;;;     allocated.
;;; 
(defmacro make-memory-block (size &optional area)
  (declare (ignore area))
  `(make-array ,size :initial-element nil))

(defmacro memory-block-size (block)
  `(array-dimension ,block 0))

(defmacro memory-block-ref (block offset)
  `(locally
     (declare (optimize (speed 3) (safety 0))
	      (inline svref))
     (svref (the simple-vector ,block) (the fixnum ,offset))))

(defsetf memory-block-ref (block offset) (new-value)
  `(locally
     (declare (optimize (speed 3) (safety 0)))
     (setf (svref (the simple-vector ,block) (the fixnum ,offset))
	   ,new-value)))

(eval-when (compile load eval)

(defun make-memory-block-mask (size &optional (words-per-entry 2))
  (let ((offset-mask 1) 
	(entry-mask 1))
	
    (loop (when (>= offset-mask size) (return))
	  (setq offset-mask (* offset-mask 2)))

    (loop (when (>= entry-mask words-per-entry) (return))
	  (setq entry-mask (* entry-mask 2)))

    (logxor (1- offset-mask)
	    (1- entry-mask))))
)

;;;
;;; clear-memory-block sets all the slots of a memory block to nil starting
;;; at start.  This really shouldn't be a macro, it should be a function.
;;; It has to be a macro because otherwise its call to memory-block-ref will
;;; get compiled before people get a chance to change memory-block-ref.
;;; This argues one of:
;;;  - this should be a function in another file.  No, it belongs here.
;;;  - Common Lisp should have defsubst.  Probably
;;;  - Implementors should take (proclaim '(inline xxx)) more seriously.
;;;  
(defmacro clear-memory-block (block start &optional times)
  (once-only (block)
    `(do ((end ,(if times `(+ ,start ,times) `(length ,block)))
	  (index ,start (+ index 1)))
	 ((= index end))
       (setf (memory-block-ref ,block index) nil))))

  ;;   
;;;;;; CLASS-OF
  ;;
;;;
;;; *class-of* is the lisp code for the definition of class-of.
;;;
;;; This version uses type-of to determine the class of an object.  Because
;;; of the underspecification of type-of, this does not always produce the
;;; "most specific class of which x is an instance".  But it is the best I
;;; can do portably.
;;;
;;; Specific ports of PCL should feel free to redefine *class-of* to provide
;;; a more accurate definition.  At some point in any definition of class-of
;;; there should be a test to determine if the argument is a %instance, and
;;; if so the %instance-class-of macro should be used to determine the class
;;; of the instance.
;;;
;;; Whenever a new meta-class is defined, the portable code will take care of
;;; modifying the definition of %instance-class-of and recompiling class-of.
;;;
(defvar *class-of*
  '(lambda (x) 
     (or (and (iwmc-class-p x)
	      (class-wrapper-class (iwmc-class-class-wrapper x)))
	 (and (funcallable-instance-p x)
	      (funcallable-instance-class x))
	 (and (%instancep x)
	      (%instance-class-of x))
	 (built-in-class-of x)
	 (error "Can't determine class of ~S" x))))

(defmacro class-of-1 (x)
  (once-only (x)
    `(or (and (iwmc-class-p ,x)
	      (class-wrapper-class (iwmc-class-class-wrapper ,x)))
	 (and (funcallable-instance-p ,x)
	      (funcallable-instance-class ,x))
	 (class-of ,x))))

(defvar *meta-classes* ())

(defmacro %instance-class-of (arg)
  `(cond ,@(iterate ((mc in *meta-classes*))
	     (collect
	       `((eq (%instance-meta-class ,arg)
		     (load-time-eval (class-named ',(car mc))))
		 (funcall (function ,(cdr mc)) ,arg))))
	 (t
	  (error
	    "Internal error in %INSTANCE-CLASS-OF.  The argument to~%~
             %instance-class-of is a %instance, but its meta-class is~%~
             not one of the meta-classes defined with define-meta-class."
	    (%instance-meta-class ,arg)))))

(defmacro define-meta-class (name class-of-function &rest options)
  (declare (ignore options))
  (check-type name symbol "a symbol which is the name of a meta-class")
  (check-type class-of-function function "a function")
  `(progn (define-meta-class-1 ',name ',class-of-function)
	  (precompile-class-of ,name ,class-of-function)))

(defun define-meta-class-1 (name class-of-function)
  (or (eq name 'standard-class)
      (class-named name t)
      (error "In define-meta-class, there is no class named ~S.~%~
              The class ~S must be defined before evaluating this~%~
              define-meta-class form."))
  (let ((existing (assq name *meta-classes*)))
    (if existing
	(setf (cdr existing) class-of-function)
	(setq *meta-classes* (nconc *meta-classes*
				    (list (cons name class-of-function)))))))

(defvar *precompiled-meta-classes* ())

(defmacro precompile-class-of (&optional name class-of-function)
  (let ((*meta-classes* *meta-classes*))
    (when name (define-meta-class-1 name class-of-function))
    `(progn (setq *precompiled-meta-classes* ',*meta-classes*)
	    (defun class-of (x) (,*class-of* x))
	    (recompile-class-of))))

(defun recompile-class-of (&optional forcep)
  ;; Check to see if the pre-compiled definition of class-of matches
  ;; the current value of *meta-classes*.  If it does, do nothing.
  ;; If it doesn't or forcep is not nill, recompile class of from
  ;; scratch.
  (when (or (not (null forcep))
	    (not (equal *precompiled-meta-classes* *meta-classes*))
	    (not (fboundp 'class-of))
	    (not (compiled-function-p (symbol-function 'class-of))))
    (setf (symbol-function 'class-of)
	  #'(lambda (x)
	      (declare (notinline class-of))
	      ;; Now recompile class-of so that the new definition
	      ;; of %instance-class-of will take effect.
	      (compile 'class-of *class-of*)
	      (class-of x)))))

  ;;
;;;;;; TYPEP and TYPE-OF support.
  ;;
;;; Portable CommonLoops makes no changes to typep or type-of.  In order for
;;; those functions to work with CommonLoops objects each implementation will
;;; have to fix its typep and type-of.  It shouldn't be hard though, and
;;; these macros should help.

;(defmacro %instance-typep (x type)
;  `(not (null (memq (class-named ,type ())
;                    (class-class-precedence-list (class-of ,x))))))
;
;(defmacro %instance-type-of (x)
;  `(class-name (class-of ,x)))

  ;;   
;;;;;; The primitive instances.
  ;;
;;;
;;; This is used by define-meta-class and friends to provide the meta-instance
;;; structure used for user-defined meta-classes.
;;;
;;; Conceptually, a %instance is an array-like datatype whose first element
;;; points to the meta-class of the %instance and whose remaining elements
;;; are used by the meta-class for whatever purpose it wants.
;;;
;;; What would like to do is use defstruct to define a new type with a
;;; variable number of slots.  Unfortunately, Common Lisp itself does not
;;; let us do that.  So we have to define a new type %instance, and have
;;; it point to an array which is the extra slots.
;;;
;;; Most any port of PCL should re-implement this datatype.  Implementing it
;;; as a variable length type so that %instance are only one vector in memory
;;; (the "extra slots" are in-line with the meta-class) will have significant
;;; impact on the speed of many CommonLoops programs.  As an example of how
;;; to do this re-implementation of %instance, please see the file 3600-low.
;;; 

(defstruct (%instance (:print-function print-instance)
		      (:constructor %allocate-instance-1 (meta-class storage))
		      (:predicate %instancep))
  meta-class
  storage)

(defmacro %allocate-instance (meta-class size)
  `(%allocate-instance-1 ,meta-class (make-array ,size)))

(defmacro %instance-ref (instance index)
  `(aref (%instance-storage ,instance) ,index))

  ;;
;;;;;;  Very Low-Level representation of instances with meta-class class.
  ;;
;;; As shown below, an instance with meta-class class (iwmc-class) is a three
;;; *slot* structure.
;;;   
;;; 
;;;                                             /------["Class"]
;;;                  /-------["Class Wrapper"  /  <slot-and-method-cache>]
;;;                 /
;;;  Instance--> [ / , \  ,  \ ]
;;;                     \     \
;;;                      \     \---[Instance Slot Storage Block]
;;;                       \
;;;                        \-------[Dynamic Slot plist]
;;;
;;; Instances with meta-class class point to their class indirectly through
;;; the class's class wrapper (each class has one class wrapper, not each
;;; instance).  This is done so that all the extant instances of a class can
;;; have the class they point to changed quickly.  See change-class.
;;;
;;; Static-slots are a 1-d-array-like structure.
;;; The default PCL implementation is as a memory block as described above.
;;; Particular ports are free to change this to a lower-level block of memory
;;; type structure. Once again, the accessor for static-slots storage doesn't
;;; need to do bounds checking, and static-slots structures don't need to be
;;; able to change size.  This is because new slots are added using the
;;; dynamic slot mechanism, and if the class changes or the class of the
;;; instance changes a new static-slot structure is allocated (if needed).
;;
;;; Dynamic-slots are a plist-like structure.
;;; The default PCL implementation is as a plist.
;;;
;;; *** Put a real discussion here of where things should be consed.
;;;  - if all the class wrappers in the world are on the same page that
;;;    would be good because during method lookup we only use the wrappers
;;;    not the classes and once a slot is cached, we only use the wrappers
;;;    too.  So a page of just wrappers would stay around all the time and
;;;    you would never have to page in the classes at least in "tight" loops.
;;;

(defstruct (iwmc-class (:predicate iwmc-class-p)
		       (:conc-name %iwmc-class-)
		       (:constructor %%allocate-instance--class ())
		       (:print-function print-instance))
  (class-wrapper nil)
  (static-slots nil)
  (dynamic-slots ()))

(defmacro iwmc-class-class-wrapper (x) `(%iwmc-class-class-wrapper ,x))
(defmacro iwmc-class-static-slots (x) `(%iwmc-class-static-slots ,x))
(defmacro iwmc-class-dynamic-slots (x) `(%iwmc-class-dynamic-slots ,x))

(defun print-instance (instance stream depth) ;This is a temporary definition
  (declare (ignore depth))		      ;used mostly for debugging the
  (printing-random-thing (instance stream)    ;bootstrapping code.
    (format stream "instance ??")))

(defmacro %allocate-instance--class (no-of-slots)
  `(let ((iwmc-class (%%allocate-instance--class)))
     (%allocate-instance--class-1 ,no-of-slots iwmc-class)
     iwmc-class))

(defmacro %allocate-instance--class-1 (no-of-slots instance)
  (once-only (instance)
    `(progn 
       (setf (iwmc-class-static-slots ,instance)
	     (%allocate-static-slot-storage--class ,no-of-slots))
       (setf (iwmc-class-dynamic-slots ,instance)
	     (%allocate-dynamic-slot-storage--class)))))


(defmacro %convert-slotd-position-to-slot-index (slotd-position)
  slotd-position)


(defmacro %allocate-static-slot-storage--class (no-of-slots)
  `(make-memory-block ,no-of-slots))

(defmacro %static-slot-storage-slot-value--class (static-slot-storage
						slot-index)
  `(memory-block-ref ,static-slot-storage ,slot-index))

(defmacro %allocate-dynamic-slot-storage--class ()
  ())

(defmacro %dynamic-slot-storage-slot-value--class (dynamic-slot-storage
						 name
						 default)
  `(getf ,dynamic-slot-storage ,name ,default))

(defmacro %dynamic-slot-storage-remove-slot--class (dynamic-slot-storage
						    name)
  `(remf ,dynamic-slot-storage ,name))



(defmacro class-of--class (iwmc-class)
  `(class-wrapper-class (iwmc-class-class-wrapper ,iwmc-class)))



  ;;   
;;;;;; Class Wrappers  (the Watercourse Way algorithm)
  ;;
;;; Well, we had this really cool scheme for keeping multiple different
;;; caches tables in the same block of memory.  Unfortunately, we only
;;; cache one thing in class wrappers these days, and soon class wrappers
;;; will go away entirely so its kind of lost generality.  I am leaving
;;; the old comment here cause the hack is worth remembering.
;;;
;;; * Old Comment
;;; * The key point are:
;;; *
;;; *  - No value in the cache can be a key for anything else stored
;;; *    in the cache.
;;; *
;;; *  - When we invalidate a wrapper cache, we flush it so that when
;;; *    it is next touched it will get a miss.
;;; *
;;; * A class wrapper is a block of memory whose first two slots have a
;;; * deadicated (I just can't help myself) purpose and whose remaining
;;; * slots are the shared cache table.  A class wrapper looks like:
;;; *
;;; *  slot 0:   <pointer to class>
;;; *  slot 1:   T if wrapper is valid, NIL otherwise.
;;; *   .
;;; *   .          shared cache
;;; *   .
;;;

(eval-when (compile load eval)

(defconstant class-wrapper-cache-size 32
  "The size of class-wrapper caches.")

(defconstant class-wrapper-leader 2
  "The number of slots at the beginning of a class wrapper which have a
   special purpose.  These are the slots that are not part of the cache.")

(defconstant class-wrapper-cache-mask 
	     (make-memory-block-mask class-wrapper-cache-size 2))

)

(defmacro make-class-wrapper (class)
  `(let ((wrapper (make-memory-block ,(+ class-wrapper-cache-size
					 class-wrapper-leader)
				     class-wrapper-area)))
     (setf (class-wrapper-class wrapper) ,class)
     (setf (class-wrapper-valid-p wrapper) t)
     wrapper))

(defmacro class-wrapper-class (class-wrapper)
  `(memory-block-ref ,class-wrapper 0))

(defmacro class-wrapper-valid-p (class-wrapper)
  `(memory-block-ref ,class-wrapper 1))

(defmacro class-wrapper-cached-key (class-wrapper offset)
  `(memory-block-ref ,class-wrapper ,offset))

(defmacro class-wrapper-cached-val (class-wrapper offset)
  `(memory-block-ref ,class-wrapper (+ ,offset 1)))

(defmacro class-wrapper-slot-value-offset (class-wrapper slot-name)
  (declare (ignore class-wrapper))
  `(+ class-wrapper-leader
      (symbol-cache-no ,slot-name ,class-wrapper-cache-mask)))


(defmacro flush-class-wrapper-cache (class-wrapper)
  `(clear-memory-block ,class-wrapper
		       ,class-wrapper-leader
		       ,class-wrapper-cache-size))

(defmacro class-wrapper-cache-cache-entry (wrapper offset key val)
  (once-only (wrapper offset key val)
    `(without-interrupts
       (setf (class-wrapper-cached-key ,wrapper ,offset) ,key)	 ;store key
       (setf (class-wrapper-cached-val ,wrapper ,offset) ,val))));store value

(defmacro class-wrapper-cache-cached-entry (wrapper offset key)
  (once-only (wrapper offset)
    `(and (eq (class-wrapper-cached-key ,wrapper ,offset) ,key)
	  (class-wrapper-cached-val ,wrapper ,offset))))

(defmacro invalidate-class-wrapper (wrapper)
  (once-only (wrapper)
    `(progn (flush-class-wrapper-cache ,wrapper)
	    (setf (class-wrapper-valid-p ,wrapper) nil))))

(defmacro validate-class-wrapper (iwmc-class)	          ;HAS to be a macro!
  `(let ((wrapper (iwmc-class-class-wrapper ,iwmc-class)));So that xxx-low
     (if (class-wrapper-valid-p wrapper)	          ;can redefine the
	 wrapper				          ;macros we use.
	 (progn (setf (iwmc-class-class-wrapper ,iwmc-class)
		      (class-wrapper (class-wrapper-class wrapper)))
		(setf (class-wrapper-valid-p wrapper) t)))))

  ;;   
;;;;;; Generating CACHE numbers
  ;;
;;; These macros should produce a CACHE number for their first argument
;;; masked to fit in their second argument.  A useful cache number is just
;;; the symbol or object's memory address.  The memory address can either
;;; be masked to fit the mask or folded down with xor to fit in the mask.
;;; See some of the other low files for examples of how to implement these
;;; macros. Except for their illustrative value, the portable versions of
;;; these macros are nearly worthless.  Any port of CommonLoops really
;;; should redefine these to be faster and produce more useful numbers.

(defvar *warned-about-symbol-cache-no* nil)
(defvar *warned-about-object-cache-no* nil)

(defmacro symbol-cache-no (symbol mask)
  (unless *warned-about-symbol-cache-no*
    (setq *warned-about-symbol-cache-no* t)
    (warn
      "Compiling PCL without having defined an implementation-specific~%~
       version of SYMBOL-CACHE-NO.  This is likely to have a significant~%~
       effect on slot-access performance.~%~
       See the definition of symbol-cache-no in the file low to get an~%~
       idea of how to implement symbol-cache-no."))
  `(logand (sxhash ,symbol) ,mask))

(defmacro object-cache-no (object mask)
  (declare (ignore object))
  (unless *warned-about-object-cache-no*
    (setq *warned-about-object-cache-no* t)
    (warn
      "Compiling PCL without having defined an implementation-specific~%~
       version of OBJECT-CACHE-NO.  This effectively disables method.~%~
       lookup caching.  See the definition of object-cache-no in the file~%~
       low to get an idea of how to implement object-cache-no."))
  `(logand 0 ,mask))


  ;;   
;;;;;; FUNCTION-ARGLIST
  ;;
;;; Given something which is functionp, function-arglist should return the
;;; argument list for it.  PCL does not count on having this available, but
;;; MAKE-SPECIALIZABLE works much better if it is available.  Versions of
;;; function-arglist for each specific port of pcl should be put in the
;;; appropriate xxx-low file. This is what it should look like:
;(defun function-arglist (function)
;  (<system-dependent-arglist-function> function))

(defun function-pretty-arglist (function)
  (declare (ignore function))
  ())

(defsetf function-pretty-arglist set-function-pretty-arglist)

(defun set-function-pretty-arglist (function new-value)
  (declare (ignore function))
  new-value)

;;;
;;; set-function-name
;;; When given a function should give this function the name <new-name>.
;;; Note that <new-name> is sometimes a list.  Some lisps get the upset
;;; in the tummy when they start thinking about functions which have
;;; lists as names.  To deal with that there is set-function-name-intern
;;; which takes a list spec for a function name and turns it into a symbol
;;; if need be.
;;;
;;; When given a funcallable instance, set-function-name MUST side-effect
;;; that FIN to give it the name.  When given any other kind of function
;;; set-function-name is allowed to return new function which is the 'same'
;;; except that it has the name.
;;;
;;; In all cases, set-function-name must return the new (or same) function.
;;; 
(defun set-function-name (function new-name)
  (declare (notinline set-function-name-1 intern-function-name))
  (set-function-name-1 function
		       (intern-function-name new-name)
		       new-name))

(defun set-function-name-1 (function new-name uninterned-name)
  (declare (ignore new-name uninterned)) function)

(defun intern-function-name (name)
  #+Symbolics name
  #-Symbolics (cond ((symbolp name) name)
		    ((listp name)
		     (intern (format nil "~S" name)
			     (if (eq (car name) 'method)
				 (symbol-package (if (listp (cadr name))
						     (cadr (cadr name))
						     (cadr name)))
				 *package*)))))


  ;;   
;;;;;; Templated functions
  ;;   
;;; In CommonLoops there are many program-generated functions which
;;; differ from other, similar program-generated functions only in the
;;; values of certain in-line constants.
;;;
;;; A prototypical example is the family of discriminating functions used by
;;; classical generic functions.  For all classical generic-functions which
;;; have the same number of required arguments and no &rest argument, the
;;; discriminating function is the same, except for the value of the
;;; "in-line" constants (the cache and generic-function).
;;;
;;; Naively, whenever we want one of these functions we have to produce and
;;; compile separate lambda. But this is very expensive, instead what we
;;; would like to do is copy the existing compiled code and replace the
;;; values of the inline constants with the right new values.
;;;
;;; Templated functions provide a nice interface to this abstraction of
;;; copying an existing compiled function and replacing certain constants
;;; with others.  Templated functions are based on the assumption that for
;;; any given CommonLisp one of the following is true:
;;;   Either:
;;;     Funcalling a lexical closure is fast, and lexical variable access
;;;     is as fast (or about as fast) in-line constant access.  In this
;;;     case we implement templated functions as lexical closures closed
;;;     over the constants we want to change from one instance of the
;;;     templated function to another.
;;;   Or:
;;;     Code can be written to take a compiled code object, copy it and
;;;     replace references to certain in-line constants with references
;;;     to other in-line constants.
;;;
;;; Actually, I believe that for most Lisp both of the above assumptions are
;;; true.  For certain lisps the explicit copy and replace scheme *may be*
;;; more efficient but the lexical closure scheme is completely portable and
;;; is likely to be more efficient since the lexical closure it returns are
;;; likely to share compiled code objects and only have separate lexical
;;; environments.
;;;
;;; Another thing to notice about templated functions is that they provide
;;; the modularity to support special objects which a particular
;;; implementation's low-level function-calling code might know about.   As
;;; an example, when a classical discriminating function is created, the
;;; code says "make a classical discriminating function with 1 required
;;; arguments". It then uses whatever comes back from the templated function
;;; code as the the discriminating function So, a particular port can easily
;;; make this return any sort of special data structure instead of one of
;;; the lexical closures the portable implementation returns.
;;;
(defvar *templated-function-types* ())
(defmacro define-function-template (name
				    template-parameters
				    instance-parameters
				    &body body)
  `(eval-when (compile load eval)
     (pushnew ',name *templated-function-types*)
     ;; Get rid of all the cached constructors.
     (setf (get ',name 'templated-fn-constructors) ())
     ;; Now define the constructor constructor.
     (setf (get ',name 'templated-fn-params)
	   (list* ',template-parameters ',instance-parameters ',body))
     (setf (get ',name 'templated-fn-constructor-constructor)
	   ,(make-templated-function-constructor-constructor
	      template-parameters instance-parameters body))))

(defun reset-templated-function-types ()
  (dolist (type *templated-function-types*)
    (setf (get type 'templated-fn-constructors) ())))

(defun get-templated-function-constructor (name &rest template-parameters)
  (setq template-parameters (copy-list template-parameters)) ;Groan.
  (let ((existing (assoc template-parameters
			 (get name 'templated-fn-constructors)
			 :test #'equal)))
    (if existing
	(progn (setf (nth 3 existing) t)	;Mark this constructor as
						;having been used.
	       (cadr existing))			;And return the actual
						;constructor.
	(let ((new-constructor
		(apply (get name 'templated-fn-constructor-constructor)
		       template-parameters)))
	  (push (list template-parameters new-constructor 'made-on-the-fly t)
		(get name 'templated-fn-constructors))
	  new-constructor))))

(defmacro pre-make-templated-function-constructor (name
						   &rest template-parameters)
  (setq template-parameters (copy-list template-parameters))	;Groan.
  (let* ((params #-GCLisp (get name 'templated-fn-params)
		 #+GCLisp (copy-tree (get name 'templated-fn-params)))
	 (template-params (car params))
	 (instance-params (cadr params))
	 (body (cddr params))
	 #+Symbolics
	 (dummy-fn-name (gensym))
	 (form 
	   (progv template-params
		  template-parameters
	    `(let ((entry
		     (or (assoc ',template-parameters 
				(get ',name 'templated-fn-constructors)
				:test #'equal)
			 (let ((new-entry
				 (list ',template-parameters () () ())))
			   (push new-entry
				 (get ',name 'templated-fn-constructors))
			   new-entry))))
	       (setf (caddr entry) 'pre-made)
	       (setf (cadr entry)
		     (function (lambda ,(eval instance-params)
				 ,(eval (cons 'progn body)))))))))
    ;;
    ;; This one may be superfluous.
    ;; 
    #+GCLisp (setq form (copy-tree form))
    #+Symbolics
    `(progn (defun ,dummy-fn-name () ,form)
	    (,dummy-fn-name))
    #-Symbolics
    form))

(defun make-templated-function-constructor-constructor (template-params
							instance-params
							body)
  (let ((cc `(function
	       (lambda ,template-params
		 (compile () (list 'lambda ,instance-params ,@body))))))
    #+GCLisp (copy-tree cc)
    #-GCLisp cc))


(defun record-definition (type spec &rest args)
  (declare (ignore type spec args))
  ())