home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / src-16f.lha / compiler / eval-comp.lisp < prev    next >
Encoding:
Text File  |  1992-12-09  |  11.4 KB  |  309 lines

  1. ;;; -*- Package: C; Log: C.Log -*-
  2. ;;;
  3. ;;; **********************************************************************
  4. ;;; This code was written as part of the CMU Common Lisp project at
  5. ;;; Carnegie Mellon University, and has been placed in the public domain.
  6. ;;; If you want to use this code or any part of CMU Common Lisp, please contact
  7. ;;; Scott Fahlman or slisp-group@cs.cmu.edu.
  8. ;;;
  9. (ext:file-comment
  10.   "$Header: eval-comp.lisp,v 1.22 92/11/25 10:32:12 wlott Exp $")
  11. ;;;
  12. ;;; **********************************************************************
  13. ;;;
  14. ;;; This file represents the current state of on-going development on compiler
  15. ;;; hooks for an interpreter that takes the compiler's IR1 of a program.
  16. ;;;
  17. ;;; Written by Bill Chiles.
  18. ;;;
  19.  
  20. (in-package "C")
  21.  
  22. (proclaim '(special *constants* *free-variables* *compile-component*
  23.             *code-vector* *next-location* *result-fixups*
  24.             *free-functions* *source-paths* *failed-optimizations*
  25.             *seen-blocks* *seen-functions* *list-conflicts-table*
  26.             *continuation-number* *continuation-numbers*
  27.             *number-continuations* *tn-id* *tn-ids* *id-tns*
  28.             *label-ids* *label-id* *id-labels*
  29.             *compiler-error-count*
  30.             *compiler-warning-count* *compiler-note-count*
  31.             *compiler-error-output* *compiler-error-bailout*
  32.             *compiler-trace-output*
  33.             *last-source-context* *last-original-source*
  34.             *last-source-form* *last-format-string* *last-format-args*
  35.             *last-message-count* *check-consistency*
  36.             *all-components* *converting-for-interpreter*
  37.             *source-info* *block-compile* *current-path*
  38.             *current-component* *lexical-environment*))
  39.  
  40. (export '(compile-for-eval lambda-eval-info-frame-size
  41.       lambda-eval-info-args-passed lambda-eval-info-entries
  42.       lambda-eval-info-function entry-node-info-st-top
  43.       entry-node-info-nlx-tag))
  44.  
  45.  
  46. ;;; COMPILE-FOR-EVAL -- Public.
  47. ;;;
  48. ;;; This translates form into the compiler's IR1 and performs environment
  49. ;;; analysis.  It is sort of a combination of NCOMPILE-FILE, SUB-COMPILE-FILE,
  50. ;;; COMPILE-TOP-LEVEL, and COMPILE-COMPONENT.
  51. ;;;
  52. (defun compile-for-eval (form quietly)
  53.   (with-ir1-namespace
  54.     (let* ((*block-compile* nil)
  55.        (*lexical-environment* (make-null-environment))
  56.        ;;
  57.        (*compiler-error-output*
  58.         (if quietly
  59.         (make-broadcast-stream)
  60.         *error-output*))
  61.        (*compiler-trace-output* nil)
  62.        (*compiler-error-bailout*
  63.         #'(lambda () (error "Fatal error, aborting evaluation.")))
  64.        ;;
  65.        (*current-path* nil)
  66.        (*last-source-context* nil)
  67.        (*last-original-source* nil)
  68.        (*last-source-form* nil)
  69.        (*last-format-string* nil)
  70.        (*last-format-args* nil)
  71.        (*last-message-count* 0)
  72.        ;;
  73.        (*compiler-error-count* 0)
  74.        (*compiler-warning-count* 0)
  75.        (*compiler-note-count* 0)
  76.        (*source-info* (make-lisp-source-info form))
  77.        (*converting-for-interpreter* t)
  78.        (*gensym-counter* 0))
  79.  
  80.       (clear-stuff nil)
  81.       (find-source-paths form 0)
  82.       ;;
  83.       ;; This LET comes from COMPILE-TOP-LEVEL.
  84.       ;; The noted DOLIST is a splice from a call that COMPILE-TOP-LEVEL makes.
  85.       (with-compilation-unit ()
  86.     (let ((lambdas (list (ir1-top-level form '(original-source-start 0 0)
  87.                         t))))
  88.       (declare (list lambdas))
  89.       (dolist (lambda lambdas)
  90.         (let* ((component
  91.             (block-component (node-block (lambda-bind lambda))))
  92.            (*all-components* (list component)))
  93.           (local-call-analyze component)))
  94.       (multiple-value-bind (components top-components)
  95.                    (find-initial-dfo lambdas)
  96.         (let ((*all-components* (append components top-components)))
  97.           (when *check-consistency*
  98.         (check-ir1-consistency *all-components*))
  99.           ;;
  100.           ;; This DOLIST body comes from the beginning of
  101.           ;; COMPILE-COMPONENT.
  102.           (dolist (component *all-components*)
  103.         (ir1-finalize component)
  104.         (let ((*compile-component* component))
  105.           (environment-analyze component))
  106.         (annotate-component-for-eval component))
  107.         (when *check-consistency*
  108.           (check-ir1-consistency *all-components*))))
  109.       (car lambdas))))))
  110.  
  111.  
  112. ;;;; Annotating IR1 for interpretation.
  113.  
  114. (defstruct (lambda-eval-info (:print-function print-lambda-eval-info)
  115.                  (:constructor make-lambda-eval-info
  116.                        (frame-size args-passed entries)))
  117.   frame-size        ;Number of stack locations needed to hold locals.
  118.   args-passed        ;Number of referenced arguments passed to lambda.
  119.   entries        ;A-list mapping entry nodes to stack locations.
  120.   (function nil))    ;A function object corresponding to this lambda.
  121.  
  122. (defun print-lambda-eval-info (obj str n)
  123.   (declare (ignore n obj))
  124.   (format str "#<Lambda-eval-info>"))
  125.  
  126. (defstruct (entry-node-info (:print-function print-entry-node-info)
  127.                 (:constructor make-entry-node-info
  128.                       (st-top nlx-tag)))
  129.   st-top    ;Stack top when we encounter the entry node.
  130.   nlx-tag)    ;Tag to which to throw to get back entry node's context.
  131.  
  132. (defun print-entry-node-info (obj str n)
  133.   (declare (ignore n obj))
  134.   (format str "#<Entry-node-info>"))
  135.  
  136.  
  137. ;;; Some compiler funny functions have definitions, so the interpreter can
  138. ;;; call them.  These require special action to coordinate the interpreter,
  139. ;;; system call stack, and the environment.  The annotation prepass marks the
  140. ;;; references to these as :unused, so the interpreter doesn't try to fetch
  141. ;;; function's through these undefined symbols.
  142. ;;;
  143. (defconstant undefined-funny-funs
  144.   '(%special-bind %special-unbind %more-arg-context %unknown-values %catch
  145.     %unwind-protect %catch-breakup %unwind-protect-breakup %lexical-exit-breakup
  146.     %continue-unwind %nlx-entry))
  147.  
  148. ;;; Some kinds of functions are only passed as arguments to funny functions,
  149. ;;; and are never actually evaluated at run time.
  150. ;;;
  151. (defconstant non-closed-function-kinds '(:cleanup :escape))
  152.  
  153. ;;; ANNOTATE-COMPONENT-FOR-EVAL -- Internal.
  154. ;;;
  155. ;;; This annotates continuations, lambda-vars, and lambdas.  For each
  156. ;;; continuation, we cache how its destination uses its value.  This only buys
  157. ;;; efficiency when the code executes more than once, but the overhead of this
  158. ;;; part of the prepass for code executed only once should be negligible.
  159. ;;;
  160. ;;; As a special case to aid interpreting local function calls, we sometimes
  161. ;;; note the continuation as :unused.  This occurs when there is a local call,
  162. ;;; and there is no actual function object to call; we mark the continuation as
  163. ;;; :unused since there is nothing to push on the interpreter's stack.
  164. ;;; Normally we would see a reference to a function that we would push on the
  165. ;;; stack to later pop and apply to the arguments on the stack.  To determine
  166. ;;; when we have a local call with no real function object, we look at the node
  167. ;;; to see if it is a reference with a destination that is a :local combination
  168. ;;; whose function is the reference node's continuation.
  169. ;;;
  170. ;;; After checking for virtual local calls, we check for funny functions the
  171. ;;; compiler refers to for calling to note certain operations.  These functions
  172. ;;; are undefined, and if the interpreter tried to reference the function cells
  173. ;;; of these symbols, it would get an error.  We mark the continuations
  174. ;;; delivering the values of these references as :unused, so the reference
  175. ;;; never takes place.
  176. ;;;
  177. ;;; For each lambda-var, including a lambda's vars and its let's vars, we note
  178. ;;; the stack offset used to access and store that variable.  Then we note the
  179. ;;; lambda with the total number of variables, so we know how big its stack
  180. ;;; frame is.  Also in the lambda's info is the number of its arguments that it
  181. ;;; actually references; the interpreter never pushes or pops an unreferenced
  182. ;;; argument, so we can't just use LENGTH on LAMBDA-VARS to know how many args
  183. ;;; the caller passed.
  184. ;;;
  185. ;;; For each entry node in a lambda, we associate in the lambda-eval-info the
  186. ;;; entry node with a stack offset.  Evaluation code stores the frame pointer
  187. ;;; in this slot upon processing the entry node to aid stack cleanup and
  188. ;;; correct frame manipulation when processing exit nodes.
  189. ;;;
  190. (defun annotate-component-for-eval (component)
  191.   (do-blocks (b component)
  192.     (do-nodes (node cont b)
  193.       (let* ((dest (continuation-dest cont))
  194.          (refp (typep node 'ref))
  195.          (leaf (if refp (ref-leaf node))))
  196.     (setf (continuation-info cont)
  197.           (cond ((and refp dest (typep dest 'basic-combination)
  198.               (eq (basic-combination-kind dest) :local)
  199.               (eq (basic-combination-fun dest) cont))
  200.              :unused)
  201.             ((and leaf (typep leaf 'global-var)
  202.               (eq (global-var-kind leaf) :global-function)
  203.               (member (c::global-var-name leaf) undefined-funny-funs
  204.                   :test #'eq))
  205.              :unused)
  206.             ((and leaf (typep leaf 'clambda)
  207.               (member (functional-kind leaf)
  208.                   non-closed-function-kinds))
  209.              (assert (not (eq (functional-kind leaf) :escape)))
  210.              :unused)
  211.             (t
  212.              (typecase dest
  213.                ;; Change locations in eval.lisp that think :return could
  214.                ;; occur.
  215.                ((or mv-combination creturn exit) :multiple)
  216.                (null :unused)
  217.                (t :single))))))))
  218.   (dolist (lambda (component-lambdas component))
  219.     (let ((locals-count 0)
  220.       (args-passed-count 0))
  221.       (dolist (var (lambda-vars lambda))
  222.     (setf (leaf-info var) locals-count)
  223.     (incf locals-count)
  224.     (when (leaf-refs var) (incf args-passed-count)))
  225.       (dolist (let (lambda-lets lambda))
  226.     (dolist (var (lambda-vars let))
  227.       (setf (leaf-info var) locals-count)
  228.       (incf locals-count)))
  229.       (let ((entries nil))
  230.     (dolist (e (lambda-entries lambda))
  231.       (ecase (process-entry-node-p e)
  232.         (:blow-it-off)
  233.         (:local-lexical-exit
  234.          (push (cons e (make-entry-node-info locals-count nil))
  235.            entries)
  236.          (incf locals-count))
  237.         (:non-local-lexical-exit
  238.          (push (cons e
  239.              (make-entry-node-info locals-count (incf locals-count)))
  240.            entries)
  241.          (incf locals-count))))
  242.     (setf (lambda-info lambda)
  243.           (make-lambda-eval-info locals-count args-passed-count
  244.                      entries))))))
  245.  
  246. ;;; PROCESS-ENTRY-NODE-P -- Internal.
  247. ;;; 
  248. (defun process-entry-node-p (entry)
  249.   (let ((entry-cleanup (entry-cleanup entry)))
  250.     (dolist (nlx (environment-nlx-info (node-environment entry))
  251.          :local-lexical-exit)
  252.       (let ((cleanup (nlx-info-cleanup nlx)))
  253.     (when (eq entry-cleanup cleanup)
  254.       (ecase (cleanup-kind cleanup)
  255.         ((:block :tagbody)
  256.          (return :non-local-lexical-exit))
  257.         ((:catch :unwind-protect)
  258.          (return :blow-it-off))))))))
  259.  
  260.  
  261. ;;; Sometime consider annotations to exclude processign of exit nodes when
  262. ;;; we want to do a tail-p thing.
  263. ;;;
  264.  
  265.  
  266. ;;;; Defining funny functions for interpreter.
  267.  
  268. #|
  269. %listify-rest-args %more-arg %verify-argument-count %argument-count-error
  270. %odd-keyword-arguments-error %unknown-keyword-argument-error
  271. |#
  272.  
  273. (defun %verify-argument-count (supplied-args defined-args)
  274.   (unless (= supplied-args defined-args)
  275.     (error "Wrong argument count, wanted ~D and got ~D."
  276.        defined-args supplied-args)))
  277.  
  278. ;;; Use (SETF SYMBOL-FUNCTION) insetad of DEFUN so that the compiler
  279. ;;; doesn't try to compile the hidden %THROW MV-CALL in the throw below as
  280. ;;; a local recursive call.
  281. ;;;
  282. (setf (symbol-function '%throw)
  283.       #'(lambda (tag &rest args)
  284.       (throw tag (values-list args))))
  285.  
  286. (defun %more-arg (args index)
  287.   (nth index args))
  288.  
  289. (defun %listify-rest-args (ptr count)
  290.   (declare (ignore count))
  291.   ptr)
  292.  
  293. (defun %argument-count-error (args-passed-count)
  294.   (error "Wrong number of arguments passed -- ~S." args-passed-count))
  295.  
  296. (defun %odd-keyword-arguments-error ()
  297.   (error "Function called with odd number of keyword arguments."))
  298.  
  299. (defun %unknown-keyword-argument-error (keyword)
  300.   (error "Unknown keyword argument -- ~S." keyword))
  301.  
  302. (defun %progv (vars vals fun)
  303.   (progv vars vals
  304.     (funcall fun)))
  305.  
  306. (defun %cleanup-point ())
  307.  
  308. (defun value-cell-ref (x) (value-cell-ref x))
  309.