home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume10 / comobj.lisp / part04 / fsc-low.l < prev    next >
Encoding:
Text File  |  1987-07-30  |  13.0 KB  |  376 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.  
  27. #|  To do:
  28.  
  29. figure out bootstrapping issues
  30.  
  31. fix problems caused by make-iwmc-class-accessor
  32.  
  33. polish up the low levels of iwmc-class, 
  34.  
  35. fix use of get-slot-using-class--class-internal
  36.  
  37. |#
  38.   ;;   
  39. ;;;;;; FUNCALLABLE INSTANCES
  40.   ;;
  41.  
  42. #|
  43.  
  44. In CommonLoops, generic functions are instances whose meta class is
  45. funcallable-standard-class.  Instances with this meta class behave
  46. something like lexical closures in that they have slots, just like
  47. instances with meta class standard-class, and are also funcallable.
  48. When an instance with meta class funcallable-standard-class is
  49. funcalled, the value of its function slot is called.
  50.  
  51. It is possible to implement funcallable instances in pure Common Lisp.
  52. A simple implementation which uses lexical closures as the instances and
  53. a hash table to record that the lexical closures are funcallable
  54. instances is easy to write.  Unfortunately, this implementation adds
  55. such significant overhead:
  56.  
  57.    to generic-function-invocation (1 function call)
  58.    to slot-access (1 function call)
  59.    to class-of a generic-function (1 hash-table lookup)
  60.  
  61. In other words, it is too slow to be practical.
  62.  
  63. Instead, PCL uses a specially tailored implementation for each common
  64. Lisp and makes no attempt to provide a purely portable implementation.
  65. The specially tailored implementations are based on each the lexical
  66. closure's provided by that implementation and tend to be fairly easy to
  67. write.
  68.  
  69. |#
  70.  
  71. (in-package 'pcl)
  72.  
  73. ;;;
  74. ;;; The first part of the file contains the implementation dependent code
  75. ;;; to implement the low-level funcallable instances.  Each implementation
  76. ;;; must provide the following functions and macros:
  77. ;;; 
  78. ;;;    MAKE-FUNCALLABLE-INSTANCE-1 ()
  79. ;;;       should create and return a new funcallable instance
  80. ;;;
  81. ;;;    FUNCALLABLE-INSTANCE-P (x)
  82. ;;;       the obvious predicate
  83. ;;;
  84. ;;;    SET-FUNCALLABLE-INSTANCE-FUNCTION-1 (fin new-value)
  85. ;;;       change the fin so that when it is funcalled, the new-value
  86. ;;;       function is called.  Note that it is legal for new-value
  87. ;;;       to be copied before it is installed in the fin (the Lucid
  88. ;;;       implementation in particular does this).
  89. ;;;
  90. ;;;    FUNCALLABLE-INSTANCE-DATA-1 (fin data-name)
  91. ;;;       should return the value of the data named data-name in the fin
  92. ;;;       data-name is one of the symbols in the list which is the value
  93. ;;;       of funcallable-instance-data.  Since data-name is almost always
  94. ;;;       a quoted symbol and funcallable-instance-data is a constant, it
  95. ;;;       is possible (and worthwhile) to optimize the computation of
  96. ;;;       data-name's offset in the data part of the fin.
  97. ;;;       
  98.  
  99. (defconstant funcallable-instance-data
  100.          '(class wrapper static-slots dynamic-slots)
  101.   "These are the 'data-slots' which funcallable instances have so that
  102.    the meta-class funcallable-standard-class can store class, and static
  103.    and dynamic slots in them.")
  104.  
  105. #+Lucid
  106. (progn
  107.   
  108. (defconstant funcallable-instance-procedure-size 50)
  109. (defconstant funcallable-instance-flag-bit #B1000000000000000)
  110. (defvar *funcallable-instance-trampolines* ()
  111.   "This is a list of all the procedure sizes which were too big to be stored
  112.    directly in a funcallable instance.  For each of these procedures, a
  113.    trampoline procedure had to be used.  This is for metering information
  114.    only.")
  115.  
  116. (defun make-funcallable-instance-1 ()
  117.   (let ((new-fin (lucid::new-procedure funcallable-instance-procedure-size)))
  118.     ;; Have to set the procedure function to something for two reasons.
  119.     ;;   1. someone might try to funcall it.
  120.     ;;   2. the flag bit that says the procedure is a funcallable
  121.     ;;      instance is set by set-funcallable-instance-function.
  122.     (set-funcallable-instance-function
  123.       new-fin
  124.       #'(lambda (&rest ignore)
  125.       (declare (ignore ignore))
  126.       (error "Attempt to funcall a funcallable-instance without first~%~
  127.                   setting its funcallable-instance-function.")))
  128.     new-fin))
  129.  
  130. (defmacro funcallable-instance-p (x)
  131.   (once-only (x)
  132.     `(and (lucid::procedurep ,x)
  133.       (logand (lucid::procedure-ref ,x lucid::procedure-flags)
  134.           funcallable-instance-flag-bit))))
  135.  
  136. (defun set-funcallable-instance-function-1 (fin new-value)
  137.   (unless (funcallable-instance-p fin)
  138.     (error "~S is not a funcallable-instance"))
  139.   (cond ((not (functionp new-value))
  140.      (error "~S is not a function."))
  141.     ((not (lucid::procedurep new-value))
  142.      ;; new-value is an interpreted function.  Install a
  143.      ;; trampoline to call the interpreted function.
  144.      (set-funcallable-instance-function fin
  145.                         (make-trampoline new-value)))
  146.     (t
  147.      (let ((new-procedure-size (lucid::procedure-length new-value))
  148.            (max-procedure-size (- funcallable-instance-procedure-size
  149.                       (length funcallable-instance-data))))
  150.        (if (< new-procedure-size max-procedure-size)
  151.            ;; The new procedure fits in the funcallable-instance.
  152.            ;; Just copy the new procedure into the fin procedure,
  153.            ;; also be sure to update the procedure-flags of the
  154.            ;; fin to keep it a fin.
  155.            (progn 
  156.          (dotimes (i max-procedure-size)
  157.            (setf (lucid::procedure-ref fin i)
  158.              (lucid::procedure-ref new-value i)))
  159.          (setf (lucid::procedure-ref fin lucid::procedure-flags)
  160.                (logand funcallable-instance-flag-bit
  161.                    (lucid::procedure-ref
  162.                  fin lucid::procedure-flags)))
  163.          new-value)
  164.            ;; The new procedure doesn't fit in the funcallable instance
  165.            ;; Instead, install a trampoline procedure which will call
  166.            ;; the new procecdure.  First make note of the fact that we
  167.            ;; had to trampoline so that we can see if its worth upping
  168.            ;; the value of funcallable-instance-procedure-size.
  169.            (progn
  170.          (push new-procedure-size *funcallable-instance-trampolines*)
  171.          (set-funcallable-instance-function
  172.            fin
  173.            (make-trampoline new-value))))))))
  174.  
  175.  
  176. (defmacro funcallable-instance-data-1 (instance data)
  177.   `(lucid::procedure-ref ,instance
  178.              (- funcallable-instance-procedure-size
  179.                 (position ,data funcallable-instance-data))))
  180.   
  181. );dicuL+#
  182.  
  183. ;;;
  184. ;;; All of these Lisps (Xerox Symbolics ExCL KCL and VAXLisp) have the
  185. ;;; following in Common:
  186. ;;; 
  187. ;;;    - they represent their compiled closures as a pair of
  188. ;;;      environment and compiled function
  189. ;;;    - they represent the environment using a list or a vector
  190. ;;;    - I don't (YET) know how to add a bit to the damn things to
  191. ;;;      say that they are funcallable-instances and so I have to
  192. ;;;      use the last entry in the closure environment to do that.
  193. ;;;      This is a lose because that is much slower, I have to CDR
  194. ;;;      down to the last element of the environment.
  195. ;;;      
  196. #+(OR Xerox Symbolics ExCL KCL (and DEC VAX))
  197. (progn
  198.  
  199. (defvar *funcallable-instance-marker* (list "Funcallable Instance Marker"))
  200.  
  201. (defconstant funcallable-instance-closure-size 15)
  202.  
  203. (defmacro lexical-closure-p (lc)
  204.   #+Xerox         `(typep ,lc 'il:compiled-closure)
  205.   #+Symbolics     `(si:lexical-closure-p ,lc)
  206.   #+ExCL          `()
  207.   #+KCL           `()
  208.   #+(and DEC VAX) (once-only (lc)
  209.             `(and (listp ,lc)
  210.               (eq (car ,lc) 'system::%compiled-closure%))))
  211.  
  212. (defmacro lexical-closure-env (lc)
  213.   #+Xerox         `()
  214.   #+Symbolics     `(si:lexical-closure-environment ,lc)
  215.   #+ExCL          `()
  216.   #+KCL           `()
  217.   #+(and DEC VAX) `(caadr ,lc))
  218.  
  219. (defmacro lexical-closure-env-size (env)
  220.   #+Xerox         `()
  221.   #+Symbolics     `(length ,env)
  222.   #+ExCL          `()
  223.   #+KCL           `()
  224.   #+(and DEC VAX) `(array-dimension ,env 0))  
  225.  
  226. (defmacro lexical-closure-env-ref (env index check) check
  227.   #+Xerox         `()
  228.   #+Symbolics     `(let ((env ,env))
  229.              (dotimes (i ,index)
  230.                (setq env (cdr env)))
  231.              (car env))
  232.   #+ExCL          `()
  233.   #+KCL           `()
  234.   #+(and DEC VAX) (once-only (env)
  235.             `(and ,(or checkp
  236.                    `(= (array-dimension ,env 0)
  237.                    funcallable-instance-closure-size))
  238.               (svref ,env 0))))
  239.  
  240. (defmacro lexical-closure-env-set (env index new checkp) checkp
  241.   #+Xerox         `()
  242.   #+Symbolics     `(let ((env ,env))
  243.              (dotimes (i ,index)
  244.                (setq env (cdr env)))
  245.              (setf (car env) ,new))
  246.   #+ExCL          `()
  247.   #+KCL           `()
  248.   #+(and DEC VAX) (once-only (env)
  249.             `(and ,(or checkp
  250.                    `(= (array-dimension ,env 0)
  251.                    funcallable-instance-closure-size))
  252.               (setf (svref ,env ,index) ,new))))
  253.  
  254. (defmacro lexical-closure-code (lc)
  255.   #+Xerox         `()
  256.   #+Symbolics     `(si:lexical-closure-function ,lc)
  257.   #+ExCL          `()
  258.   #+KCL           `()
  259.   #+(and DEC VAX) `(caddr ,lc))
  260.  
  261. (defmacro compiled-function-code (cf)  
  262.   #+Xerox         `()
  263.   #+Symbolics     cf
  264.   #+ExCL          `()
  265.   #+KCL           `()
  266.   #+(and DEC VAX) `())
  267.  
  268. (eval-when (load eval)
  269.   (let ((dummies ()))
  270.     (dotimes (i funcallable-instance-closure-size)
  271.       (push (gentemp "Dummy Closure Variable ") dummies))
  272.     (compile 'make-funcallable-instance-1    ;For the time being, this use
  273.          `(lambda ()            ;of compile at load time is
  274.         (let (new-fin ,@dummies)    ;simpler than using #.
  275.           (setq new-fin #'(lambda ()
  276.                     ,@(mapcar #'(lambda (d)
  277.                           `(setq ,d (dummy-fn ,d)))
  278.                           dummies)))
  279.           (lexical-closure-env-set
  280.             (lexical-closure-env new-fin)
  281.             (1- funcallable-instance-closure-size)
  282.             *funcallable-instance-marker*
  283.             t)
  284.           new-fin)))))
  285.  
  286. (defmacro funcallable-instance-p (x)
  287.   (once-only (x)
  288.     `(and (lexical-closure-p ,x)
  289.       (let ((env (lexical-closure-env ,x)))
  290.         (and (eq (lexical-closure-env-ref
  291.                env (1- funcallable-instance-closure-size) t)
  292.              *funcallable-instance-marker*))))))
  293.  
  294. (defun set-funcallable-instance-function-1 (fin new-value)
  295.   (cond ((lexical-closure-p new-value)
  296.      (let* ((fin-env (lexical-closure-env fin))
  297.         (new-env (lexical-closure-env new-value))
  298.         (new-env-size (lexical-closure-env-size new-env))
  299.         (fin-env-size (- funcallable-instance-closure-size
  300.                  (length funcallable-instance-data))))
  301.        (cond ((<= new-env-size fin-env-size)
  302.           (dotimes (i new-env-size)
  303.             (lexical-closure-env-set
  304.               fin-env i (lexical-closure-env-ref new-env i nil) nil))
  305.           (setf (lexical-closure-code fin)
  306.             (lexical-closure-code new-value)))
  307.          (t            
  308.           (set-funcallable-instance-function-1
  309.             fin (make-trampoline new-value))))))
  310.     (t
  311.      #+Symbolics
  312.      (set-funcallable-instance-function-1 fin
  313.                           (make-trampoline new-value))
  314.      #-Symbolics
  315.      (setf (lexical-closure-code fin)
  316.            (compiled-function-code new-value)))))
  317.     
  318. (defmacro funcallable-instance-data-1 (fin data)
  319.   `(lexical-closure-env-ref
  320.      (lexical-closure-env ,fin)
  321.      (- funcallable-instance-closure-size
  322.     (position ,data funcallable-instance-data)
  323.     2)
  324.      nil))
  325.  
  326. (defsetf funcallable-instance-data-1 (fin data) (new-value)
  327.   `(lexical-closure-env-set
  328.      (lexical-closure-env ,fin)
  329.      (- funcallable-instance-closure-size
  330.     (position ,data funcallable-instance-data)
  331.     2)
  332.      ,new-value
  333.      nil))
  334.  
  335. );
  336.  
  337.  
  338. (defun make-trampoline (function)
  339.   #'(lambda (&rest args)
  340.       (apply function args)))
  341.  
  342. (defun set-funcallable-instance-function (fin new-value)
  343.   (cond ((not (funcallable-instance-p fin))
  344.      (error "~S is not a funcallable-instance"))
  345.     ((not (functionp new-value))
  346.      (error "~S is not a function."))
  347.     ((compiled-function-p new-value)
  348.      (set-funcallable-instance-function-1 fin new-value))
  349.     (t
  350.      (set-funcallable-instance-function-1 fin
  351.                           (make-trampoline new-value)))))
  352.  
  353.  
  354. (defmacro funcallable-instance-class (fin)
  355.   `(funcallable-instance-data-1 ,fin 'class))
  356.  
  357. (defmacro funcallable-instance-wrapper (fin)
  358.   `(funcallable-instance-data-1 ,fin 'wrapper))
  359.  
  360. (defmacro funcallable-instance-static-slots (fin)
  361.   `(funcallable-instance-data-1 ,fin 'static-slots))
  362.  
  363. (defmacro funcallable-instance-dynamic-slots (fin)
  364.   `(funcallable-instance-data-1 ,fin 'dynamic-slots))
  365.  
  366. (defun make-funcallable-instance (class wrapper number-of-static-slots)
  367.   (let ((fin (make-funcallable-instance-1))
  368.     (static-slots (make-memory-block number-of-static-slots))
  369.     (dynamic-slots ()))
  370.     (setf (funcallable-instance-class fin) class
  371.       (funcallable-instance-wrapper fin) wrapper
  372.       (funcallable-instance-static-slots fin) static-slots
  373.       (funcallable-instance-dynamic-slots fin) dynamic-slots)
  374.     fin))
  375.  
  376.