0.7.3.2:
[sbcl.git] / src / compiler / main.lisp
index d17c7dc..c44d601 100644 (file)
 (in-package "SB!C")
 
 ;;; FIXME: Doesn't this belong somewhere else, like early-c.lisp?
-(declaim (special *constants* *free-variables* *component-being-compiled*
+(declaim (special *constants* *free-vars* *component-being-compiled*
                  *code-vector* *next-location* *result-fixups*
-                 *free-functions* *source-paths*
-                 *seen-blocks* *seen-functions* *list-conflicts-table*
+                 *free-funs* *source-paths*
+                 *seen-blocks* *seen-funs* *list-conflicts-table*
                  *continuation-number* *continuation-numbers*
                  *number-continuations* *tn-id* *tn-ids* *id-tns*
                  *label-ids* *label-id* *id-labels*
 ;;; :BLOCK-COMPILE and :ENTRY-POINTS arguments that COMPILE-FILE was
 ;;; called with.
 ;;;
-;;; *BLOCK-COMPILE-ARGUMENT* holds the original value of the
-;;; :BLOCK-COMPILE argument, which overrides any internal
-;;; declarations.
+;;; *BLOCK-COMPILE-ARG* holds the original value of the :BLOCK-COMPILE
+;;; argument, which overrides any internal declarations.
 (defvar *block-compile*)
-(defvar *block-compile-argument*)
-(declaim (type (member nil t :specified)
-              *block-compile* *block-compile-argument*))
+(defvar *block-compile-arg*)
+(declaim (type (member nil t :specified) *block-compile* *block-compile-arg*))
 (defvar *entry-points*)
 (declaim (list *entry-points*))
 
                   (warning #'compiler-warning-handler))
 
       (let ((undefs (sort *undefined-warnings* #'string<
-                         :key #'(lambda (x)
-                                  (let ((x (undefined-warning-name x)))
-                                    (if (symbolp x)
-                                        (symbol-name x)
-                                        (prin1-to-string x)))))))
+                         :key (lambda (x)
+                                (let ((x (undefined-warning-name x)))
+                                  (if (symbolp x)
+                                      (symbol-name x)
+                                      (prin1-to-string x)))))))
        (dolist (undef undefs)
          (let ((name (undefined-warning-name undef))
                (kind (undefined-warning-kind undef))
                (warnings (undefined-warning-warnings undef))
                (undefined-warning-count (undefined-warning-count undef)))
            (dolist (*compiler-error-context* warnings)
-             (compiler-style-warning "undefined ~(~A~): ~S" kind name))
+             (compiler-style-warn "undefined ~(~A~): ~S" kind name))
            (let ((warn-count (length warnings)))
              (when (and warnings (> undefined-warning-count warn-count))
                (let ((more (- undefined-warning-count warn-count)))
-                 (compiler-style-warning
-                  "~D more use~:P of undefined ~(~A~) ~S"
+                 (compiler-style-warn
+                  "~W more use~:P of undefined ~(~A~) ~S"
                   more kind name))))))
        
        (dolist (kind '(:variable :function :type))
                                 (remove kind undefs :test-not #'eq
                                         :key #'undefined-warning-kind))))
            (when summary
-             (compiler-style-warning
+             (compiler-style-warn
               "~:[This ~(~A~) is~;These ~(~A~)s are~] undefined:~
                ~%  ~{~<~%  ~1:;~S~>~^ ~}"
               (cdr summary) kind summary)))))))
     (format *error-output* "~&")
     (pprint-logical-block (*error-output* nil :per-line-prefix "; ")
       (compiler-mumble "compilation unit ~:[finished~;aborted~]~
-                       ~[~:;~:*~&  caught ~D fatal ERROR condition~:P~]~
-                       ~[~:;~:*~&  caught ~D ERROR condition~:P~]~
-                       ~[~:;~:*~&  caught ~D WARNING condition~:P~]~
-                       ~[~:;~:*~&  caught ~D STYLE-WARNING condition~:P~]~
-                       ~[~:;~:*~&  printed ~D note~:P~]"
+                       ~[~:;~:*~&  caught ~W fatal ERROR condition~:P~]~
+                       ~[~:;~:*~&  caught ~W ERROR condition~:P~]~
+                       ~[~:;~:*~&  caught ~W WARNING condition~:P~]~
+                       ~[~:;~:*~&  caught ~W STYLE-WARNING condition~:P~]~
+                       ~[~:;~:*~&  printed ~W note~:P~]"
                       abort-p
                       *aborted-compilation-unit-count*
                       *compiler-error-count*
 ;;; Do all the IR1 phases for a non-top-level component.
 (defun ir1-phases (component)
   (declare (type component component))
+  (aver-live-component component)
   (let ((*constraint-number* 0)
        (loop-count 1)
         (*delayed-ir1-transforms* nil))
     (declare (special *constraint-number* *delayed-ir1-transforms*))
     (loop
       (ir1-optimize-until-done component)
-      (when (or (component-new-functions component)
-               (component-reanalyze-functions component))
+      (when (or (component-new-functionals component)
+               (component-reanalyze-functionals component))
        (maybe-mumble "locall ")
-       (local-call-analyze component))
+       (locall-analyze-component component))
       (dfo-as-needed component)
       (when *constraint-propagate*
        (maybe-mumble "constraint ")
        (constraint-propagate component))
       (when (retry-delayed-ir1-transforms :constraint)
         (maybe-mumble "Rtran "))
-      ;; Delay the generation of type checks until the type
-      ;; constraints have had time to propagate, else the compiler can
-      ;; confuse itself.
-      (unless (and (or (component-reoptimize component)
-                      (component-reanalyze component)
-                      (component-new-functions component)
-                      (component-reanalyze-functions component))
-                  (< loop-count (- *reoptimize-after-type-check-max* 4)))
-        (maybe-mumble "type ")
-       (generate-type-checks component)
-       (unless (or (component-reoptimize component)
-                   (component-reanalyze component)
-                   (component-new-functions component)
-                   (component-reanalyze-functions component))
-         (return)))
+      (flet ((want-reoptimization-p ()
+              (or (component-reoptimize component)
+                  (component-reanalyze component)
+                  (component-new-functionals component)
+                  (component-reanalyze-functionals component))))
+       (unless (and (want-reoptimization-p)
+                    ;; We delay the generation of type checks until
+                    ;; the type constraints have had time to
+                    ;; propagate, else the compiler can confuse itself.
+                    (< loop-count (- *reoptimize-after-type-check-max* 4)))
+         (maybe-mumble "type ")
+         (generate-type-checks component)
+         (unless (want-reoptimization-p)
+           (return))))
       (when (>= loop-count *reoptimize-after-type-check-max*)
        (maybe-mumble "[reoptimize limit]")
        (event reoptimize-maxed-out)
              (null))))))
 
   ;; We're done, so don't bother keeping anything around.
-  (setf (component-info component) nil)
+  (setf (component-info component) :dead)
 
   (values))
 
       (:toplevel (return))
       (:external
        (unless (every (lambda (ref)
-                       (eq (block-component (node-block ref))
-                           component))
+                       (eq (node-component ref) component))
                      (leaf-refs fun))
         (return))))))
 
 (defun compile-component (component)
+
+  ;; miscellaneous sanity checks
+  ;;
+  ;; FIXME: These are basically pretty wimpy compared to the checks done
+  ;; by the old CHECK-IR1-CONSISTENCY code. It would be really nice to
+  ;; make those internal consistency checks work again and use them.
+  (aver-live-component component)
+  (do-blocks (block component)
+    (aver (eql (block-component block) component)))
+  (dolist (lambda (component-lambdas component))
+    ;; sanity check to prevent weirdness from propagating insidiously as
+    ;; far from its root cause as it did in bug 138: Make sure that
+    ;; thing-to-COMPONENT links are consistent.
+    (aver (eql (lambda-component lambda) component))
+    (aver (eql (node-component (lambda-bind lambda)) component)))
+
   (let* ((*component-being-compiled* component))
     (when sb!xc:*compile-print*
       (compiler-mumble "~&; compiling ~A: " (component-name component)))
 ;;;; global data structures entirely when possible and consing up the
 ;;;; others from scratch instead of clearing and reusing them?
 
-;;; Clear the INFO in constants in the *FREE-VARIABLES*, etc. In
+;;; Clear the INFO in constants in the *FREE-VARS*, etc. In
 ;;; addition to allowing stuff to be reclaimed, this is required for
 ;;; correct assignment of constant offsets, since we need to assign a
 ;;; new offset for each component. We don't clear the FUNCTIONAL-INFO
 ;;; slots, since they are used to keep track of functions across
 ;;; component boundaries.
 (defun clear-constant-info ()
-  (maphash #'(lambda (k v)
-              (declare (ignore k))
-              (setf (leaf-info v) nil))
+  (maphash (lambda (k v)
+            (declare (ignore k))
+            (setf (leaf-info v) nil))
           *constants*)
-  (maphash #'(lambda (k v)
-              (declare (ignore k))
-              (when (constant-p v)
-                (setf (leaf-info v) nil)))
-          *free-variables*)
+  (maphash (lambda (k v)
+            (declare (ignore k))
+            (when (constant-p v)
+              (setf (leaf-info v) nil)))
+          *free-vars*)
   (values))
 
 ;;; Blow away the REFS for all global variables, and let COMPONENT
 (defun clear-ir1-info (component)
   (declare (type component component))
   (labels ((blast (x)
-            (maphash #'(lambda (k v)
-                         (declare (ignore k))
-                         (when (leaf-p v)
-                           (setf (leaf-refs v)
-                                 (delete-if #'here-p (leaf-refs v)))
-                           (when (basic-var-p v)
-                             (setf (basic-var-sets v)
-                                   (delete-if #'here-p (basic-var-sets v))))))
+            (maphash (lambda (k v)
+                       (declare (ignore k))
+                       (when (leaf-p v)
+                         (setf (leaf-refs v)
+                               (delete-if #'here-p (leaf-refs v)))
+                         (when (basic-var-p v)
+                           (setf (basic-var-sets v)
+                                 (delete-if #'here-p (basic-var-sets v))))))
                      x))
           (here-p (x)
-            (eq (block-component (node-block x)) component)))
-    (blast *free-variables*)
-    (blast *free-functions*)
+            (eq (node-component x) component)))
+    (blast *free-vars*)
+    (blast *free-funs*)
     (blast *constants*))
   (values))
 
 (defun clear-stuff (&optional (debug-too t))
 
   ;; Clear global tables.
-  (when (boundp '*free-functions*)
-    (clrhash *free-functions*)
-    (clrhash *free-variables*)
+  (when (boundp '*free-funs*)
+    (clrhash *free-funs*)
+    (clrhash *free-vars*)
     (clrhash *constants*))
 
   ;; Clear debug counters and tables.
   (clrhash *seen-blocks*)
-  (clrhash *seen-functions*)
+  (clrhash *seen-funs*)
   (clrhash *list-conflicts-table*)
 
   (when debug-too
 \f
 ;;;; trace output
 
-;;; Print out some useful info about Component to Stream.
+;;; Print out some useful info about COMPONENT to STREAM.
 (defun describe-component (component *standard-output*)
   (declare (type component component))
   (format t "~|~%;;;; component: ~S~2%" (component-name component))
 ;;;; the error context and for recovering from errors.
 ;;;;
 ;;;; The interface we provide to this stuff is the stream-oid
-;;;; Source-Info structure. The bookkeeping is done as a side-effect
+;;;; SOURCE-INFO structure. The bookkeeping is done as a side effect
 ;;;; of getting the next source form.
 
 ;;; A FILE-INFO structure holds all the source information for a
 
 
 ;;; utilities for extracting COMPONENTs of FUNCTIONALs
-(defun clambda-component (clambda)
-  (block-component (node-block (lambda-bind clambda))))
 (defun functional-components (f)
   (declare (type functional f))
   (etypecase f
-    (clambda (list (clambda-component f)))
+    (clambda (list (lambda-component f)))
     (optional-dispatch (let ((result nil))
                         (labels ((frob (clambda)
-                                   (pushnew (clambda-component clambda)
+                                   (pushnew (lambda-component clambda)
                                             result))
                                  (maybe-frob (maybe-clambda)
                                    (when maybe-clambda
          (component (make-empty-component))
          (*current-component* component))
     (setf (component-name component)
-          (format nil "~S initial component" name))
+         (debug-namify "~S initial component" name))
     (setf (component-kind component) :initial)
-    (let* ((locall-fun (ir1-convert-lambda definition
-                                          :debug-name (debug-namify
-                                                       "top level locall ~S"
-                                                       name)))
-           (fun (ir1-convert-lambda (make-xep-lambda locall-fun)
+    (let* ((locall-fun (ir1-convert-lambda
+                       definition
+                       :debug-name (debug-namify "top level local call ~S"
+                                                 name)))
+           (fun (ir1-convert-lambda (make-xep-lambda-expression locall-fun)
                                    :source-name (or name '.anonymous.)
-                                   :debug-name (or name "top level form"))))
-      (/show "in MAKE-FUNCTIONAL-FROM-TOP-LEVEL-LAMBDA" locall-fun fun component)
-      (setf (functional-entry-function fun) locall-fun
+                                   :debug-name (unless name
+                                                 "top level form"))))
+      (setf (functional-entry-fun fun) locall-fun
             (functional-kind fun) :external
             (functional-has-external-references-p fun) t)
       fun)))
                  ;; nice default for things where we don't have a
                  ;; real source path (as in e.g. inside CL:COMPILE).
                  '(original-source-start 0 0)))
-  (/show "entering %COMPILE" lambda-expression name)
   (unless (or (null name) (legal-fun-name-p name))
     (error "not a legal function name: ~S" name))
   (let* ((*lexenv* (make-lexenv :policy *policy*))
          (fun (make-functional-from-toplevel-lambda lambda-expression
                                                    :name name
                                                    :path path)))
-    (/show fun)
 
     ;; FIXME: The compile-it code from here on is sort of a
     ;; twisted version of the code in COMPILE-TOPLEVEL. It'd be
     ;; the :LOCALL-ONLY option to IR1-FOR-LAMBDA. Then maybe the
     ;; whole FUNCTIONAL-KIND=:TOPLEVEL case could go away..)
 
-    (local-call-analyze-until-done (list fun))
-
+    (locall-analyze-clambdas-until-done (list fun))
+    
     (multiple-value-bind (components-from-dfo top-components hairy-top)
         (find-initial-dfo (list fun))
-      (/show components-from-dfo top-components hairy-top)
 
       (let ((*all-components* (append components-from-dfo top-components)))
-       (mapc #'preallocate-physenvs-for-toplevelish-lambdas
-             (append hairy-top top-components))
+       ;; FIXME: This is more monkey see monkey do based on CMU CL
+       ;; code. If anyone figures out why to only prescan HAIRY-TOP
+       ;; and TOP-COMPONENTS here, instead of *ALL-COMPONENTS* or
+       ;; some other combination of results from FIND-INITIAL-VALUES,
+       ;; it'd be good to explain it.
+       (mapc #'preallocate-physenvs-for-toplevelish-lambdas hairy-top)
+       (mapc #'preallocate-physenvs-for-toplevelish-lambdas top-components)
         (dolist (component-from-dfo components-from-dfo)
-         (/show component-from-dfo (component-lambdas component-from-dfo))
           (compile-component component-from-dfo)
           (replace-toplevel-xeps component-from-dfo)))
 
               (aver found-p)
               result))
         (mapc #'clear-ir1-info components-from-dfo)
-        (clear-stuff)
-       (/show "returning from %COMPILE")))))
+        (clear-stuff)))))
 
 (defun process-toplevel-cold-fset (name lambda-expression path)
   (unless (producing-fasl-file)
 
 ;;; Compile FORM and arrange for it to be called at load-time. Return
 ;;; the dumper handle and our best guess at the type of the object.
-(defun compile-load-time-value
-       (form &optional
-            (name (let ((*print-level* 2) (*print-length* 3))
-                    (format nil "load time value of ~S"
-                            (if (and (listp form)
-                                     (eq (car form) 'make-value-cell))
-                                (second form)
-                                form)))))
-  (let ((lambda (compile-load-time-stuff form name t)))
+(defun compile-load-time-value (form)
+  (let ((lambda (compile-load-time-stuff form t)))
     (values
      (fasl-dump-load-time-value-lambda lambda *compile-object*)
      (let ((type (leaf-type lambda)))
 
 ;;; Compile the FORMS and arrange for them to be called (for effect,
 ;;; not value) at load time.
-(defun compile-make-load-form-init-forms (forms name)
-  (let ((lambda (compile-load-time-stuff `(progn ,@forms) name nil)))
+(defun compile-make-load-form-init-forms (forms)
+  (let ((lambda (compile-load-time-stuff `(progn ,@forms) nil)))
     (fasl-dump-toplevel-lambda-call lambda *compile-object*)))
 
-;;; Does the actual work of COMPILE-LOAD-TIME-VALUE or
-;;; COMPILE-MAKE-LOAD-FORM- INIT-FORMS.
-(defun compile-load-time-stuff (form name for-value)
+;;; Do the actual work of COMPILE-LOAD-TIME-VALUE or
+;;; COMPILE-MAKE-LOAD-FORM-INIT-FORMS.
+(defun compile-load-time-stuff (form for-value)
   (with-ir1-namespace
    (let* ((*lexenv* (make-null-lexenv))
          (lambda (ir1-toplevel form *current-path* for-value)))
 (defun compile-load-time-value-lambda (lambdas)
   (aver (null (cdr lambdas)))
   (let* ((lambda (car lambdas))
-        (component (block-component (node-block (lambda-bind lambda)))))
+        (component (lambda-component lambda)))
     (when (eql (component-kind component) :toplevel)
       (setf (component-name component) (leaf-debug-name lambda))
       (compile-component component)
     (flet ((loser (start)
             (or (position-if (lambda (x)
                                (not (eq (component-kind
-                                         (block-component
-                                          (node-block
-                                           (lambda-bind x))))
+                                         (node-component (lambda-bind x)))
                                         :toplevel)))
                              lambdas
-                             :start start)
+                             ;; this used to read ":start start", but
+                             ;; start can be greater than len, which
+                             ;; is an error according to ANSI - CSR,
+                             ;; 2002-04-25
+                             :start (min start len))
                 len)))
       (do* ((start 0 (1+ loser))
            (loser (loser start) (loser start)))
   (declare (list lambdas))
 
   (maybe-mumble "locall ")
-  (local-call-analyze-until-done lambdas)
+  (locall-analyze-clambdas-until-done lambdas)
 
   (maybe-mumble "IDFO ")
   (multiple-value-bind (components top-components hairy-top)
 ;;; Return (VALUES NIL WARNINGS-P FAILURE-P).
 (defun sub-compile-file (info)
   (declare (type source-info info))
-  (let* ((*block-compile* *block-compile-argument*)
+  (let* ((*block-compile* *block-compile-arg*)
         (*package* (sane-package))
         (*policy* *policy*)
         (*lexenv* (make-null-lexenv))
 
      ;; extensions
      (trace-file nil) 
-     ((:block-compile *block-compile-argument*) nil))
+     ((:block-compile *block-compile-arg*) nil))
 
   #!+sb-doc
   "Compile INPUT-FILE, producing a corresponding fasl file and returning
 ;;; deal with it.
 (defvar *constants-being-created* nil)
 (defvar *constants-created-since-last-init* nil)
-;;; FIXME: Shouldn't these^ variables be bound in LET forms?
+;;; FIXME: Shouldn't these^ variables be unbound outside LET forms?
 (defun emit-make-load-form (constant)
   (aver (fasl-output-p *compile-object*))
   (unless (or (fasl-constant-already-dumped-p constant *compile-object*)
                   (fasl-note-handle-for-constant
                    constant
                    (compile-load-time-value
-                    creation-form
-                    (format nil "creation form for ~A" name))
+                    creation-form)
                    *compile-object*)
                   nil)
               (compiler-error "circular references in creation form for ~S"
                       (loop for (name form) on (cdr info) by #'cddr
                         collect name into names
                         collect form into forms
-                        finally
-                        (compile-make-load-form-init-forms
-                         forms
-                         (format nil "init form~:[~;s~] for ~{~A~^, ~}"
-                                 (cdr forms) names)))
+                        finally (compile-make-load-form-init-forms forms))
                       nil)))
               (when circular-ref
                 (setf (cdr circular-ref)