This file is indexed.

/usr/share/scheme48-1.9/opt/analyze.scm is in scheme48 1.9-5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
; Part of Scheme 48 1.9.  See file COPYING for notices and license.

; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Robert Ransom, Taylor Campbell

; Simple code analysis to determine whether it's a good idea to
; in-line calls to a given procedure.

; Hook into the byte code compiler.

(set-optimizer! 'auto-integrate
  (lambda (forms package)
    (let ((out (current-noise-port)))
      (newline out)
      (display "Analyzing... " out) (force-output out)
      (let* ((forms (find-usages (map force-node forms) package))
	     (names (analyze-forms forms package)))
	(cond ((not (null? names))
	       (newline out)
	       (display "Calls will be compiled in line: " out)
	       (write (reverse names) out))
	      (else
	       (display "no in-line procedures" out)))
	(newline out)
	forms))))

(define (analyze-forms scanned-nodes package)
  (let ((inlines '()))
    (for-each (lambda (node)
		(let ((lhs (analyze-form node package)))
		  (if lhs
		      (set! inlines (cons lhs inlines)))))
	      scanned-nodes)
    inlines))

(define (analyze-form node package)	;Return LHS iff calls will be inlined.
  (if (define-node? node)
      (let ((form (node-form node)))
	(let ((lhs (node-form (cadr form)))
	      (rhs (caddr form)))
	  (let ((type (package-lookup-type package lhs)))
	    (if (variable-type? type)
		(require "not assigned" lhs #f)
		(let ((method (inlinable-rhs? rhs type package lhs)))
		  (if method
		      (begin (package-add-static! package lhs method)
			     (if (transform? method)
				 lhs
				 #f))
		      #f))))))
      #f))

(define (inlinable-rhs? node type package lhs)
  (cond ((lambda-node? node)
	 (if (simple-lambda? node lhs package)
	     (make-inline-transform node type package lhs)
	     #f))
	((name-node? node)
	 (let ((name (node-form node)))
	   (if (and (require "symbol rhs" (list lhs name)
		      (symbol? name))
		    (require "rhs bound" (list lhs name)
		      (binding? (package-lookup-type package name)))
		    (require "rhs unassigned" (list lhs name)
		      (not (variable-type? (package-lookup-type package name))))
		    (require "definitely procedure" (list lhs name)
		      (procedure-type? (package-lookup-type package name))))
	       (make-inline-transform node type package lhs)
	       #f)))
	((loophole-node? node)
	 (inlinable-rhs? (caddr (node-form node)) type package lhs))
;These should already be taken care of.
;	((primitive-procedure-node? node)
;	 (get-operator (cadr (node-form node))))
	(else
	 #f)))

; We elect to integrate a procedure definition when
;  1. The procedure is not n-ary,
;  2. Every parameter is used exactly once and not assigned, and
;  3. The analysis phase says that the body is acceptable (see below). 

(define (simple-lambda? node id package)
  (let* ((exp (node-form node))
	 (formals (cadr exp))
	 (body (caddr exp))
	 (var-nodes (normalize-formals formals)))
    (and (require "not n-ary" id
	   (not (n-ary? formals)))
	 (require "unique references" id
	   (every (lambda (var-node)
		    (let ((usage (node-ref var-node 'usage)))
		      (and (= (usage-reference-count usage) 1)
			   (= (usage-assignment-count usage) 0))))
		  var-nodes))
	 (require "good analysis" id
	   (simple? (caddr exp) ret)))))

; --------------------
; SIMPLE? takes an alpha-converted expression and returns either
;  - #f, meaning that the procedure in which the expression occurs
;    has no chance of being fully inlinable, so we might as well give up,
;  - #t, if there's no problem, or
;  - 'empty, if there's no problem AND there are no lexical variable
;    references at or below this node.
; Foul situations are:
;  - complex quotations (we don't want to make multiple copies of them)
;  - a LAMBDA occurs (too much overhead, presumably)
;  - a call that is not to a primitive and not a tail call


; Main dispatch for analyzer
; The name node analyzer needs the node; all others can get by with the
; expression.

(define (simple? node ret?)
  ((operator-table-ref analyzers (node-operator-id node))
     (if (name-node? node)
	 node
	 (node-form node))
     ret?))

(define (simple-list? exp-list)
  (if (null? exp-list)
      'empty
      (let ((s1 (simple? (car exp-list) no-ret)))
	(cond ((eq? s1 'empty)
	       (simple-list? (cdr exp-list)))
	      ((and s1
		    (simple-list? (cdr exp-list)))
	       #t)
	      (else
	       #f)))))

; Particular operators

(define analyzers
  (make-operator-table (lambda (exp ret?)
			 (simple-list? (cdr exp)))))

(define (define-analyzer name proc)
  (operator-define! analyzers name #f proc))

(define-analyzer 'literal
  (lambda (exp ret?)
    (if (require "repeatable literal" #f
	  (simple-literal? exp))
	'empty
	#f)))

(define-analyzer 'unspecific
  (lambda (exp ret?)
    #t))

; It's too awkward to try to inline references to unbound variables.
; By special dispensation, this one analyzer receives the node instead of the
; expression.  It needs the node to look up the binding record.

(define-analyzer 'name
  (lambda (node ret?)
    ;; (if (node-ref node 'usage) #t 'empty)
    ;;   ... (not (generated? exp)) ugh ...
    (not (eq? (node-ref node 'binding)
	      'unbound))))

(define-analyzer 'quote
  (lambda (exp ret?)
    (if (require "repeatable quotation" #f
	  (simple-literal? (cadr exp)))
	'empty
	#f)))

(define-analyzer 'lambda
  (lambda (exp ret?) #f))

(define-analyzer 'letrec
  (lambda (exp ret?) #f))

(define-analyzer 'letrec*
  (lambda (exp ret?) #f))

(define-analyzer 'pure-letrec
  (lambda (exp ret?) #f))

(define-analyzer 'lap
  (lambda (exp ret?) #f))

; SET! loses because we might move a variable reference past a SET! on the
; variable.  This can't happen if the SET! is the last thing done.
; It's too awkward to try to inline references to unbound variables.

(define-analyzer 'set!
  (lambda (exp ret?)
    (and ret?
	 (not (eq? (node-ref (cadr exp) 'binding)
		   'unbound))
	 (simple? (caddr exp) no-ret))))

(define-analyzer 'loophole
  (lambda (exp ret?)
    (simple? (caddr exp) ret?)))

; Can't always fully in-line things like (lambda (a b c) (if a b c))

(define-analyzer 'if
  (lambda (exp ret?)
    (and (eq? (simple? (caddr exp) ret?) 'empty)
	 (eq? (simple? (cadddr exp) ret?) 'empty)
	 (simple? (cadr exp) no-ret))))

(define-analyzer 'begin
  (lambda (exp ret?)
    (let loop ((exps (cdr exp)))
      (if (null? (cdr exps))
	  (if (simple? (car exps) ret?) #t #f)
	  (and (simple? (car exps) no-ret)
	       (loop (cdr exps)))))))

(define-analyzer 'call
  (lambda (exp ret?)
    (let ((static (static-value (car exp))))
      (if (transform? static)
          (let ((new-node
                 (apply-inline-transform static
                                         exp
                                         (node-form (car exp)))))
            (if (eq? new-node exp)
                (really-simple-call? exp ret?)
                (simple? new-node ret?)))
	  (really-simple-call? exp ret?)))))

(define (really-simple-call? exp ret?)
  (let ((proc (car exp)))
    (and (require "non-local non-tail call" proc
	   (or (and ret? (simple? proc no-ret))	;tail calls are ok
               (primitive-proc? proc)))         ;as are calls to primitives
	 (simple-list? exp))))

; Calls to primitives and lexically bound variables are okay.

(define (primitive-proc? proc)
  (cond ((literal-node? proc)
	 (primop? (node-form proc)))
	((name-node? proc)
	 (let ((binding (node-ref proc 'binding)))
	   (and (binding? binding)
		(primop? (binding-static binding)))))
	(else
	 #f)))

(define no-ret #f)

(define ret #t)

(define (simple-literal? x) ;Things that TRANSPORT won't copy.
  (or (integer? x)
      (boolean? x)
      (null? x)
      (char? x)
      (symbol? x)))

; --------------------
; debugging hack

(define (require reason id x)
  (if (and *debug?* (not x))
      (begin (write id)
	     (display " lost because ")
	     (display reason)
	     (display " failed")
	     (newline)))
  x)

(define *debug?* #f)

; utility

(define (package-lookup-type p name)
  (let ((probe (package-lookup p name)))
    (if (binding? probe)
	(binding-type probe)
	#f)))

;----------------
;(define (foo f p)
;  (analyze-forms (alpha-forms (scan-file f p) p)))
;
;
;(define (tst e p)
;  (inlinable-rhs? (alpha e p) #f))
;
;(define b (make-compiler-base))
;
;(define p (make-simple-package (list b) eval #f))
;
;; (define b-stuff (alpha-structure b))
;