X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Fmain.lisp;h=6a75cf05b12f347aa40899d0d883974faa96de74;hb=5d04a95274c9ddaebbcd6ddffc5d646e2c25598c;hp=f99f24eda888d7a066bc80ec280ecf55e7df7620;hpb=7f2a87e987b70891684cafe8c71e057b9cdc6092;p=sbcl.git diff --git a/src/compiler/main.lisp b/src/compiler/main.lisp index f99f24e..6a75cf0 100644 --- a/src/compiler/main.lisp +++ b/src/compiler/main.lisp @@ -720,10 +720,15 @@ ;;; A FILE-INFO structure holds all the source information for a ;;; given file. -(def!struct (file-info (:copier nil)) +(def!struct (file-info + (:copier nil) + #-no-ansi-print-object + (:print-object (lambda (s stream) + (print-unreadable-object (s stream :type t) + (princ (file-info-name s) stream))))) ;; If a file, the truename of the corresponding source file. If from ;; a Lisp form, :LISP. If from a stream, :STREAM. - (name (missing-arg) :type (or pathname (member :lisp :stream))) + (name (missing-arg) :type (or pathname (eql :lisp))) ;; the external format that we'll call OPEN with, if NAME is a file. (external-format nil) ;; the defaulted, but not necessarily absolute file name (i.e. prior @@ -756,29 +761,39 @@ (file-info nil :type (or file-info null)) ;; the stream that we are using to read the FILE-INFO, or NIL if ;; no stream has been opened yet - (stream nil :type (or stream null))) + (stream nil :type (or stream null)) + ;; if the current compilation is recursive (e.g., due to EVAL-WHEN + ;; processing at compile-time), the invoking compilation's + ;; source-info. + (parent nil :type (or source-info null))) ;;; Given a pathname, return a SOURCE-INFO structure. (defun make-file-source-info (file external-format) - (let ((file-info (make-file-info :name (truename file) - :untruename (merge-pathnames file) - :external-format external-format - :write-date (file-write-date file)))) - - (make-source-info :file-info file-info))) + (make-source-info + :file-info (make-file-info :name (truename file) + :untruename (merge-pathnames file) + :external-format external-format + :write-date (file-write-date file)))) ;;; Return a SOURCE-INFO to describe the incremental compilation of FORM. -(defun make-lisp-source-info (form) - (make-source-info :start-time (get-universal-time) - :file-info (make-file-info :name :lisp - :forms (vector form) - :positions '#(0)))) - -;;; Return a SOURCE-INFO which will read from STREAM. -(defun make-stream-source-info (stream) - (let ((file-info (make-file-info :name :stream))) - (make-source-info :file-info file-info - :stream stream))) +(defun make-lisp-source-info (form &key parent) + (make-source-info + :file-info (make-file-info :name :lisp + :forms (vector form) + :positions '#(0)) + :parent parent)) + +;;; Walk up the SOURCE-INFO list until we either reach a SOURCE-INFO +;;; with no parent (e.g., from a REPL evaluation) or until we reach a +;;; SOURCE-INFO whose FILE-INFO denotes a file. +(defun get-toplevelish-file-info (&optional (source-info *source-info*)) + (if source-info + (do* ((sinfo source-info (source-info-parent sinfo)) + (finfo (source-info-file-info sinfo) + (source-info-file-info sinfo))) + ((or (not (source-info-p (source-info-parent sinfo))) + (pathnamep (file-info-name finfo))) + finfo)))) ;;; Return a form read from STREAM; or for EOF use the trick, ;;; popularized by Kent Pitman, of returning STREAM itself. If an @@ -835,24 +850,37 @@ (setf (source-info-stream info) nil) (values)) +;;; Loop over FORMS retrieved from INFO. Used by COMPILE-FILE and +;;; LOAD when loading from a FILE-STREAM associated with a source +;;; file. +(defmacro do-forms-from-info (((form &rest keys) info) + &body body) + (aver (symbolp form)) + (once-only ((info info)) + `(let ((*source-info* ,info)) + (loop (destructuring-bind (,form &key ,@keys &allow-other-keys) + (let* ((file-info (source-info-file-info ,info)) + (stream (get-source-stream ,info)) + (pos (file-position stream)) + (form (read-for-compile-file stream pos))) + (if (eq form stream) ; i.e., if EOF + (return) + (let* ((forms (file-info-forms file-info)) + (current-idx (+ (fill-pointer forms) + (file-info-source-root + file-info)))) + (vector-push-extend form forms) + (vector-push-extend pos (file-info-positions + file-info)) + (list form :current-index current-idx)))) + ,@body))))) + ;;; Read and compile the source file. (defun sub-sub-compile-file (info) - (let* ((file-info (source-info-file-info info)) - (stream (get-source-stream info))) - (loop - (let* ((pos (file-position stream)) - (form (read-for-compile-file stream pos))) - (if (eq form stream) ; i.e., if EOF - (return) - (let* ((forms (file-info-forms file-info)) - (current-idx (+ (fill-pointer forms) - (file-info-source-root file-info)))) - (vector-push-extend form forms) - (vector-push-extend pos (file-info-positions file-info)) - (find-source-paths form current-idx) - (process-toplevel-form form - `(original-source-start 0 ,current-idx) - nil))))))) + (do-forms-from-info ((form current-index) info) + (find-source-paths form current-index) + (process-toplevel-form + form `(original-source-start 0 ,current-index) nil))) ;;; Return the INDEX'th source form read from INFO and the position ;;; where it was read. @@ -870,19 +898,21 @@ ;;; *TOPLEVEL-LAMBDAS* instead. (defun convert-and-maybe-compile (form path) (declare (list path)) - (if (fopcompilable-p form) - (let ((*fopcompile-label-counter* 0)) - (fopcompile form path nil)) - (let* ((*top-level-form-noted* (note-top-level-form form t)) - (*lexenv* (make-lexenv - :policy *policy* - :handled-conditions *handled-conditions* - :disabled-package-locks *disabled-package-locks*)) - (tll (ir1-toplevel form path nil))) - (if (eq *block-compile* t) - (push tll *toplevel-lambdas*) - (compile-toplevel (list tll) nil)) - nil))) + (let ((*top-level-form-noted* (note-top-level-form form t))) + ;; Don't bother to compile simple objects that just sit there. + (when (and form (or (symbolp form) (consp form))) + (if (fopcompilable-p form) + (let ((*fopcompile-label-counter* 0)) + (fopcompile form path nil)) + (let ((*lexenv* (make-lexenv + :policy *policy* + :handled-conditions *handled-conditions* + :disabled-package-locks *disabled-package-locks*)) + (tll (ir1-toplevel form path nil))) + (if (eq *block-compile* t) + (push tll *toplevel-lambdas*) + (compile-toplevel (list tll) nil)) + nil))))) ;;; Macroexpand FORM in the current environment with an error handler. ;;; We only expand one level, so that we retain all the intervening @@ -971,7 +1001,7 @@ (maybe-frob (optional-dispatch-main-entry f))) result)))) -(defun make-functional-from-toplevel-lambda (definition +(defun make-functional-from-toplevel-lambda (lambda-expression &key name (path @@ -981,17 +1011,15 @@ (missing-arg))) (let* ((*current-path* path) (component (make-empty-component)) - (*current-component* component)) - (setf (component-name component) - (debug-name 'initial-component name)) - (setf (component-kind component) :initial) + (*current-component* component) + (debug-name-tail (or name (name-lambdalike lambda-expression))) + (source-name (or name '.anonymous.))) + (setf (component-name component) (debug-name 'initial-component debug-name-tail) + (component-kind component) :initial) (let* ((locall-fun (let ((*allow-instrumenting* t)) (funcall #'ir1-convert-lambdalike - definition - :source-name name))) - (debug-name (debug-name 'tl-xep - (or name - (functional-%source-name locall-fun)))) + lambda-expression + :source-name source-name))) ;; Convert the XEP using the policy of the real ;; function. Otherwise the wrong policy will be used for ;; deciding whether to type-check the parameters of the @@ -1000,8 +1028,8 @@ (*lexenv* (make-lexenv :policy (lexenv-policy (functional-lexenv locall-fun)))) (fun (ir1-convert-lambda (make-xep-lambda-expression locall-fun) - :source-name (or name '.anonymous.) - :debug-name debug-name))) + :source-name source-name + :debug-name (debug-name 'tl-xep debug-name-tail)))) (when name (assert-global-function-definition-type name locall-fun)) (setf (functional-entry-fun fun) locall-fun @@ -1150,7 +1178,7 @@ (declare (list path)) (catch 'process-toplevel-form-error-abort - (let* ((path (or (gethash form *source-paths*) (cons form path))) + (let* ((path (or (get-source-path form) (cons form path))) (*compiler-error-bailout* (lambda (&optional condition) (convert-and-maybe-compile @@ -1482,7 +1510,7 @@ (invoke-restart it)))))))) ;;; Read all forms from INFO and compile them, with output to OBJECT. -;;; Return (VALUES NIL WARNINGS-P FAILURE-P). +;;; Return (VALUES ABORT-P WARNINGS-P FAILURE-P). (defun sub-compile-file (info) (declare (type source-info info)) (let ((*package* (sane-package)) @@ -1496,14 +1524,13 @@ (*disabled-package-locks* *disabled-package-locks*) (*lexenv* (make-null-lexenv)) (*block-compile* *block-compile-arg*) - (*source-info* info) (*toplevel-lambdas* ()) (*fun-names-in-this-file* ()) (*allow-instrumenting* nil) (*compiler-error-bailout* (lambda () (compiler-mumble "~2&; fatal error, aborting compilation~%") - (return-from sub-compile-file (values nil t t)))) + (return-from sub-compile-file (values t t t)))) (*current-path* nil) (*last-source-context* nil) (*last-original-source* nil) @@ -1557,7 +1584,7 @@ "~@" condition)) (finish-output *error-output*) - (values nil t t))))) + (values t t t))))) ;;; Return a pathname for the named file. The file must exist. (defun verify-source-file (pathname-designator) @@ -1666,7 +1693,7 @@ SPEED and COMPILATION-SPEED optimization values, and the |# (let* ((fasl-output nil) (output-file-name nil) - (compile-won nil) + (abort-p t) (warnings-p nil) (failure-p t) ; T in case error keeps this from being set later (input-pathname (verify-source-file input-file)) @@ -1697,31 +1724,34 @@ SPEED and COMPILATION-SPEED optimization values, and the (when sb!xc:*compile-verbose* (print-compile-start-note source-info)) - (let ((*compile-object* fasl-output) - dummy) - (multiple-value-setq (dummy warnings-p failure-p) - (sub-compile-file source-info))) - (setq compile-won t)) + + (let ((*compile-object* fasl-output)) + (setf (values abort-p warnings-p failure-p) + (sub-compile-file source-info)))) (close-source-info source-info) (when fasl-output - (close-fasl-output fasl-output (not compile-won)) + (close-fasl-output fasl-output abort-p) (setq output-file-name (pathname (fasl-output-stream fasl-output))) - (when (and compile-won sb!xc:*compile-verbose*) + (when (and (not abort-p) sb!xc:*compile-verbose*) (compiler-mumble "~2&; ~A written~%" (namestring output-file-name)))) (when sb!xc:*compile-verbose* - (print-compile-end-note source-info compile-won)) + (print-compile-end-note source-info (not abort-p))) (when *compiler-trace-output* (close *compiler-trace-output*))) - (values (if output-file - ;; Hack around filesystem race condition... - (or (probe-file output-file-name) output-file-name) - nil) + ;; CLHS says that the first value is NIL if the "file could not + ;; be created". We interpret this to mean "a valid fasl could not + ;; be created" -- which can happen if the compilation is aborted + ;; before the whole file has been processed, due to eg. a reader + ;; error. + (values (when (and (not abort-p) output-file) + ;; Hack around filesystem race condition... + (or (probe-file output-file-name) output-file-name)) warnings-p failure-p))) @@ -1809,7 +1839,7 @@ SPEED and COMPILATION-SPEED optimization values, and the (defvar *constants-being-created* nil) (defvar *constants-created-since-last-init* nil) ;;; FIXME: Shouldn't these^ variables be unbound outside LET forms? -(defun emit-make-load-form (constant) +(defun emit-make-load-form (constant &optional (name nil namep)) (aver (fasl-output-p *compile-object*)) (unless (or (fasl-constant-already-dumped-p constant *compile-object*) ;; KLUDGE: This special hack is because I was too lazy @@ -1825,10 +1855,14 @@ SPEED and COMPILATION-SPEED optimization values, and the (throw constant t)) (throw 'pending-init circular-ref))) (multiple-value-bind (creation-form init-form) - (handler-case - (sb!xc:make-load-form constant (make-null-lexenv)) - (error (condition) - (compiler-error condition))) + (if namep + ;; If the constant is a reference to a named constant, we can + ;; just use SYMBOL-VALUE during LOAD. + (values `(symbol-value ',name) nil) + (handler-case + (sb!xc:make-load-form constant (make-null-lexenv)) + (error (condition) + (compiler-error condition)))) (case creation-form (:sb-just-dump-it-normally (fasl-validate-structure constant *compile-object*)