0.pre7.86.flaky7.3:
[sbcl.git] / src / compiler / physenvanal.lisp
index 8860c6a..4afe914 100644 (file)
   (setf (component-new-funs component) ())
   (dolist (fun (component-lambdas component))
     (reinit-lambda-physenv fun))
-  (dolist (fun (component-lambdas component))
-    (compute-closure fun)
-    (dolist (let (lambda-lets fun))
-      (compute-closure let)))
+  (mapc #'compute-closure (component-lambdas component))
 
   (find-non-local-exits component)
   (find-cleanup-points component)
   (let ((found-it nil))
     (dolist (lambda (component-lambdas component))
       (when (compute-closure lambda)
-       (setq found-it t))
-      (dolist (let (lambda-lets lambda))
-       (when (compute-closure let)
-         (setq found-it t))))
+       (setq found-it t)))
     found-it))
 
 ;;; This is like old CMU CL PRE-ENVIRONMENT-ANALYZE-TOPLEVEL, except
 ;;;     post-pass will use the existing structure, rather than
 ;;;     allocating a new one. We return true if we discover any
 ;;;     possible closure vars.
-;;; But that doesn't seem to explain why it's important. I do observe
-;;; that when it's not done, compiler assertions occasionally fail. My
-;;; tentative hypothesis is that other environment analysis expects to
+;;; But that doesn't seem to explain either why it's important to do
+;;; this for top level lambdas, or why it's important to do it only
+;;; for top level lambdas instead of just doing it indiscriminately
+;;; for all lambdas. I do observe that when it's not done, compiler
+;;; assertions occasionally fail. My tentative hypothesis for why it's
+;;; important to do it is that other environment analysis expects to
 ;;; bottom out on the outermost enclosing thing, and (insert
 ;;; mysterious reason here) it's important to set up bottomed-out-here
-;;; environments before anything else. -- WHN 2001-09-30
+;;; environments before anything else. I haven't been able to guess
+;;; why it's important to do it selectively instead of
+;;; indiscriminately. -- WHN 2001-11-10
 (defun preallocate-physenvs-for-toplevelish-lambdas (component)
-  (/show "entering PREALLOCATE-PHYSENVS-FOR-TOPLEVELISH-LAMDBAS" component)
   (dolist (clambda (component-lambdas component))
-    (/show clambda (lambda-vars clambda) (lambda-toplevelish-p clambda))
     (when (lambda-toplevelish-p clambda)
       (compute-closure clambda)))
-  (/show "leaving PREALLOCATE-PHYSENVS-FOR-TOPLEVELISH-LAMDBAS" component)
   (values))
 
-;;; If CLAMBDA has a PHYSENV , return it, otherwise assign an empty one.
+;;; If CLAMBDA has a PHYSENV, return it, otherwise assign an empty one
+;;; and return that.
 (defun get-lambda-physenv (clambda)
   (declare (type clambda clambda))
   (let ((homefun (lambda-home clambda)))
     (or (lambda-physenv homefun)
-       (let ((res (make-physenv :function homefun)))
+       (let ((res (make-physenv :lambda homefun)))
          (setf (lambda-physenv homefun) res)
+         ;; All the LETLAMBDAs belong to HOMEFUN, and share the same
+         ;; PHYSENV. Thus, (1) since HOMEFUN's PHYSENV was NIL,
+         ;; theirs should be NIL too, and (2) since we're modifying
+         ;; HOMEFUN's PHYSENV, we should modify theirs, too.
          (dolist (letlambda (lambda-lets homefun))
-           ;; This assertion is to make explicit an
-           ;; apparently-otherwise-undocumented property of existing
-           ;; code: We never overwrite an old LAMBDA-PHYSENV.
-           ;; -- WHN 2001-09-30
-           (aver (null (lambda-physenv letlambda)))
-           ;; I *think* this is true regardless of LAMBDA-KIND.
-           ;; -- WHN 2001-09-30
            (aver (eql (lambda-home letlambda) homefun))
+           (aver (null (lambda-physenv letlambda)))
            (setf (lambda-physenv letlambda) res))
          res))))
 
   (declare (type node node))
   (get-lambda-physenv (node-home-lambda node)))
 
-;;; Find any variables in FUN with references outside of the home
-;;; environment and close over them. If a closed over variable is set,
-;;; then we set the INDIRECT flag so that we will know the closed over
-;;; value is really a pointer to the value cell. We also warn about
-;;; unreferenced variables here, just because it's a convenient place
-;;; to do it. We return true if we close over anything.
-(defun compute-closure (fun)
-  (declare (type clambda fun))
-  (let ((env (get-lambda-physenv fun))
-       (did-something nil))
-    (note-unreferenced-vars fun)
-    (dolist (var (lambda-vars fun))
-      (dolist (ref (leaf-refs var))
-       (let ((ref-env (get-node-physenv ref)))
-         (unless (eq ref-env env)
-           (when (lambda-var-sets var)
-             (setf (lambda-var-indirect var) t))
-           (setq did-something t)
-           (close-over var ref-env env))))
-      (dolist (set (basic-var-sets var))
-       (let ((set-env (get-node-physenv set)))
-         (unless (eq set-env env)
-           (setq did-something t)
-           (setf (lambda-var-indirect var) t)
-           (close-over var set-env env)))))
-    did-something))
+;;; Find any variables in CLAMBDA -- either directly in LAMBDA-VARS or
+;;; in the LAMBDA-VARS of elements of LAMBDA-LETS -- with references
+;;; outside of the home environment and close over them. If a
+;;; closed-over variable is set, then we set the INDIRECT flag so that
+;;; we will know the closed over value is really a pointer to the
+;;; value cell. We also warn about unreferenced variables here, just
+;;; because it's a convenient place to do it. We return true if we
+;;; close over anything.
+(defun compute-closure (clambda)
+  (declare (type clambda clambda))
+  (flet (;; This is the old CMU CL COMPUTE-CLOSURE, which only works
+        ;; on LAMBDA-VARS directly, not on the LAMBDA-VARS of
+        ;; LAMBDA-LETS. It seems never to be valid to use this
+        ;; operation alone, so in SBCL, it's private, and the public
+        ;; interface always runs over all the variables, both the
+        ;; LAMBDA-VARS of CLAMBDA itself and the LAMBDA-VARS of
+        ;; CLAMBDA's LAMBDA-LETS.
+        ;;
+        ;; Note that we don't need to make a distinction between the
+        ;; outer CLAMBDA argument and the inner one, or refer to the
+        ;; outer CLAMBDA argument at all, because the LET-conversion
+        ;; process carefully modifies all the necessary CLAMBDA slots
+        ;; (e.g. LAMBDA-PHYSENV) of a LET-converted CLAMBDA to refer
+        ;; to the new home.
+        (%compute-closure (clambda)
+          (let ((physenv (get-lambda-physenv clambda))
+                (did-something nil))
+            (note-unreferenced-vars clambda)
+            (dolist (var (lambda-vars clambda))
+              (dolist (ref (leaf-refs var))
+                (let ((ref-physenv (get-node-physenv ref)))
+                  (unless (eq ref-physenv physenv)
+                    (when (lambda-var-sets var)
+                      (setf (lambda-var-indirect var) t))
+                    (setq did-something t)
+                    (close-over var ref-physenv physenv))))
+              (dolist (set (basic-var-sets var))
+                (let ((set-physenv (get-node-physenv set)))
+                  (unless (eq set-physenv physenv)
+                    (setq did-something t)
+                    (setf (lambda-var-indirect var) t)
+                    (close-over var set-physenv physenv)))))
+            did-something)))
+    (let ((did-something nil))
+      (when (%compute-closure clambda)
+       (setf did-something t))
+      (dolist (lambda-let (lambda-lets clambda))
+       ;; There's no need to recurse through full COMPUTE-CLOSURE
+       ;; here, since LETS only go one layer deep.
+       (aver (null (lambda-lets lambda-let)))
+       (when (%compute-closure lambda-let)
+         (setf did-something t)))
+      did-something)))
 
-;;; Make sure that THING is closed over in REF-ENV and in all
-;;; environments for the functions that reference REF-ENV's function
-;;; (not just calls.) HOME-ENV is THING's home environment. When we
+;;; Make sure that THING is closed over in REF-PHYSENV and in all
+;;; PHYSENVs for the functions that reference REF-PHYSENV's function
+;;; (not just calls). HOME-PHYSENV is THING's home environment. When we
 ;;; reach the home environment, we stop propagating the closure.
-(defun close-over (thing ref-env home-env)
-  (declare (type physenv ref-env home-env))
-  (cond ((eq ref-env home-env))
-       ((member thing (physenv-closure ref-env)))
+(defun close-over (thing ref-physenv home-physenv)
+  (declare (type physenv ref-physenv home-physenv))
+  (cond ((eq ref-physenv home-physenv))
+       ((member thing (physenv-closure ref-physenv)))
        (t
-        (push thing (physenv-closure ref-env))
-        (dolist (call (leaf-refs (physenv-function ref-env)))
-          (close-over thing (get-node-physenv call) home-env))))
+        (push thing (physenv-closure ref-physenv))
+        (dolist (call (leaf-refs (physenv-lambda ref-physenv)))
+          (close-over thing (get-node-physenv call) home-physenv))))
   (values))
 \f
 ;;;; non-local exit