home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume10 / comobj.lisp / part08 / low.l < prev   
Text File  |  1987-08-01  |  28KB  |  707 lines

  1. ;;;-*-Mode:LISP; Package:(PCL (LISP WALKER) 1000); Base:10; Syntax:Common-lisp -*-
  2. ;;;
  3. ;;; *************************************************************************
  4. ;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
  5. ;;;
  6. ;;; Use and copying of this software and preparation of derivative works
  7. ;;; based upon this software are permitted.  Any distribution of this
  8. ;;; software or derivative works must comply with all applicable United
  9. ;;; States export control laws.
  10. ;;; 
  11. ;;; This software is made available AS IS, and Xerox Corporation makes no
  12. ;;; warranty about the software, its performance or its conformity to any
  13. ;;; specification.
  14. ;;; 
  15. ;;; Any person obtaining a copy of this software is requested to send their
  16. ;;; name and post office or electronic mail address to:
  17. ;;;   CommonLoops Coordinator
  18. ;;;   Xerox Artifical Intelligence Systems
  19. ;;;   2400 Hanover St.
  20. ;;;   Palo Alto, CA 94303
  21. ;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
  22. ;;;
  23. ;;; Suggestions, comments and requests for improvements are also welcome.
  24. ;;; *************************************************************************
  25. ;;;
  26. ;;; This file contains portable versions of low-level functions and macros
  27. ;;; which are ripe for implementation specific customization.  None of the
  28. ;;; code in this file *has* to be customized for a particular Common Lisp
  29. ;;; implementation. Moreover, in some implementations it may not make any
  30. ;;; sense to customize some of this code.
  31. ;;;
  32. ;;; But, experience suggests that MOST Common Lisp implementors will want
  33. ;;; to customize some of the code in this file to make PCL run better in
  34. ;;; their implementation.  The code in this file has been separated and
  35. ;;; heavily commented to make that easier.
  36. ;;;
  37. ;;; Implementation-specific version of this file already exist for:
  38. ;;; 
  39. ;;;    Symbolics 3600 family       3600-low.lisp
  40. ;;;    Lucid Lisp                  lucid-low.lisp
  41. ;;;    Xerox 1100 family           1100-low.lisp
  42. ;;;    Ti Explorer                 ti-low.lisp
  43. ;;;    Vaxlisp                     vaxl-low.lisp
  44. ;;;    Spice Lisp                  spice-low.lisp
  45. ;;;    Kyoto Common Lisp           kcl-low.lisp
  46. ;;;    ExCL (Franz)                excl-low.lisp
  47. ;;;    H.P. Common Lisp            hp-low.lisp
  48. ;;;    
  49. ;;;
  50. ;;; These implementation-specific files are loaded after this file.  Because
  51. ;;; none of the macros defined by this file are used in functions defined by
  52. ;;; this file the implementation-specific files can just contain the parts of
  53. ;;; this file they want to change.  They don't have to copy this whole file
  54. ;;; and then change the parts they want.
  55. ;;;
  56. ;;; If you make changes or improvements to these files, or if you need some
  57. ;;; low-level part of PCL re-modularized to make it more portable to your
  58. ;;; system please send mail to CommonLoops.pa@Xerox.com.
  59. ;;;
  60. ;;; Thanks.
  61. ;;; 
  62.  
  63. (in-package 'pcl)
  64.  
  65.   ;;   
  66. ;;;;;; without-interrupts
  67.   ;;   
  68. ;;; OK, Common Lisp doesn't have this and for good reason.  But For all of
  69. ;;; the Common Lisp's that PCL runs on today, there is a meaningful way to
  70. ;;; implement this.  WHAT I MEAN IS:
  71. ;;;
  72. ;;; I want the body to be evaluated in such a way that no other code that is
  73. ;;; running PCL can be run during that evaluation.  I agree that the body
  74. ;;; won't take *long* to evaluate.  That is to say that I will only use
  75. ;;; without interrupts around small computations.
  76. ;;;
  77. ;;; OK?
  78. ;;;
  79. (defmacro without-interrupts (&body body)
  80.   `(progn ,.body))
  81.  
  82.   ;;   
  83. ;;;;;; Load Time Eval
  84.   ;;
  85. ;;;
  86. ;;; #, is woefully inadequate.  You can't use it inside of a macro and have
  87. ;;; the expansion of part of the macro be evaluated at load-time.
  88. ;;;
  89. ;;; load-time-eval is used to provide an interface to implementation
  90. ;;; dependent implementation of load time evaluation.
  91. ;;;
  92. ;;; A compiled call to load-time-eval:
  93. ;;;   should evaluated the form at load time,
  94. ;;;   but if it is being compiled-to-core evaluate it at compile time
  95. ;;; Interpreted calls to load-time-eval:
  96. ;;;   should just evaluate form at run-time.
  97. ;;; 
  98. ;;; The portable implementation just evaluates it every time, and PCL knows
  99. ;;; this.  PCL is careful to only use load-time-eval in places where (except
  100. ;;; for performance penalty) it is OK to evaluate the form every time.
  101. ;;; 
  102. (defmacro load-time-eval (form)
  103.   `(progn ,form))
  104.  
  105.   ;;   
  106. ;;;;;; Memory Blocks (array-like blocks of memory)
  107.   ;;
  108. ;;; The portable implementation of memory-blocks is as arrays.
  109. ;;;
  110. ;;; The area argument to make-memory-block is based on the area feature of
  111. ;;; LispM's.  As it is used in PCL that argument will always be an unquoted
  112. ;;; symbol.  So a call to make-memory-block will look like:
  113. ;;;     (make-memory-block 100 class-wrapper-area)
  114. ;;; This allows any particular implementation of make-memory-block to look at
  115. ;;; the symbol at compile time (macroexpand time) and know where the memory-
  116. ;;; block should be consed.  Currently the only values ever used as the area
  117. ;;; argument are:
  118. ;;; 
  119. ;;;    CLASS-WRAPPER-AREA        used when making a class-wrapper
  120. ;;;
  121. ;;; NOTE:
  122. ;;;     It is perfectly legitimate for an implementation of make-memory-block
  123. ;;;     to ignore the area argument.  It only exists to try to improve paging
  124. ;;;     performance in systems which do allow control over where memory is
  125. ;;;     allocated.
  126. ;;; 
  127. (defmacro make-memory-block (size &optional area)
  128.   (ignore area)
  129.   `(make-array ,size :initial-element nil))
  130.  
  131. (defmacro memory-block-size (block)
  132.   `(array-dimension ,block 0))
  133.  
  134. (defmacro memory-block-ref (block offset)
  135.   `(svref ,block ,offset))
  136.  
  137. (eval-when (compile load eval)
  138.  
  139. (defun make-memory-block-mask (size &optional (words-per-entry 2))
  140.   (logxor (1- (expt 2 (floor (log size 2))))
  141.       (1- (expt 2 (ceiling (log words-per-entry 2))))))
  142.  
  143. )
  144.  
  145. ;;;
  146. ;;; clear-memory-block sets all the slots of a memory block to nil starting
  147. ;;; at start.  This really shouldn't be a macro, it should be a function.
  148. ;;; It has to be a macro because otherwise its call to memory-block-ref will
  149. ;;; get compiled before people get a chance to change memory-block-ref.
  150. ;;; This argues one of:
  151. ;;;  - this should be a function in another file.  No, it belongs here.
  152. ;;;  - Common Lisp should have defsubst.  Probably
  153. ;;;  - Implementors should take (proclaim '(inline xxx)) more seriously.
  154. ;;;  
  155. (defmacro clear-memory-block (block start &optional times)
  156.   (once-only (block)
  157.     `(do ((end ,(if times `(+ ,start ,times) `(length ,block)))
  158.       (index ,start (+ index 1)))
  159.      ((= index end))
  160.        (setf (memory-block-ref ,block index) nil))))
  161.  
  162.   ;;   
  163. ;;;;;; CLASS-OF
  164.   ;;
  165. ;;;
  166. ;;; *class-of* is the lisp code for the definition of class-of.
  167. ;;;
  168. ;;; This version uses type-of to determine the class of an object.  Because
  169. ;;; of the underspecification of type-of, this does not always produce the
  170. ;;; "most specific class of which x is an instance".  But it is the best I
  171. ;;; can do portably.
  172. ;;;
  173. ;;; Specific ports of PCL should feel free to redefine *class-of* to provide
  174. ;;; a more accurate definition.  At some point in any definition of class-of
  175. ;;; there should be a test to determine if the argument is a %instance, and
  176. ;;; if so the %instance-class-of macro should be used to determine the class
  177. ;;; of the instance.
  178. ;;;
  179. ;;; Whenever a new meta-class is defined, the portable code will take care of
  180. ;;; modifying the definition of %instance-class-of and recompiling class-of.
  181. ;;;
  182. (defvar *class-of*
  183.     '(lambda (x) 
  184.        (or (and (%instancep x)
  185.             (%instance-class-of x))
  186.           ;(%funcallable-instance-p x)
  187.            (class-named (type-of x) t)
  188.            (error "Can't determine class of ~S" x))))
  189.  
  190. (defvar *meta-classes* ())
  191.  
  192. (defmacro %instance-class-of (arg)
  193.   `(cond ,@(iterate ((mc in *meta-classes*))
  194.          (collect
  195.            `((eq (%instance-meta-class ,arg)
  196.              ;; %^&$%& KCL has to have this stupid call to
  197.              ;; load-time-eval here because their compiler
  198.              ;; always creates a file and compiles that file.
  199.              #-KCL',(class-named (car mc))
  200.              #+KCL (load-time-eval (class-named ',(car mc))))
  201.          (funcall (function ,(cdr mc)) ,arg))))
  202.      (t
  203.       (error
  204.         "Internal error in %INSTANCE-CLASS-OF.  The argument to~%~
  205.              %instance-class-of is a %instance, but its meta-class is~%~
  206.              not one of the meta-classes defined with define-meta-class."
  207.         (%instance-meta-class ,arg)))))
  208.  
  209. (defmacro define-meta-class (name class-of-function &rest options)
  210.   (check-type name symbol "a symbol which is the name of a meta-class")
  211.   (check-type class-of-function function "a function")  
  212.   `(load-define-meta-class ',name ',class-of-function))
  213.  
  214. (defun load-define-meta-class (name class-of-function)
  215.   (or (eq name 'class)
  216.       (class-named name t)
  217.       (error "In define-meta-class, there is no class named ~S.~%~
  218.               The class ~S must be defined before evaluating this~%~
  219.               define-meta-class form."))
  220.   (let ((existing (assq name *meta-classes*)))
  221.     (if existing
  222.     (setf (cdr existing) class-of-function)
  223.     (setq *meta-classes* (nconc *meta-classes*
  224.                     (list (cons name class-of-function)))))
  225.     (recompile-class-of)))
  226.  
  227. (defun recompile-class-of ()
  228.     ;; Change the definition of class-of so that the next time it is
  229.     ;; called it will recompile itself.
  230.     ;; NOTE:  This does not have to be written this way.  If we impose
  231.     ;;        the constraint that any define-meta-class must be loaded
  232.     ;;        in the same environment as it was compiled then there is
  233.     ;;        no need for a compiler at run or load time.
  234.     ;;        By same environment I mean with the same define-meta-class
  235.     ;;        forms already in force, and this certainly seems like a
  236.     ;;        reasonable constraint to me.
  237.     (setf (symbol-function 'class-of)
  238.       #'(lambda (x)
  239.           (declare (notinline class-of))
  240.           ;; Now recompile class-of so that the new definition
  241.           ;; of %instance-class-of will take effect.
  242.           (compile 'class-of *class-of*)
  243.           (class-of x))))
  244.  
  245.   ;;
  246. ;;;;;; TYPEP and TYPE-OF support.
  247.   ;;
  248. ;;; Portable CommonLoops makes no changes to typep or type-of.  In order for
  249. ;;; those functions to work with CommonLoops objects each implementation will
  250. ;;; have to fix its typep and type-of.  It shouldn't be hard though, and
  251. ;;; these macros should help.
  252.  
  253. (defmacro %instance-typep (x type)
  254.   `(not (null (memq (class-named ,type ())
  255.                     (class-class-precedence-list (class-of ,x))))))
  256.  
  257. (defmacro %instance-type-of (x)
  258.   `(class-name (class-of ,x)))
  259.  
  260.   ;;   
  261. ;;;;;; The primitive instances.
  262.   ;;
  263. ;;;
  264. ;;; Conceptually, a %instance is an array-like datatype whose first element
  265. ;;; points to the meta-class of the %instance and whose remaining elements
  266. ;;; are used by the meta-class for whatever purpose it wants.
  267. ;;;
  268. ;;; What would like to do is use defstruct to define a new type with a
  269. ;;; variable number of slots.  Unfortunately, Common Lisp itself does not
  270. ;;; let us do that.  So we have to define a new type %instance, and have
  271. ;;; it point to an array which is the extra slots.
  272. ;;;
  273. ;;; Most any port of PCL should re-implement this datatype.  Implementing it
  274. ;;; as a variable length type so that %instance are only one vector in memory
  275. ;;; (the "extra slots" are in-line with the meta-class) will have significant
  276. ;;; impact on the speed of many CommonLoops programs.  As an example of how
  277. ;;; to do this re-implementation of %instance, please see the file 3600-low.
  278. ;;; 
  279.  
  280. (defstruct (%instance (:print-function print-instance)
  281.               (:constructor %make-instance-1 (meta-class storage))
  282.               (:predicate %instancep))
  283.   meta-class
  284.   storage)
  285.  
  286. (defmacro %make-instance (meta-class size)
  287.   `(%make-instance-1 ,meta-class (make-array ,size)))
  288.  
  289. (defmacro %instance-ref (instance index)
  290.   `(aref (%instance-storage ,instance) ,index))
  291.  
  292. (defun print-instance (instance stream depth) ;This is a temporary definition
  293.   (ignore depth)                  ;used mostly for debugging the
  294.   (printing-random-thing (instance stream)    ;bootstrapping code.
  295.     (format stream "instance ??")))
  296.  
  297.   ;;
  298. ;;;;;;  Very Low-Level representation of instances with meta-class class.
  299.   ;;
  300. ;;; As shown below, an instance with meta-class class (iwmc-class) is a three
  301. ;;; *slot* structure.
  302. ;;;   
  303. ;;; 
  304. ;;;                                             /------["Class"]
  305. ;;;                  /-------["Class Wrapper"  /  <slot-and-method-cache>]
  306. ;;;                 /
  307. ;;;  Instance--> [ / , \  ,  \ ]
  308. ;;;                     \     \
  309. ;;;                      \     \---[Instance Slot Storage Block]
  310. ;;;                       \
  311. ;;;                        \-------[Dynamic Slot plist]
  312. ;;;
  313. ;;; Instances with meta-class class point to their class indirectly through
  314. ;;; the class's class wrapper (each class has one class wrapper, not each
  315. ;;; instance).  This is done so that all the extant instances of a class can
  316. ;;; have the class they point to changed quickly.  See change-class.
  317. ;;;
  318. ;;; Static-slots are a 1-d-array-like structure.
  319. ;;; The default PCL implementation is as a memory block as described above.
  320. ;;; Particular ports are free to change this to a lower-level block of memory
  321. ;;; type structure. Once again, the accessor for static-slots storage doesn't
  322. ;;; need to do bounds checking, and static-slots structures don't need to be
  323. ;;; able to change size.  This is because new slots are added using the
  324. ;;; dynamic slot mechanism, and if the class changes or the class of the
  325. ;;; instance changes a new static-slot structure is allocated (if needed).
  326. ;;
  327. ;;; Dynamic-slots are a plist-like structure.
  328. ;;; The default PCL implementation is as a plist.
  329. ;;;
  330. ;;; *** Put a real discussion here of where things should be consed.
  331. ;;;  - if all the class wrappers in the world are on the same page that
  332. ;;;    would be good because during method lookup we only use the wrappers
  333. ;;;    not the classes and once a slot is cached, we only use the wrappers
  334. ;;;    too.  So a page of just wrappers would stay around all the time and
  335. ;;;    you would never have to page in the classes at least in "tight" loops.
  336. ;;;
  337.  
  338. (defmacro iwmc-class-p (x)
  339.   `(and (%instancep ,x)
  340.     (eq (%instance-meta-class ,x)
  341.         (load-time-eval (class-named 'class)))))
  342.  
  343. ;(defmacro %allocate-iwmc-class ()
  344. ;  `(%make-instance (load-time-eval (class-named 'class)) 3))
  345.  
  346. (defmacro iwmc-class-class-wrapper (iwmc-class)
  347.   `(%instance-ref ,iwmc-class 0))
  348.  
  349. (defmacro iwmc-class-static-slots (iwmc-class)
  350.   `(%instance-ref ,iwmc-class 1))
  351.  
  352. (defmacro iwmc-class-dynamic-slots (iwmc-class)
  353.   `(%instance-ref ,iwmc-class 2))
  354.  
  355.  
  356. (defmacro %allocate-instance--class (no-of-slots &optional class-class)
  357.   `(let ((iwmc-class
  358.        (%make-instance ,(or class-class
  359.                 '(load-time-eval (class-named 'class)))
  360.                3)))
  361.      (%allocate-instance--class-1 ,no-of-slots iwmc-class)
  362.      iwmc-class))
  363.  
  364. (defmacro %allocate-instance--class-1 (no-of-slots instance)
  365.   (once-only (instance)
  366.     `(progn 
  367.        (setf (iwmc-class-static-slots ,instance)
  368.          (%allocate-static-slot-storage--class ,no-of-slots))
  369.        (setf (iwmc-class-dynamic-slots ,instance)
  370.          (%allocate-dynamic-slot-storage--class)))))
  371.  
  372.  
  373. (defmacro %allocate-class-class (no-of-slots)    ;This is used to allocate the
  374.   `(let ((i (%make-instance nil 3)))        ;class class.  It bootstraps
  375.      (setf (%instance-meta-class i) i)        ;the call to class-named in
  376.      (setf (class-named 'class) i)        ;%allocate-instance--class.
  377.      (%allocate-instance--class-1 ,no-of-slots i)
  378.      i))
  379.  
  380. (defmacro %convert-slotd-position-to-slot-index (slotd-position)
  381.   slotd-position)
  382.  
  383.  
  384. (defmacro %allocate-static-slot-storage--class (no-of-slots)
  385.   `(make-memory-block ,no-of-slots))
  386.  
  387. (defmacro %static-slot-storage-get-slot--class (static-slot-storage
  388.                         slot-index)
  389.   `(memory-block-ref ,static-slot-storage ,slot-index))
  390.  
  391. (defmacro %allocate-dynamic-slot-storage--class ()
  392.   ())
  393.  
  394. (defmacro %dynamic-slot-storage-get-slot--class (dynamic-slot-storage
  395.                          name
  396.                          default)
  397.   `(getf ,dynamic-slot-storage ,name ,default))
  398.  
  399. (defmacro %dynamic-slot-storage-remove-slot--class (dynamic-slot-storage
  400.                             name)
  401.   `(remf ,dynamic-slot-storage ,name))
  402.  
  403.  
  404.  
  405. (defmacro class-of--class (iwmc-class)
  406.   `(class-wrapper-class (iwmc-class-class-wrapper ,iwmc-class)))
  407.  
  408. (define-meta-class class (lambda (x) (class-of--class x)))
  409.  
  410.  
  411.   ;;   
  412. ;;;;;; Class Wrappers  (the Watercourse Way algorithm)
  413.   ;;
  414. ;;; Well, we had this really cool scheme for keeping multiple different
  415. ;;; caches tables in the same block of memory.  Unfortunately, we only
  416. ;;; cache one thing in class wrappers these days, and soon class wrappers
  417. ;;; will go away entirely so its kind of lost generality.  I am leaving
  418. ;;; the old comment here cause the hack is worth remembering.
  419. ;;;
  420. ;;; * Old Comment
  421. ;;; * The key point are:
  422. ;;; *
  423. ;;; *  - No value in the cache can be a key for anything else stored
  424. ;;; *    in the cache.
  425. ;;; *
  426. ;;; *  - When we invalidate a wrapper cache, we flush it so that when
  427. ;;; *    it is next touched it will get a miss.
  428. ;;; *
  429. ;;; * A class wrapper is a block of memory whose first two slots have a
  430. ;;; * deadicated (I just can't help myself) purpose and whose remaining
  431. ;;; * slots are the shared cache table.  A class wrapper looks like:
  432. ;;; *
  433. ;;; *  slot 0:   <pointer to class>
  434. ;;; *  slot 1:   T if wrapper is valid, NIL otherwise.
  435. ;;; *   .
  436. ;;; *   .          shared cache
  437. ;;; *   .
  438. ;;;
  439.  
  440. (eval-when (compile load eval)
  441.  
  442. (defconstant class-wrapper-cache-size 32
  443.   "The size of class-wrapper caches.")
  444.  
  445. (defconstant class-wrapper-leader 2
  446.   "The number of slots at the beginning of a class wrapper which have a
  447.    special purpose.  These are the slots that are not part of the cache.")
  448.  
  449. ; due to a compiler bug, the extra "2" default argument has been added
  450. ; to the following function invocation, for HP Lisp. rds 3/6/87
  451. (defconstant class-wrapper-cache-mask 
  452.          (make-memory-block-mask class-wrapper-cache-size 2))
  453.  
  454. )
  455.  
  456. (defmacro make-class-wrapper (class)
  457.   `(let ((wrapper (make-memory-block ,(+ class-wrapper-cache-size
  458.                      class-wrapper-leader)
  459.                      class-wrapper-area)))
  460.      (setf (class-wrapper-class wrapper) ,class)
  461.      (setf (class-wrapper-valid-p wrapper) t)
  462.      wrapper))
  463.  
  464. (defmacro class-wrapper-class (class-wrapper)
  465.   `(memory-block-ref ,class-wrapper 0))
  466.  
  467. (defmacro class-wrapper-valid-p (class-wrapper)
  468.   `(memory-block-ref ,class-wrapper 1))
  469.  
  470. (defmacro class-wrapper-cached-key (class-wrapper offset)
  471.   `(memory-block-ref ,class-wrapper ,offset))
  472.  
  473. (defmacro class-wrapper-cached-val (class-wrapper offset)
  474.   `(memory-block-ref ,class-wrapper (+ ,offset 1)))
  475.  
  476. (defmacro class-wrapper-get-slot-offset (class-wrapper slot-name)
  477.   (ignore class-wrapper)
  478.   `(+ class-wrapper-leader
  479.       0
  480.       (symbol-cache-no ,slot-name ,class-wrapper-cache-mask)))
  481.  
  482.  
  483. (defmacro flush-class-wrapper-cache (class-wrapper)
  484.   `(clear-memory-block ,class-wrapper
  485.                ,class-wrapper-leader
  486.                ,class-wrapper-cache-size))
  487.  
  488. (defmacro class-wrapper-cache-cache-entry (wrapper offset key val)
  489.   (once-only (wrapper offset key val)
  490.     `(without-interrupts
  491.        (setf (class-wrapper-cached-key ,wrapper ,offset) ,key)     ;store key
  492.        (setf (class-wrapper-cached-val ,wrapper ,offset) ,val))));store value
  493.  
  494. (defmacro class-wrapper-cache-cached-entry (wrapper offset key)
  495.   (once-only (wrapper offset)
  496.     `(and (eq (class-wrapper-cached-key ,wrapper ,offset) ,key)
  497.       (class-wrapper-cached-val ,wrapper ,offset))))
  498.  
  499. (defmacro invalidate-class-wrapper (wrapper)
  500.   (once-only (wrapper)
  501.     `(progn (flush-class-wrapper-cache ,wrapper)
  502.         (setf (class-wrapper-valid-p ,wrapper) nil))))
  503.  
  504. (defmacro validate-class-wrapper (iwmc-class)              ;HAS to be a macro!
  505.   `(let ((wrapper (iwmc-class-class-wrapper ,iwmc-class)));So that xxx-low
  506.      (if (class-wrapper-valid-p wrapper)              ;can redefine the
  507.      wrapper                          ;macros we use.
  508.      (progn (setf (iwmc-class-class-wrapper ,iwmc-class)
  509.               (class-wrapper (class-wrapper-class wrapper)))
  510.         (setf (class-wrapper-valid-p wrapper) t)))))
  511.  
  512.   ;;   
  513. ;;;;;; Generating CACHE numbers
  514.   ;;
  515. ;;; These macros should produce a CACHE number for their first argument
  516. ;;; masked to fit in their second argument.  A useful cache number is just
  517. ;;; the symbol or object's memory address.  The memory address can either
  518. ;;; be masked to fit the mask or folded down with xor to fit in the mask.
  519. ;;; See some of the other low files for examples of how to implement these
  520. ;;; macros. Except for their illustrative value, the portable versions of
  521. ;;; these macros are nearly worthless.  Any port of CommonLoops really
  522. ;;; should redefine these to be faster and produce more useful numbers.
  523.  
  524. (defvar *warned-about-symbol-cache-no* nil)
  525. (defvar *warned-about-object-cache-no* nil)
  526.  
  527. (defmacro symbol-cache-no (symbol mask)
  528.   (unless *warned-about-symbol-cache-no*
  529.     (setq *warned-about-symbol-cache-no* t)
  530.     (warn
  531.       "Compiling PCL without having defined an implementation-specific~%~
  532.        version of SYMBOL-CACHE-NO.  This is likely to have a significant~%~
  533.        effect on slot-access performance.~%~
  534.        See the definition of symbol-cache-no in the file low to get an~%~
  535.        idea of how to implement symbol-cache-no."))
  536.   `(logand (sxhash ,symbol) ,mask))
  537.  
  538. (defmacro object-cache-no (object mask)
  539.   (ignore object)
  540.   (unless *warned-about-object-cache-no*
  541.     (setq *warned-about-object-cache-no* t)
  542.     (warn
  543.       "Compiling PCL without having defined an implementation-specific~%~
  544.        version of OBJECT-CACHE-NO.  This effectively disables method.~%~
  545.        lookup caching.  See the definition of object-cache-no in the file~%~
  546.        low to get an idea of how to implement object-cache-no."))
  547.   `(logand 0 ,mask))
  548.  
  549.  
  550.   ;;   
  551. ;;;;;; FUNCTION-ARGLIST
  552.   ;;
  553. ;;; Given something which is functionp, function-arglist should return the
  554. ;;; argument list for it.  PCL does not count on having this available, but
  555. ;;; MAKE-SPECIALIZABLE works much better if it is available.  Versions of
  556. ;;; function-arglist for each specific port of pcl should be put in the
  557. ;;; appropriate xxx-low file. This is what it should look like:
  558. ;(defun function-arglist (function)
  559. ;  (<system-dependent-arglist-function> function))
  560.  
  561. (defun function-pretty-arglist (function)
  562.   (ignore function)
  563.   ())
  564.  
  565. (defsetf function-pretty-arglist set-function-pretty-arglist)
  566.  
  567. (defun set-function-pretty-arglist (function new-value)
  568.   (ignore function)
  569.   new-value)
  570.  
  571.  
  572.  
  573.   ;;   
  574. ;;;;;; Templated functions
  575.   ;;   
  576. ;;; In CommonLoops there are many program-generated functions which
  577. ;;; differ from other, similar program-generated functions only in the
  578. ;;; values of certain in-line constants.
  579. ;;;
  580. ;;; A prototypical example is the family of discriminating functions used by
  581. ;;; classical discriminators.  For all classical discriminators which have
  582. ;;; the same number of required arguments and no &rest argument, the
  583. ;;; discriminating function is the same, except for the value of the
  584. ;;; "in-line" constants (the cache and discriminator).
  585. ;;;
  586. ;;; Naively, whenever we want one of these functions we have to produce and
  587. ;;; compile separate lambda. But this is very expensive, instead what we
  588. ;;; would like to do is copy the existing compiled code and replace the
  589. ;;; values of the inline constants with the right new values.
  590. ;;;
  591. ;;; Templated functions provide a nice interface to this abstraction of
  592. ;;; copying an existing compiled function and replacing certain constants
  593. ;;; with others.  Templated functions are based on the assumption that for
  594. ;;; any given CommonLisp one of the following is true:
  595. ;;;   Either:
  596. ;;;     Funcalling a lexical closure is fast, and lexical variable access
  597. ;;;     is as fast (or about as fast) in-line constant access.  In this
  598. ;;;     case we implement templated functions as lexical closures closed
  599. ;;;     over the constants we want to change from one instance of the
  600. ;;;     templated function to another.
  601. ;;;   Or:
  602. ;;;     Code can be written to take a compiled code object, copy it and
  603. ;;;     replace references to certain in-line constants with references
  604. ;;;     to other in-line constants.
  605. ;;;
  606. ;;; Actually, I believe that for most Lisp both of the above assumptions are
  607. ;;; true.  For certain lisps the explicit copy and replace scheme *may be*
  608. ;;; more efficient but the lexical closure scheme is completely portable and
  609. ;;; is likely to be more efficient since the lexical closure it returns are
  610. ;;; likely to share compiled code objects and only have separate lexical
  611. ;;; environments.
  612. ;;;
  613. ;;; Another thing to notice about templated functions is that they provide
  614. ;;; the modularity to support special objects which a particular
  615. ;;; implementation's low-level function-calling code might know about.   As
  616. ;;; an example, when a classical discriminating function is created, the
  617. ;;; code says "make a classical discriminating function with 1 required
  618. ;;; arguments". It then uses whatever comes back from the templated function
  619. ;;; code as the the discriminating function So, a particular port can easily
  620. ;;; make this return any sort of special data structure instead of one of
  621. ;;; the lexical closures the portable implementation returns.
  622. ;;;
  623. (defvar *templated-function-types* ())
  624. (defmacro define-function-template (name
  625.                     template-parameters
  626.                     instance-parameters
  627.                     &body body)
  628.   `(progn
  629.      (pushnew ',name *templated-function-types*)
  630.      ;; Get rid of all the cached constructors.
  631.      (setf (get ',name 'templated-fn-constructors) ())
  632.      ;; Now define the constructor constructor.
  633.      (setf (get ',name 'templated-fn-params)
  634.        (list* ',template-parameters ',instance-parameters ',body))
  635.      (setf (get ',name 'templated-fn-constructor-constructor)
  636.        ,(make-templated-function-constructor-constructor
  637.           template-parameters instance-parameters body))))
  638.  
  639. (defun reset-templated-function-types ()
  640.   (dolist (type *templated-function-types*)
  641.     (setf (get type 'templated-fn-constructors) ())))
  642.  
  643. (defun get-templated-function-constructor (name &rest template-parameters)
  644.   (setq template-parameters (copy-list template-parameters)) ;Groan.
  645.   (let ((existing (assoc template-parameters
  646.              (get name 'templated-fn-constructors)
  647.              :test #'equal)))
  648.     (if existing
  649.     (progn (setf (nth 3 existing) t)    ;Mark this constructor as
  650.                         ;having been used.
  651.            (cadr existing))            ;And return the actual
  652.                         ;constructor.
  653.     (let ((new-constructor
  654.         (apply (get name 'templated-fn-constructor-constructor)
  655.                template-parameters)))
  656.       (push (list template-parameters new-constructor 'made-on-the-fly t)
  657.         (get name 'templated-fn-constructors))
  658.       new-constructor))))
  659.  
  660. (defmacro pre-make-templated-function-constructor (name
  661.                            &rest template-parameters)
  662.   (setq template-parameters (copy-list template-parameters))    ;Groan.
  663.   (let* ((params (get name 'templated-fn-params))
  664.      (template-params (car params))
  665.      (instance-params (cadr params))
  666.      (body (cddr params))
  667.      (dummy-fn-name (gensym)))   ;For the 3600, which doesn't bother to 
  668.                      ;compile top-level forms, we do the
  669.                      ;top-level form compilation by hand.
  670.     (progv template-params
  671.        template-parameters
  672.       `(progn
  673.      (defun ,dummy-fn-name ()
  674.        (let ((entry
  675.            (or (assoc ',template-parameters 
  676.                   (get ',name 'templated-fn-constructors)
  677.                   :test #'equal)
  678.                (let ((new-entry
  679.                    (list ',template-parameters () () ())))
  680.              (push new-entry
  681.                    (get ',name 'templated-fn-constructors))
  682.              new-entry))))
  683.          (setf (caddr entry) 'pre-made)
  684.          (setf (cadr entry)
  685.            (function (lambda ,(eval instance-params)
  686.                    ,(eval (cons 'progn body)))))))
  687.      (,dummy-fn-name)))))
  688.  
  689. (defun make-templated-function-constructor-constructor (template-params
  690.                             instance-params
  691.                             body)
  692.   `(function
  693.      (lambda ,template-params
  694.        (compile () (list 'lambda ,instance-params ,@body)))))
  695.  
  696.   ;;   
  697. ;;;;;; 
  698.   ;;   
  699.  
  700. (defun record-definition (name type &rest args)
  701.   (ignore name type args)
  702.   ())
  703.  
  704. (defun compile-time-define (&rest ignore)
  705.   (ignore ignore))
  706.  
  707.