home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d556 / scheme2c.lha / Scheme2C / Scheme-src.lzh / scsc / closeana.sc < prev    next >
Text File  |  1991-10-11  |  20KB  |  545 lines

  1. ;;; This phase of the Scheme compiler figures out whether closures must be
  2. ;;; stack or heap allocated.  According to Steele's RABBIT paper, a heap
  3. ;;; allocated closure is needed for the following reasons:
  4. ;;;
  5. ;;;    - the Lambda expression is used as an argument to a function.
  6. ;;;
  7. ;;;    - the Lambda expression is bound to a variable which is used as an
  8. ;;;      argument to a function.
  9. ;;;
  10. ;;;    - the Lambda expression is bound to a variable which is used as a 
  11. ;;;      function within a closure.
  12. ;;;
  13.  
  14. ;*              Copyright 1989 Digital Equipment Corporation
  15. ;*                         All Rights Reserved
  16. ;*
  17. ;* Permission to use, copy, and modify this software and its documentation is
  18. ;* hereby granted only under the following terms and conditions.  Both the
  19. ;* above copyright notice and this permission notice must appear in all copies
  20. ;* of the software, derivative works or modified versions, and any portions
  21. ;* thereof, and both notices must appear in supporting documentation.
  22. ;*
  23. ;* Users of this software agree to the terms and conditions set forth herein,
  24. ;* and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
  25. ;* right and license under any changes, enhancements or extensions made to the
  26. ;* core functions of the software, including but not limited to those affording
  27. ;* compatibility with other hardware or software environments, but excluding
  28. ;* applications which incorporate this software.  Users further agree to use
  29. ;* their best efforts to return to Digital any such changes, enhancements or
  30. ;* extensions that they make and inform Digital of noteworthy uses of this
  31. ;* software.  Correspondence should be provided to Digital at:
  32. ;* 
  33. ;*                       Director of Licensing
  34. ;*                       Western Research Laboratory
  35. ;*                       Digital Equipment Corporation
  36. ;*                       100 Hamilton Avenue
  37. ;*                       Palo Alto, California  94301  
  38. ;* 
  39. ;* This software may be distributed (but not offered for sale or transferred
  40. ;* for compensation) to third parties, provided such third parties agree to
  41. ;* abide by the terms and conditions of this notice.  
  42. ;* 
  43. ;* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  44. ;* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
  45. ;* MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
  46. ;* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  47. ;* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  48. ;* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  49. ;* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  50. ;* SOFTWARE.
  51.  
  52. (module closeana)
  53.  
  54. ;;; External and in-line definitions.
  55.  
  56. (include "plist.sch")
  57. (include "expform.sch")
  58. (include "lambdaexp.sch")
  59. (include "miscexp.sch")
  60.  
  61. ;;; Closure analysis before transformations is done by the following functions.
  62. ;;; The first is called to identify top-level functions which can be directly
  63. ;;; called, i.e. they are never assigned.  Once this is done, then further
  64. ;;; analysis is done to identify lambda expressions that must be closed over
  65. ;;; some variables.
  66.  
  67. (define (ANALYZE-CLOSURES1A exp)
  68.     (if ($define? exp)
  69.     (let ((var ($define-id exp))
  70.           (value ($define-exp exp)))
  71.          (if (and ($lambda? value) (not (id-set! var)))
  72.          (name-a-lambda var value)))))
  73.  
  74. (define (ANALYZE-CLOSURES1B exp)
  75.     (set! walk-lambda-id 'top-level)
  76.     (update-lambda-slots exp)
  77.     (walk-$tree assign-lambdas exp)
  78.     (update-lambda-slots exp)
  79.     (walk-$tree inherit-closed exp))
  80.  
  81. ;;; Given that the bindings of lambda functions are now known, it is possible
  82. ;;; to count the number of calls to the function.  Those calls which are
  83. ;;; marked tail-recursive and actually are, will not be counted.  All others
  84. ;;; will have their tail-recursive flag cleared and will be counted.  When
  85. ;;; this is done, the following will be known:
  86. ;;;
  87. ;;;    - all call's with the tail-recursive flag set will become branches.
  88. ;;;
  89. ;;;    - all lambda expressions which are stack allocated and have 1 real-call
  90. ;;;      can be open coded at the point that they are called and any variable
  91. ;;;      binding can be ignored.
  92.  
  93. (define (ANALYZE-CLOSURES2 exp)
  94.     (set! walk-lambda-id 'top-level)
  95.     (set! close-lambda-list '())
  96.     (update-lambda-slots exp)
  97.     (walk-$tree mark-tail-calls exp)
  98.     (walk-$tree count-calls exp)
  99.     (generate-lambdas close-lambda-list)
  100.     (update-lambda-slots exp)
  101.     (walk-$tree display-close exp))
  102.  
  103. ;;; WALK-$TREE walks the tree for a function produced by PASS1 and calls the
  104. ;;; inspection function.  During the walk, WALK-LAMBDA-ID will be set to the
  105. ;;; current lambda-id.
  106.  
  107. (define (WALK-$TREE function leaf)
  108.     (if (pair? leaf)
  109.     (begin (function leaf)
  110.            (cond (($set? leaf)
  111.               (walk-$tree function ($set-exp leaf)))
  112.              (($define? leaf)
  113.               (walk-$tree function ($define-exp leaf)))
  114.              (($lambda? leaf)
  115.               (let ((old-walk-lambda-id walk-lambda-id))
  116.                (set! walk-lambda-id ($lambda-id leaf))
  117.                (walk-$tree-list function ($lambda-body leaf))
  118.                (set! walk-lambda-id old-walk-lambda-id)))
  119.              (($call? leaf)
  120.               (let ((func ($call-func leaf)))
  121.                (walk-$tree-list function ($call-argl leaf))
  122.                (walk-$tree function func)))
  123.              (($if? leaf)
  124.               (walk-$tree-list function (cdr leaf)))))))
  125.  
  126. (define (WALK-$TREE-LIST function forms)
  127.     (for-each (lambda (leaf) (walk-$tree function leaf)) forms))
  128.  
  129. (define WALK-LAMBDA-ID 'top-level)
  130.     
  131. (define WALK-LAMBDA-IDS '(top-level))
  132.  
  133. (define WALK-LAMBDA-LEXICAL '())
  134.  
  135. (define CLOSE-LAMBDA-LIST '())
  136.  
  137. ;;; ASSIGN-LAMBDAS tries to figure out if any lambda expression is ever
  138. ;;; used for something besides a function.  If so, it must be "closed" on the
  139. ;;; heap.
  140. ;;;
  141. ;;; Once that information has been obtained, then the closure property is
  142. ;;; propogated by INHERIT-CLOSED.
  143.  
  144. (define (ASSIGN-LAMBDAS exp)
  145.     (cond (($set? exp)
  146.        (if (or (not ($lambda? ($set-exp exp)))
  147.            (not (eq? (id-lambda ($set-id exp))
  148.                  ($lambda-id ($set-exp exp)))))
  149.            (assign-lambdas-arg ($set-exp exp))))
  150.       (($lambda? exp)
  151.        (for-each assign-lambdas-arg ($lambda-body exp)))
  152.       (($if? exp)
  153.        (assign-lambdas-arg ($if-test exp))
  154.        (assign-lambdas-arg ($if-true exp))
  155.        (assign-lambdas-arg ($if-false exp)))
  156.       (($call? exp)
  157.        (let ((func ($call-func exp)))
  158.         (if ($lambda? func)
  159.             (begin (let loop ((vars (lambda-reqvars ($lambda-id func)))
  160.                       (vals ($call-argl exp)))
  161.                  (if vars
  162.                     (let ((var (car vars))
  163.                       (val (car vals)))
  164.                      (if (and (symbol? val)
  165.                           (id-lambda val))
  166.                          (set-id-lambda! var
  167.                          (id-lambda val)))
  168.                      (loop (cdr vars) (cdr vals))))))
  169.             (for-each assign-lambdas-arg ($call-argl exp)))))))
  170.  
  171. (define (ASSIGN-LAMBDAS-ARG exp)
  172.     (let ((lid (or (and (symbol? exp) (id-lambda exp))
  173.            ($lambda-id exp))))
  174.      (if lid
  175.          (begin (if (or (not (eq? (lambda-nestin lid) 'top-level))
  176.                 (and (symbol? exp)
  177.                  (not (eq? (id-use exp) 'global))))
  178.             (begin (set-lambda-closed! lid #t)
  179.                    (if (log? 'closed)
  180.                    (format sc-icode
  181.                        "~A must be a closed procedure~%"
  182.                        lid))))
  183.             (lambda-is-procedure lid)))))
  184.   
  185. (define (INHERIT-CLOSED exp)
  186.     (let ((closed-id ($lambda-id exp)))
  187.      (if (and closed-id (lambda-closed closed-id))
  188.          (let ((vars (indirect-lambda-lexical closed-id)))
  189.           (if (log? 'closed)
  190.               (format sc-icode "~A forces ~A to the display~%"
  191.                   closed-id vars))
  192.           (for-each
  193.               (lambda (var) (set-id-display! var #t))
  194.               vars)))))
  195.  
  196. ;;; The list of lexical variables used with-in the body of lid and all the
  197. ;;; lambda expressions which it calls.
  198.  
  199. (define INDIRECT-LAMBDA-CHECKED '())
  200.  
  201. (define (INDIRECT-LAMBDA-LEXICAL lid)
  202.     (set! indirect-lambda-checked '())
  203.     (indirect-lambda-lexical1 lid '() '()))
  204.  
  205. (define (INDIRECT-LAMBDA-LEXICAL1 lid lexvars bound)
  206.     (if (memq lid indirect-lambda-checked)
  207.     lexvars
  208.     (let* ((bound (append (append (lambda-reqvars lid)
  209.                       (lambda-optvars lid))
  210.                   bound))
  211.            (calls (lambda-calls lid))
  212.            (lexvars (let loop ((mine (lambda-lexical lid))
  213.                    (lexvars lexvars))
  214.                  (define (ADD-TO-CALLS var)
  215.                      (if (not (memq var calls))
  216.                      (set! calls
  217.                            (cons (id-lambda var)calls)))
  218.                      #t)
  219.                  (if mine
  220.                  (let ((var (car mine)))
  221.                       (if (or (memq var lexvars)
  222.                           (memq var bound)
  223.                           (and (id-lambda var)
  224.                            (lambda-generate
  225.                                (id-lambda var))
  226.                            (not (eq?
  227.                                 (lambda-generate
  228.                                 (id-lambda var))
  229.                                 'closed-procedure))
  230.                            (add-to-calls var)))
  231.                       (loop (cdr mine) lexvars)
  232.                       (loop (cdr mine)
  233.                         (cons var lexvars))))
  234.                  lexvars))))
  235.           (set! indirect-lambda-checked (cons lid indirect-lambda-checked))
  236.           (let loop ((calls calls) (lexvars lexvars))
  237.            (if calls
  238.                (let ((call (car calls)))
  239.                 (if (eq? (lambda-nestin call) 'top-level)
  240.                 (loop (cdr calls) lexvars)
  241.                 (loop (cdr calls)
  242.                       (indirect-lambda-lexical1
  243.                       call
  244.                       lexvars
  245.                       bound))))
  246.                lexvars)))))
  247.          
  248. ;;; UPDATE-LAMBDA-SLOTS is called to update fields in the lambda records which
  249. ;;; may change because of transformations.  The fields updated are
  250. ;;; LAMBDA-LEXICAL and LAMBDA-CALLS.
  251.  
  252. (define (UPDATE-LAMBDA-SLOTS exp)
  253.     (cond ((or ($set? exp) ($if? exp))
  254.        (for-each update-lambda-slots (cdr exp)))
  255.       (($define? exp)
  256.        (set! walk-lambda-id 'top-level)
  257.        (set! walk-lambda-ids '(top-level))
  258.        (set! walk-lambda-lexical '())
  259.        (update-lambda-slots ($define-exp exp)))
  260.       ((and ($lambda? exp) (not (memq ($lambda-id exp) walk-lambda-ids)))
  261.        (set! walk-lambda-ids (cons ($lambda-id exp) walk-lambda-ids))
  262.        (set! walk-lambda-id (car walk-lambda-ids))
  263.        (set-lambda-calls! walk-lambda-id '())
  264.        (let ((save-walk-lambda-lexical walk-lambda-lexical)
  265.          (lex '()))
  266.         (for-each
  267.             (lambda (exp)
  268.                 (set! walk-lambda-lexical '())
  269.                 (update-lambda-slots exp)
  270.                 (let loop ((vars walk-lambda-lexical))
  271.                  (cond ((null? vars))
  272.                        ((or (memq (car vars) lex)
  273.                         (eq? (id-boundid (car vars))
  274.                          walk-lambda-id))
  275.                     (loop (cdr vars)))
  276.                        (else (set! lex (cons (car vars) lex))
  277.                          (loop (cdr vars))))))
  278.             ($lambda-body exp))
  279.         (set-lambda-lexical! walk-lambda-id lex)
  280.         (set! walk-lambda-lexical save-walk-lambda-lexical)
  281.         (for-each
  282.             (lambda (x)
  283.                 (set! walk-lambda-lexical
  284.                   (mergeq x walk-lambda-lexical)))
  285.             lex))
  286.        (set! walk-lambda-ids (cdr walk-lambda-ids))
  287.        (set! walk-lambda-id (car walk-lambda-ids)))
  288.       (($call? exp)
  289.        (let* ((func ($call-func exp))
  290.           (lid (or ($lambda-id func)
  291.                (and (symbol? func) (id-lambda func)))))
  292.          (when lid
  293.                (set-lambda-calls! walk-lambda-id
  294.                (mergeq lid (lambda-calls walk-lambda-id)))
  295.                (if (symbol? func)
  296.                (if (memq (lambda-generate lid)
  297.                      '(inline inline-closed))
  298.                    (update-lambda-slots (lambda-$lambda lid)))))
  299.          (update-lambda-slots func)
  300.          (for-each update-lambda-slots ($call-argl exp))))
  301.       ((and (symbol? exp)
  302.         (id-boundid exp)
  303.         (not (eq? (id-boundid exp) walk-lambda-id)))
  304.        (set! walk-lambda-lexical (mergeq exp walk-lambda-lexical)))))
  305.  
  306. ;;; A simple merge function based on EQ?.
  307.  
  308. (define (MERGEQ x y)
  309.     (cond ((null? x) y)
  310.       ((memq x y) y)
  311.       (else (cons x y))))
  312.  
  313. ;;; MARK-TAIL-CALLS is called to flag all function calls which exit their
  314. ;;; containing lambda expression.  The flag is the id of the outer-most lambda
  315. ;;; expression that they exit.  Lambda expressions which are called inline
  316. ;;; will be so noted and have their generate field set to INLINE and their
  317. ;;; nestin field set correctly  at this time.  Similarly, top-level functions
  318. ;;; will have their generate field set to PROCEDURE.  Finally, a list of all
  319. ;;; lambda-id's will be collected in CLOSE-LAMBDA-LIST.
  320.  
  321. (define (MARK-TAIL-CALLS exp)
  322.     (cond (($lambda? exp)
  323.        (let ((lid ($lambda-id exp)))
  324.         (set! close-lambda-list (cons lid close-lambda-list))
  325.         (set-lambda-str-calls! lid '())
  326.         (set-lambda-tail-calls! lid '())
  327.         (set-lambda-real-calls! lid '())    
  328.         (if (eq? (lambda-nestin lid) 'top-level)
  329.             (if (not (lambda-generate lid)) (lambda-is-procedure lid))
  330.             (set-lambda-$lambda! lid exp))
  331.         (mark-tail-calls1 (car (last-pair ($lambda-body exp))) lid)))
  332.       ((and ($call? exp) ($lambda? ($call-func exp)))
  333.        (let ((lid ($lambda-id ($call-func exp))))
  334.         (set-lambda-nestin! lid walk-lambda-id)
  335.         (lambda-is-inline lid)))))
  336.  
  337. (define (MARK-TAIL-CALLS1 exp exitid)
  338.     (cond ((and ($call? exp) (not ($call-tail exp)))
  339.        (set-$call-tail! exp exitid)
  340.        (if ($lambda? ($call-func exp))
  341.            (begin (set-lambda-exits! ($lambda-id ($call-func exp)) exitid)
  342.               (mark-tail-calls1
  343.               (car (last-pair ($lambda-body ($call-func exp))))
  344.               exitid))))
  345.       (($if? exp)
  346.        (mark-tail-calls1 ($if-true exp) exitid)
  347.        (mark-tail-calls1 ($if-false exp) exitid))))
  348.  
  349. ;;; Calls are counted by the following function.  Three lists are maintained,
  350. ;;; STR-CALLS (self-tail-recursive calls), TAIL-CALLS (other tail calls), and
  351. ;;; REAL-CALLS (other calls).  The STR-CALLS and REAL-CALLS are composed of
  352. ;;; the caller's lambda-id.  The TAIL-CALLS list is composed of two item
  353. ;;; entries of the form (caller-id tail-exit-id).  Note that calls are only
  354. ;;; counted for lambda expressions which are internal to a function as those
  355. ;;; are the only ones that can be relocated.
  356.  
  357. (define (COUNT-CALLS exp)
  358.     (let* ((func (if ($call? exp) ($call-func exp) #f))
  359.        (id   (if (symbol? func) (id-lambda func) #f)))
  360.       (if (and id (not (id-external func)))
  361.           (cond ((eq? ($call-tail exp) id)
  362.              (set-lambda-str-calls! id
  363.              (cons walk-lambda-id (lambda-str-calls id))))
  364.             (($call-tail exp)
  365.              (set-lambda-tail-calls! id
  366.              (cons (list walk-lambda-id ($call-tail exp))
  367.                    (lambda-tail-calls id))))
  368.             (else
  369.              (set-lambda-real-calls! id
  370.              (cons walk-lambda-id (lambda-real-calls id))))))))
  371.  
  372. ;;; Once calls have been counted, it is possible to assign code generation
  373. ;;; methods to each of the lambda expressions.  This is done by this function
  374. ;;; which is called with a list of lambda expressions.  It makes an initial
  375. ;;; pass over the list and inspects those which don't have a code generation
  376. ;;; method.  Any lambda expressions that are called once are marked INLINE.
  377. ;;; Any others which have real-calls are marked (CLOSED-)PROCEDURE, and the
  378. ;;; rest (which have several tail calls) are saved for processing by
  379. ;;; GENERATE-TAILS.  Following this, any items with unknown generation methods
  380. ;;; are marked as PROCEDURE.
  381.  
  382. (define (GENERATE-LAMBDAS lambda-list)
  383.     (let ((unknown '()))
  384.      (for-each
  385.          (lambda (lid)
  386.              (let ((real (lambda-real-calls lid))
  387.                (tail (lambda-tail-calls lid)))
  388.               (cond ((lambda-generate lid) #t)
  389.                 ((= 1 (+ (length real) (length tail)))
  390.                  (if tail (set-lambda-exits! lid (cadar tail)))
  391.                  (let ((nestin (if real (car real)
  392.                            (caar tail))))
  393.                       (if (la-nestin-lb? nestin lid)
  394.                       (lambda-is-procedure lid)
  395.                       (begin (set-lambda-nestin! lid
  396.                              nestin)
  397.                          (lambda-is-inline lid)))))
  398.                 (real
  399.                  (lambda-is-procedure lid))
  400.                 (else (set! unknown (cons lid unknown))))))
  401.          lambda-list)
  402.      (for-each lambda-is-procedure
  403.          (generate-tails (generate-tails unknown 1) 2))))
  404.  
  405. ;;; GENERATE-TAILS attempts to turn the left overs into either INLINE or
  406. ;;; INLINE-TAIL calls. This is an iterative process and when no more
  407. ;;; conversions can be made, it will mark those left as PROCEDURE.  A lambda
  408. ;;; expression may be designated INLINE-TAIL when:
  409. ;;;
  410. ;;;     1.  All the callers are tail calls within the same procedure.
  411. ;;;     2.  All the calls exit the same lambda expression.
  412. ;;;
  413. ;;; FSM's are defered to the second pass to prevent lambda expressions from
  414. ;;; becoming inline-tails that could be inline.
  415.  
  416. (define (GENERATE-TAILS unknown pass)
  417.     (let ((progress #f)
  418.       (still-unknown '()))
  419.      (for-each
  420.          (lambda (lid)
  421.              (let ((tails (remove-self-tails lid)))
  422.               (if (= (length tails) 1)
  423.                   (begin (set-lambda-exits! lid (cadar tails))
  424.                      (set-lambda-nestin! lid (caar tails))
  425.                      (lambda-is-inline lid))
  426.                   (verify-tails lid pass))
  427.               (if (lambda-generate lid)
  428.                   (set! progress #t)
  429.                   (set! still-unknown (cons lid still-unknown)))))
  430.          unknown)
  431.      (if progress
  432.          (generate-tails still-unknown pass)
  433.          unknown)))
  434.  
  435. (define (LAMBDA-IS-PROCEDURE lid)
  436.     (set-lambda-$lambda! lid '())
  437.     (if (lambda-name lid) (assign-known-name (lambda-name lid)))
  438.     (if (lambda-closed lid)
  439.     (begin (set-lambda-nestin! lid 'top-level)
  440.            (set-lambda-generate! lid 'closed-procedure))
  441.     (set-lambda-generate! lid 'procedure)))
  442.  
  443. (define (LAMBDA-IS-INLINE lid)
  444.     (if (lambda-name lid) (set-id-display! (lambda-name lid) #f))
  445.     (set-lambda-generate! lid 'inline))
  446.  
  447. (define (LAMBDA-IS-INLINE-TAIL lid)
  448.     (if (lambda-name lid) (set-id-display! (lambda-name lid) #f))
  449.     (set-lambda-generate! lid 'inline-tail))
  450.  
  451. (define (REMOVE-SELF-TAILS lid)
  452.     (do ((tails (lambda-tail-calls lid) (cdr tails))
  453.      (newtails '()))
  454.     ((null? tails)
  455.      (set-lambda-tail-calls! lid newtails)
  456.      newtails)
  457.     (if (not (eq? (generate-tails-exits (cadar tails)) lid))
  458.         (set! newtails (cons (car tails) newtails)))))
  459.  
  460. (define (VERIFY-TAILS lid pass)
  461.     (do ((tails (lambda-tail-calls lid) (cdr tails))
  462.      (exits  '()))
  463.     ((null? tails)
  464.      (let ((exits (if (= (length exits) 1) (car exits) #f)))
  465.           (if exits     
  466.           (begin (do ((inline-tails (lambda-inline-tails exits)
  467.                   (merge-inline-tails (car ids) inline-tails))
  468.                   (ids (cons lid (lambda-inline-tails lid)) 
  469.                    (cdr ids)))
  470.                  ((null? ids)
  471.                   (set-lambda-inline-tails! exits inline-tails))
  472.                  (set-lambda-exits! (car ids) exits))
  473.              (set-lambda-inline-tails! lid '())
  474.              (set-lambda-nestin! lid exits)
  475.              (lambda-is-inline-tail lid)))))
  476.     (let ((x (generate-tails-exits (cadar tails))))
  477.          (if (and (not (memq x exits))
  478.               (or (eq? pass 1)
  479.               (not (could-inline-tail? (cadar tails) exits))))
  480.          (set! exits (cons x exits))))))
  481.  
  482. (define (GENERATE-TAILS-EXITS lid)
  483.     (if (and (memq (lambda-generate lid) '(inline inline-tail))
  484.          (lambda-exits lid))
  485.     (generate-tails-exits (lambda-exits lid))
  486.     lid))
  487.  
  488. ;;; A lambda expression that could be inline-tailed in the current context is
  489. ;;; one whose generation method is unknown and who only tail calls items who's
  490. ;;; generation methods are unknown or a member of the exits list.
  491.  
  492. (define (COULD-INLINE-TAIL? lid exits)
  493.     (and (not (lambda-generate lid))
  494.      (let loop ((tails (lambda-tail-calls lid)))
  495.           (if tails
  496.           (let ((exit (generate-tails-exits (cadar tails))))
  497.                (if (and (lambda-generate exit) (not (memq exit exits)))
  498.                #f
  499.                (loop (cdr tails))))
  500.           #t))))
  501.  
  502. ;;; The INLINE-TAILS list is ordered such that lambda expressions occur before
  503. ;;; those which nest in them and before those which they call.  This is
  504. ;;; required to generate correct code.
  505.  
  506. (define (MERGE-INLINE-TAILS lid tails)
  507.     (cond ((null? tails) (list lid))
  508.       ((or (la-nestin-lb? (car tails) lid)
  509.            (memq (car tails) (lambda-calls lid)))
  510.        (cons lid tails))
  511.       (else (cons (car tails) (merge-inline-tails lid (cdr tails))))))
  512.  
  513. ;;; The following boolean tests whether lambda expression "a" is nested in
  514. ;;; lambda expression "b".
  515.  
  516. (define (LA-NESTIN-LB? la lb)
  517.     (cond ((eq? la lb)          #t)
  518.           ((eq? la 'top-level)  #f)
  519.           (else                 (la-nestin-lb? (lambda-nestin la) lb))))
  520.  
  521. ;;; Once all the code generation modes for each lambda expression have been
  522. ;;; decided, the final analysis step is to decide which lexical variables must
  523. ;;; be allocated in the display.  A variable must be allocated to the display
  524. ;;; if it is used by a "closed" procedure, or it is lexically referenced
  525. ;;; across a C procedure boundary.
  526.  
  527. (define (DISPLAY-CLOSE exp)
  528.     (if ($lambda? exp)
  529.     (let ((id ($lambda-id exp)))
  530.          (if (memq (lambda-generate id) '(procedure closed-procedure))
  531.          (for-each
  532.              (lambda (var)
  533.                  (cond ((and (id-lambda var)
  534.                      (not (eq? (lambda-generate
  535.                                (id-lambda var))
  536.                            'closed-procedure)))
  537.                     (set-id-display! var #f))
  538.                    ((not (id-display var))
  539.                     (if (log? 'closed)
  540.                     (format sc-icode
  541.                         "~A forces ~A to display~%"
  542.                         id var))
  543.                     (set-id-display! var #t))))
  544.              (lambda-lexical id))))))
  545.