;;; the continuation has no block, then we make it be in the block
;;; that the node is in. If the continuation heads its block, we end
;;; our block and link it to that block. If the continuation is not
-;;; currently used, then we set the derived-type for the continuation
+;;; currently used, then we set the DERIVED-TYPE for the continuation
;;; to that of the node, so that a little type propagation gets done.
;;;
;;; We also deal with a bit of THE's semantics here: we weaken the
;;; otherwise NIL is returned.
;;;
;;; This function may have arbitrary effects on the global environment
-;;; due to processing of PROCLAIMs and EVAL-WHENs. All syntax error
-;;; checking is done, with erroneous forms being replaced by a proxy
-;;; which signals an error if it is evaluated. Warnings about possibly
-;;; inconsistent or illegal changes to the global environment will
-;;; also be given.
+;;; due to processing of EVAL-WHENs. All syntax error checking is
+;;; done, with erroneous forms being replaced by a proxy which signals
+;;; an error if it is evaluated. Warnings about possibly inconsistent
+;;; or illegal changes to the global environment will also be given.
;;;
;;; We make the initial component and convert the form in a PROGN (and
;;; an optional NIL tacked on the end.) We then return the lambda. We
;;; Convert a reference to a symbolic constant or variable. If the
;;; symbol is entered in the LEXENV-VARIABLES we use that definition,
;;; otherwise we find the current global definition. This is also
-;;; where we pick off symbol macro and Alien variable references.
+;;; where we pick off symbol macro and alien variable references.
(defun ir1-convert-variable (start cont name)
(declare (type continuation start cont) (symbol name))
(let ((var (or (lexenv-find name variables) (find-free-variable name))))
key))))
key))
-;;; Parse a lambda-list into a list of VAR structures, stripping off
-;;; any aux bindings. Each arg name is checked for legality, and
+;;; Parse a lambda list into a list of VAR structures, stripping off
+;;; any &AUX bindings. Each arg name is checked for legality, and
;;; duplicate names are checked for. If an arg is globally special,
;;; the var is marked as :SPECIAL instead of :LEXICAL. &KEY,
;;; &OPTIONAL and &REST args are annotated with an ARG-INFO structure
;;; 4. a list of the &AUX variables; and
;;; 5. a list of the &AUX values.
(declaim (ftype (function (list) (values list boolean boolean list list))
- find-lambda-vars))
-(defun find-lambda-vars (list)
+ make-lambda-vars))
+(defun make-lambda-vars (list)
(multiple-value-bind (required optional restp rest keyp keys allowp aux
morep more-context more-count)
(parse-lambda-list list)
form))
(unless (and (consp (cdr form)) (listp (cadr form)))
(compiler-error
- "The lambda expression has a missing or non-list lambda-list:~% ~S"
+ "The lambda expression has a missing or non-list lambda list:~% ~S"
form))
(multiple-value-bind (vars keyp allow-other-keys aux-vars aux-vals)
- (find-lambda-vars (cadr form))
+ (make-lambda-vars (cadr form))
(multiple-value-bind (forms decls) (sb!sys:parse-body (cddr form))
- (let* ((cont (make-continuation))
+ (let* ((result-cont (make-continuation))
(*lexenv* (process-decls decls
(append aux-vars vars)
- nil cont))
+ nil result-cont))
(res (if (or (find-if #'lambda-var-arg-info vars) keyp)
(ir1-convert-hairy-lambda forms vars keyp
allow-other-keys
- aux-vars aux-vals cont
+ aux-vars aux-vals result-cont
:source-name source-name
:debug-name debug-name)
(ir1-convert-lambda-body forms vars
:aux-vars aux-vars
:aux-vals aux-vals
- :result cont
+ :result result-cont
:source-name source-name
:debug-name debug-name))))
(setf (functional-inline-expansion res) form)
(setf (component-new-funs component) ())
(dolist (fun (component-lambdas component))
(reinit-lambda-physenv fun))
- (mapc #'compute-closure (component-lambdas component))
+ (mapc #'add-lambda-vars-and-let-vars-to-closures
+ (component-lambdas component))
(find-non-local-exits component)
(find-cleanup-points component)
(declare (type component component))
(let ((found-it nil))
(dolist (lambda (component-lambdas component))
- (when (compute-closure lambda)
+ (when (add-lambda-vars-and-let-vars-to-closures lambda)
(setq found-it t)))
found-it))
(defun preallocate-physenvs-for-toplevelish-lambdas (component)
(dolist (clambda (component-lambdas component))
(when (lambda-toplevelish-p clambda)
- (compute-closure clambda)))
+ (add-lambda-vars-and-let-vars-to-closures clambda)))
(values))
;;; If CLAMBDA has a PHYSENV, return it, otherwise assign an empty one
(declare (type node node))
(get-lambda-physenv (node-home-lambda node)))
+;;; private guts of ADD-LAMBDA-VARS-AND-LET-VARS-TO-CLOSURES
+;;;
+;;; 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,
+;;; ADD-LAMBDA-VARS-AND-LET-VARS-TO-CLOSURES, always runs over all the
+;;; variables, not only the LAMBDA-VARS of CLAMBDA itself but also
+;;; the LAMBDA-VARS of CLAMBDA's LAMBDA-LETS.
+(defun %add-lambda-vars-to-closures (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))
+
;;; 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
;;; 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)
+(defun add-lambda-vars-and-let-vars-to-closures (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)))
+ (let ((did-something nil))
+ (when (%add-lambda-vars-to-closures 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 (%add-lambda-vars-to-closures lambda-let)
+ (setf did-something t)))
+ did-something))
;;; Make sure that THING is closed over in REF-PHYSENV and in all
;;; PHYSENVs for the functions that reference REF-PHYSENV's function
;;; reach the home environment, we stop propagating the closure.
(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-physenv))
- (dolist (call (leaf-refs (physenv-lambda ref-physenv)))
- (close-over thing (get-node-physenv call) home-physenv))))
+ (let ((flooded-physenvs nil))
+ (named-let flood ((flooded-physenv ref-physenv))
+ (unless (or (eql flooded-physenv home-physenv)
+ (member flooded-physenv flooded-physenvs))
+ (push flooded-physenv flooded-physenvs)
+ (pushnew thing (physenv-closure flooded-physenv))
+ (dolist (ref (leaf-refs (physenv-lambda flooded-physenv)))
+ (flood (get-node-physenv ref))))))
(values))
\f
;;;; non-local exit