when leaving a non-tail let, allow bound vals to be collected
[bpt/guile.git] / module / language / tree-il / compile-glil.scm
CommitLineData
811d10f5
AW
1;;; TREE-IL -> GLIL compiler
2
9dadfa47 3;; Copyright (C) 2001,2008,2009,2010,2011 Free Software Foundation, Inc.
811d10f5 4
53befeb7
NJ
5;;;; This library is free software; you can redistribute it and/or
6;;;; modify it under the terms of the GNU Lesser General Public
7;;;; License as published by the Free Software Foundation; either
8;;;; version 3 of the License, or (at your option) any later version.
9;;;;
10;;;; This library is distributed in the hope that it will be useful,
11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;;;; Lesser General Public License for more details.
14;;;;
15;;;; You should have received a copy of the GNU Lesser General Public
16;;;; License along with this library; if not, write to the Free Software
17;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
811d10f5
AW
18
19;;; Code:
20
21(define-module (language tree-il compile-glil)
22 #:use-module (system base syntax)
66d3e9a3 23 #:use-module (system base pmatch)
4b856371 24 #:use-module (system base message)
cf10678f 25 #:use-module (ice-9 receive)
811d10f5 26 #:use-module (language glil)
60ed31d2 27 #:use-module (system vm instruction)
811d10f5 28 #:use-module (language tree-il)
073bb617 29 #:use-module (language tree-il optimize)
b275fb26 30 #:use-module (language tree-il canonicalize)
cf10678f 31 #:use-module (language tree-il analyze)
48b1db75 32 #:use-module ((srfi srfi-1) #:select (filter-map))
811d10f5
AW
33 #:export (compile-glil))
34
073bb617 35;; allocation:
66d3e9a3 36;; sym -> {lambda -> address}
8a4ca0ea
AW
37;; lambda -> (labels . free-locs)
38;; lambda-case -> (gensym . nlocs)
66d3e9a3 39;;
8a4ca0ea
AW
40;; address ::= (local? boxed? . index)
41;; labels ::= ((sym . lambda) ...)
66d3e9a3
AW
42;; free-locs ::= ((sym0 . address0) (sym1 . address1) ...)
43;; free variable addresses are relative to parent proc.
073bb617 44
a1a482e0
AW
45(define *comp-module* (make-fluid))
46
4b856371 47(define %warning-passes
48b1db75 48 `((unused-variable . ,unused-variable-analysis)
bcae9a98 49 (unused-toplevel . ,unused-toplevel-analysis)
ae03cf1f 50 (unbound-variable . ,unbound-variable-analysis)
75365375
LC
51 (arity-mismatch . ,arity-analysis)
52 (format . ,format-analysis)))
4b856371 53
811d10f5 54(define (compile-glil x e opts)
4b856371
LC
55 (define warnings
56 (or (and=> (memq #:warnings opts) cadr)
57 '()))
58
43eb8aca 59 ;; Go through the warning passes.
48b1db75
LC
60 (let ((analyses (filter-map (lambda (kind)
61 (assoc-ref %warning-passes kind))
62 warnings)))
63 (analyze-tree analyses x e))
aaae0d5a 64
8a4ca0ea 65 (let* ((x (make-lambda (tree-il-src x) '()
1e2a8edb 66 (make-lambda-case #f '() #f #f #f '() '() x #f)))
aaae0d5a 67 (x (optimize! x e opts))
b275fb26 68 (x (canonicalize! x))
aaae0d5a 69 (allocation (analyze-lexicals x)))
4b856371 70
eddd16d7
AW
71 (with-fluids ((*comp-module* e))
72 (values (flatten-lambda x #f allocation)
73 e
74 e))))
811d10f5
AW
75
76\f
811d10f5 77
112edbae
AW
78(define *primcall-ops* (make-hash-table))
79(for-each
80 (lambda (x) (hash-set! *primcall-ops* (car x) (cdr x)))
81 '(((eq? . 2) . eq?)
82 ((eqv? . 2) . eqv?)
83 ((equal? . 2) . equal?)
84 ((= . 2) . ee?)
85 ((< . 2) . lt?)
86 ((> . 2) . gt?)
87 ((<= . 2) . le?)
88 ((>= . 2) . ge?)
89 ((+ . 2) . add)
90 ((- . 2) . sub)
7382f23e
AW
91 ((1+ . 1) . add1)
92 ((1- . 1) . sub1)
112edbae
AW
93 ((* . 2) . mul)
94 ((/ . 2) . div)
95 ((quotient . 2) . quo)
96 ((remainder . 2) . rem)
97 ((modulo . 2) . mod)
b10d9330
AW
98 ((ash . 2) . ash)
99 ((logand . 2) . logand)
100 ((logior . 2) . logior)
101 ((logxor . 2) . logxor)
112edbae
AW
102 ((not . 1) . not)
103 ((pair? . 1) . pair?)
104 ((cons . 2) . cons)
105 ((car . 1) . car)
106 ((cdr . 1) . cdr)
107 ((set-car! . 2) . set-car!)
108 ((set-cdr! . 2) . set-cdr!)
109 ((null? . 1) . null?)
c11f46af 110 ((list? . 1) . list?)
cf45ff03
AW
111 ((symbol? . 1) . symbol?)
112 ((vector? . 1) . vector?)
c11f46af 113 (list . list)
ad9b8c45 114 (vector . vector)
aec4a84a 115 ((class-of . 1) . class-of)
ad9b8c45 116 ((@slot-ref . 2) . slot-ref)
d6f1ce3d
AW
117 ((@slot-set! . 3) . slot-set)
118 ((vector-ref . 2) . vector-ref)
119 ((vector-set! . 3) . vector-set)
1d30393f
AW
120 ((variable-ref . 1) . variable-ref)
121 ;; nb, *not* variable-set! -- the args are switched
d27a7811 122 ((variable-bound? . 1) . variable-bound?)
bd91ecce
LC
123 ((struct? . 1) . struct?)
124 ((struct-vtable . 1) . struct-vtable)
a752c0dc
LC
125 ((struct-ref . 2) . struct-ref)
126 ((struct-set! . 3) . struct-set)
9a974fd3 127 (make-struct/no-tail . make-struct)
39141c87 128
d61e866c 129 ;; hack for javascript
52272fc7 130 ((return . 1) . return)
9582b26c
AW
131 ;; hack for lua
132 (return/values . return/values)
d61e866c 133
39141c87
AW
134 ((bytevector-u8-ref . 2) . bv-u8-ref)
135 ((bytevector-u8-set! . 3) . bv-u8-set)
136 ((bytevector-s8-ref . 2) . bv-s8-ref)
137 ((bytevector-s8-set! . 3) . bv-s8-set)
138
139 ((bytevector-u16-ref . 3) . bv-u16-ref)
140 ((bytevector-u16-set! . 4) . bv-u16-set)
141 ((bytevector-u16-native-ref . 2) . bv-u16-native-ref)
142 ((bytevector-u16-native-set! . 3) . bv-u16-native-set)
143 ((bytevector-s16-ref . 3) . bv-s16-ref)
144 ((bytevector-s16-set! . 4) . bv-s16-set)
145 ((bytevector-s16-native-ref . 2) . bv-s16-native-ref)
146 ((bytevector-s16-native-set! . 3) . bv-s16-native-set)
147
148 ((bytevector-u32-ref . 3) . bv-u32-ref)
149 ((bytevector-u32-set! . 4) . bv-u32-set)
150 ((bytevector-u32-native-ref . 2) . bv-u32-native-ref)
151 ((bytevector-u32-native-set! . 3) . bv-u32-native-set)
152 ((bytevector-s32-ref . 3) . bv-s32-ref)
153 ((bytevector-s32-set! . 4) . bv-s32-set)
154 ((bytevector-s32-native-ref . 2) . bv-s32-native-ref)
155 ((bytevector-s32-native-set! . 3) . bv-s32-native-set)
156
157 ((bytevector-u64-ref . 3) . bv-u64-ref)
158 ((bytevector-u64-set! . 4) . bv-u64-set)
159 ((bytevector-u64-native-ref . 2) . bv-u64-native-ref)
160 ((bytevector-u64-native-set! . 3) . bv-u64-native-set)
161 ((bytevector-s64-ref . 3) . bv-s64-ref)
162 ((bytevector-s64-set! . 4) . bv-s64-set)
163 ((bytevector-s64-native-ref . 2) . bv-s64-native-ref)
164 ((bytevector-s64-native-set! . 3) . bv-s64-native-set)
165
166 ((bytevector-ieee-single-ref . 3) . bv-f32-ref)
167 ((bytevector-ieee-single-set! . 4) . bv-f32-set)
168 ((bytevector-ieee-single-native-ref . 2) . bv-f32-native-ref)
169 ((bytevector-ieee-single-native-set! . 3) . bv-f32-native-set)
170 ((bytevector-ieee-double-ref . 3) . bv-f64-ref)
171 ((bytevector-ieee-double-set! . 4) . bv-f64-set)
172 ((bytevector-ieee-double-native-ref . 2) . bv-f64-native-ref)
173 ((bytevector-ieee-double-native-set! . 3) . bv-f64-native-set)))
174
175
176\f
112edbae 177
811d10f5
AW
178(define (make-label) (gensym ":L"))
179
66d3e9a3 180(define (vars->bind-list ids vars allocation proc)
2ce77f2d 181 (map (lambda (id v)
66d3e9a3
AW
182 (pmatch (hashq-ref (hashq-ref allocation v) proc)
183 ((#t ,boxed? . ,n)
184 (list id boxed? n))
3b24aee6 185 (,x (error "bad var list element" id v x))))
2ce77f2d 186 ids
cf10678f
AW
187 vars))
188
66d3e9a3 189(define (emit-bindings src ids vars allocation proc emit-code)
d97b69d9
AW
190 (emit-code src (make-glil-bind
191 (vars->bind-list ids vars allocation proc))))
cf10678f
AW
192
193(define (with-output-to-code proc)
194 (let ((out '()))
195 (define (emit-code src x)
196 (set! out (cons x out))
197 (if src
198 (set! out (cons (make-glil-source src) out))))
199 (proc emit-code)
200 (reverse out)))
201
9b29d607 202(define (flatten-lambda x self-label allocation)
8a4ca0ea
AW
203 (record-case x
204 ((<lambda> src meta body)
205 (make-glil-program
206 meta
207 (with-output-to-code
208 (lambda (emit-code)
209 ;; write source info for proc
210 (if src (emit-code #f (make-glil-source src)))
8a4ca0ea 211 ;; compile the body, yo
0083cb5e
AW
212 (flatten-lambda-case body allocation x self-label
213 (car (hashq-ref allocation x))
214 emit-code)))))))
cf10678f 215
0083cb5e
AW
216(define (flatten-lambda-case lcase allocation self self-label fix-labels
217 emit-code)
cf10678f
AW
218 (define (emit-label label)
219 (emit-code #f (make-glil-label label)))
220 (define (emit-branch src inst label)
221 (emit-code src (make-glil-branch inst label)))
222
230cfcfb
AW
223 ;; RA: "return address"; #f unless we're in a non-tail fix with labels
224 ;; MVRA: "multiple-values return address"; #f unless we're in a let-values
0083cb5e 225 (let comp ((x lcase) (context 'tail) (RA #f) (MVRA #f))
230cfcfb
AW
226 (define (comp-tail tree) (comp tree context RA MVRA))
227 (define (comp-push tree) (comp tree 'push #f #f))
228 (define (comp-drop tree) (comp tree 'drop #f #f))
229 (define (comp-vals tree MVRA) (comp tree 'vals #f MVRA))
230 (define (comp-fix tree RA) (comp tree context RA MVRA))
231
232 ;; A couple of helpers. Note that if we are in tail context, we
233 ;; won't have an RA.
234 (define (maybe-emit-return)
235 (if RA
236 (emit-branch #f 'br RA)
237 (if (eq? context 'tail)
238 (emit-code #f (make-glil-call 'return 1)))))
239
fb135e12
AW
240 ;; After lexical binding forms in non-tail context, call this
241 ;; function to clear stack slots, allowing their previous values to
242 ;; be collected.
243 (define (clear-stack-slots context syms)
244 (case context
245 ((push drop)
246 (for-each (lambda (v)
247 (and=>
248 ;; Can be #f if the var is labels-allocated.
249 (hashq-ref allocation v)
250 (lambda (h)
251 (pmatch (hashq-ref h self)
252 ((#t _ . ,n)
253 (emit-code #f (make-glil-void))
254 (emit-code #f (make-glil-lexical #t #f 'set n)))
255 (,loc (error "bad let var allocation" x loc))))))
256 syms))))
257
cf10678f
AW
258 (record-case x
259 ((<void>)
260 (case context
230cfcfb
AW
261 ((push vals tail)
262 (emit-code #f (make-glil-void))))
263 (maybe-emit-return))
cf10678f
AW
264
265 ((<const> src exp)
266 (case context
230cfcfb
AW
267 ((push vals tail)
268 (emit-code src (make-glil-const exp))))
269 (maybe-emit-return))
cf10678f
AW
270
271 ;; FIXME: should represent sequence as exps tail
e5f5113c 272 ((<sequence> exps)
cf10678f
AW
273 (let lp ((exps exps))
274 (if (null? (cdr exps))
275 (comp-tail (car exps))
276 (begin
277 (comp-drop (car exps))
278 (lp (cdr exps))))))
279
280 ((<application> src proc args)
dce042f1 281 ;; FIXME: need a better pattern-matcher here
112edbae 282 (cond
dce042f1
AW
283 ((and (primitive-ref? proc)
284 (eq? (primitive-ref-name proc) '@apply)
0f423f20 285 (>= (length args) 1))
dce042f1
AW
286 (let ((proc (car args))
287 (args (cdr args)))
288 (cond
289 ((and (primitive-ref? proc) (eq? (primitive-ref-name proc) 'values)
f4aa8d53 290 (not (eq? context 'push)) (not (eq? context 'vals)))
dce042f1
AW
291 ;; tail: (lambda () (apply values '(1 2)))
292 ;; drop: (lambda () (apply values '(1 2)) 3)
293 ;; push: (lambda () (list (apply values '(10 12)) 1))
294 (case context
230cfcfb 295 ((drop) (for-each comp-drop args) (maybe-emit-return))
dce042f1
AW
296 ((tail)
297 (for-each comp-push args)
298 (emit-code src (make-glil-call 'return/values* (length args))))))
299
300 (else
dce042f1 301 (case context
0f423f20
AW
302 ((tail)
303 (comp-push proc)
304 (for-each comp-push args)
a5bbb22e 305 (emit-code src (make-glil-call 'tail-apply (1+ (length args)))))
0f423f20 306 ((push)
b7946e9e 307 (emit-code src (make-glil-call 'new-frame 0))
0f423f20
AW
308 (comp-push proc)
309 (for-each comp-push args)
230cfcfb
AW
310 (emit-code src (make-glil-call 'apply (1+ (length args))))
311 (maybe-emit-return))
f4aa8d53
AW
312 ((vals)
313 (comp-vals
314 (make-application src (make-primitive-ref #f 'apply)
315 (cons proc args))
230cfcfb
AW
316 MVRA)
317 (maybe-emit-return))
0f423f20
AW
318 ((drop)
319 ;; Well, shit. The proc might return any number of
320 ;; values (including 0), since it's in a drop context,
321 ;; yet apply does not create a MV continuation. So we
322 ;; mv-call out to our trampoline instead.
323 (comp-drop
324 (make-application src (make-primitive-ref #f 'apply)
230cfcfb
AW
325 (cons proc args)))
326 (maybe-emit-return)))))))
327
b88fef55 328 ((and (primitive-ref? proc) (eq? (primitive-ref-name proc) 'values))
a1a482e0
AW
329 ;; tail: (lambda () (values '(1 2)))
330 ;; drop: (lambda () (values '(1 2)) 3)
331 ;; push: (lambda () (list (values '(10 12)) 1))
f4aa8d53 332 ;; vals: (let-values (((a b ...) (values 1 2 ...))) ...)
a1a482e0 333 (case context
230cfcfb 334 ((drop) (for-each comp-drop args) (maybe-emit-return))
b88fef55
AW
335 ((push)
336 (case (length args)
337 ((0)
338 ;; FIXME: This is surely an error. We need to add a
339 ;; values-mismatch warning pass.
340 (emit-code src (make-glil-call 'new-frame 0))
341 (comp-push proc)
342 (emit-code src (make-glil-call 'call 0))
343 (maybe-emit-return))
344 ((1)
345 (comp-push (car args)))
346 (else
347 ;; Taking advantage of unspecified order of evaluation of
348 ;; arguments.
349 (for-each comp-drop (cdr args))
350 (comp-push (car args)))))
f4aa8d53
AW
351 ((vals)
352 (for-each comp-push args)
353 (emit-code #f (make-glil-const (length args)))
230cfcfb 354 (emit-branch src 'br MVRA))
a1a482e0
AW
355 ((tail)
356 (for-each comp-push args)
b88fef55
AW
357 (emit-code src (let ((len (length args)))
358 (if (= len 1)
359 (make-glil-call 'return 1)
360 (make-glil-call 'return/values len)))))))
f4aa8d53 361
dce042f1
AW
362 ((and (primitive-ref? proc)
363 (eq? (primitive-ref-name proc) '@call-with-values)
364 (= (length args) 2))
365 ;; CONSUMER
366 ;; PRODUCER
367 ;; (mv-call MV)
368 ;; ([tail]-call 1)
369 ;; goto POST
370 ;; MV: [tail-]call/nargs
371 ;; POST: (maybe-drop)
f4aa8d53
AW
372 (case context
373 ((vals)
374 ;; Fall back.
375 (comp-vals
376 (make-application src (make-primitive-ref #f 'call-with-values)
377 args)
230cfcfb
AW
378 MVRA)
379 (maybe-emit-return))
f4aa8d53
AW
380 (else
381 (let ((MV (make-label)) (POST (make-label))
382 (producer (car args)) (consumer (cadr args)))
b7946e9e
AW
383 (if (not (eq? context 'tail))
384 (emit-code src (make-glil-call 'new-frame 0)))
f4aa8d53 385 (comp-push consumer)
b7946e9e 386 (emit-code src (make-glil-call 'new-frame 0))
f4aa8d53
AW
387 (comp-push producer)
388 (emit-code src (make-glil-mv-call 0 MV))
389 (case context
a5bbb22e 390 ((tail) (emit-code src (make-glil-call 'tail-call 1)))
f4aa8d53
AW
391 (else (emit-code src (make-glil-call 'call 1))
392 (emit-branch #f 'br POST)))
393 (emit-label MV)
394 (case context
a5bbb22e 395 ((tail) (emit-code src (make-glil-call 'tail-call/nargs 0)))
f4aa8d53
AW
396 (else (emit-code src (make-glil-call 'call/nargs 0))
397 (emit-label POST)
398 (if (eq? context 'drop)
230cfcfb
AW
399 (emit-code #f (make-glil-call 'drop 1)))
400 (maybe-emit-return)))))))
dce042f1
AW
401
402 ((and (primitive-ref? proc)
403 (eq? (primitive-ref-name proc) '@call-with-current-continuation)
e32a1792 404 (= (length args) 1))
dce042f1 405 (case context
0f423f20
AW
406 ((tail)
407 (comp-push (car args))
a5bbb22e 408 (emit-code src (make-glil-call 'tail-call/cc 1)))
f4aa8d53
AW
409 ((vals)
410 (comp-vals
411 (make-application
412 src (make-primitive-ref #f 'call-with-current-continuation)
413 args)
230cfcfb
AW
414 MVRA)
415 (maybe-emit-return))
0f423f20
AW
416 ((push)
417 (comp-push (car args))
230cfcfb
AW
418 (emit-code src (make-glil-call 'call/cc 1))
419 (maybe-emit-return))
0f423f20
AW
420 ((drop)
421 ;; Crap. Just like `apply' in drop context.
422 (comp-drop
423 (make-application
424 src (make-primitive-ref #f 'call-with-current-continuation)
230cfcfb
AW
425 args))
426 (maybe-emit-return))))
dce042f1 427
9b3cc659
AW
428 ;; A hack for variable-set, the opcode for which takes its args
429 ;; reversed, relative to the variable-set! function
430 ((and (primitive-ref? proc)
431 (eq? (primitive-ref-name proc) 'variable-set!)
432 (= (length args) 2))
433 (comp-push (cadr args))
434 (comp-push (car args))
435 (emit-code src (make-glil-call 'variable-set 2))
436 (case context
437 ((tail push vals) (emit-code #f (make-glil-void))))
438 (maybe-emit-return))
439
112edbae 440 ((and (primitive-ref? proc)
c11f46af
AW
441 (or (hash-ref *primcall-ops*
442 (cons (primitive-ref-name proc) (length args)))
443 (hash-ref *primcall-ops* (primitive-ref-name proc))))
112edbae
AW
444 => (lambda (op)
445 (for-each comp-push args)
446 (emit-code src (make-glil-call op (length args)))
60ed31d2
AW
447 (case (instruction-pushes op)
448 ((0)
449 (case context
230cfcfb
AW
450 ((tail push vals) (emit-code #f (make-glil-void))))
451 (maybe-emit-return))
60ed31d2
AW
452 ((1)
453 (case context
230cfcfb
AW
454 ((drop) (emit-code #f (make-glil-call 'drop 1))))
455 (maybe-emit-return))
9582b26c
AW
456 ((-1)
457 ;; A control instruction, like return/values. Here we
458 ;; just have to hope that the author of the tree-il
459 ;; knew what they were doing.
460 *unspecified*)
60ed31d2
AW
461 (else
462 (error "bad primitive op: too many pushes"
463 op (instruction-pushes op))))))
464
0083cb5e 465 ;; call to the same lambda-case in tail position
9b29d607
AW
466 ((and (lexical-ref? proc)
467 self-label (eq? (lexical-ref-gensym proc) self-label)
0083cb5e
AW
468 (eq? context 'tail)
469 (not (lambda-case-kw lcase))
470 (not (lambda-case-rest lcase))
471 (= (length args)
472 (+ (length (lambda-case-req lcase))
473 (or (and=> (lambda-case-opt lcase) length) 0))))
474 (for-each comp-push args)
475 (for-each (lambda (sym)
476 (pmatch (hashq-ref (hashq-ref allocation sym) self)
477 ((#t #f . ,index) ; unboxed
478 (emit-code #f (make-glil-lexical #t #f 'set index)))
479 ((#t #t . ,index) ; boxed
480 ;; new box
481 (emit-code #f (make-glil-lexical #t #t 'box index)))
482 (,x (error "bad lambda-case arg allocation" x))))
483 (reverse (lambda-case-gensyms lcase)))
484 (emit-branch src 'br (car (hashq-ref allocation lcase))))
9b29d607 485
230cfcfb
AW
486 ;; lambda, the ultimate goto
487 ((and (lexical-ref? proc)
488 (assq (lexical-ref-gensym proc) fix-labels))
8a4ca0ea
AW
489 ;; like the self-tail-call case, though we can handle "drop"
490 ;; contexts too. first, evaluate new values, pushing them on
491 ;; the stack
230cfcfb 492 (for-each comp-push args)
8a4ca0ea
AW
493 ;; find the specific case, rename args, and goto the case label
494 (let lp ((lcase (lambda-body
495 (assq-ref fix-labels (lexical-ref-gensym proc)))))
496 (cond
497 ((and (lambda-case? lcase)
498 (not (lambda-case-kw lcase))
499 (not (lambda-case-opt lcase))
500 (not (lambda-case-rest lcase))
501 (= (length args) (length (lambda-case-req lcase))))
502 ;; we have a case that matches the args; rename variables
503 ;; and goto the case label
504 (for-each (lambda (sym)
505 (pmatch (hashq-ref (hashq-ref allocation sym) self)
506 ((#t #f . ,index) ; unboxed
507 (emit-code #f (make-glil-lexical #t #f 'set index)))
508 ((#t #t . ,index) ; boxed
509 (emit-code #f (make-glil-lexical #t #t 'box index)))
3b24aee6 510 (,x (error "bad lambda-case arg allocation" x))))
93f63467 511 (reverse (lambda-case-gensyms lcase)))
8a4ca0ea
AW
512 (emit-branch src 'br (car (hashq-ref allocation lcase))))
513 ((lambda-case? lcase)
514 ;; no match, try next case
3a88cb3b 515 (lp (lambda-case-alternate lcase)))
8a4ca0ea
AW
516 (else
517 ;; no cases left. we can't really handle this currently.
518 ;; ideally we would push on a new frame, then do a "local
519 ;; call" -- which doesn't require consing up a program
520 ;; object. but for now error, as this sort of case should
521 ;; preclude label allocation.
522 (error "couldn't find matching case for label call" x)))))
230cfcfb 523
112edbae 524 (else
b7946e9e
AW
525 (if (not (eq? context 'tail))
526 (emit-code src (make-glil-call 'new-frame 0)))
112edbae
AW
527 (comp-push proc)
528 (for-each comp-push args)
dce042f1
AW
529 (let ((len (length args)))
530 (case context
a5bbb22e 531 ((tail) (emit-code src (make-glil-call 'tail-call len)))
230cfcfb
AW
532 ((push) (emit-code src (make-glil-call 'call len))
533 (maybe-emit-return))
534 ((vals) (emit-code src (make-glil-mv-call len MVRA))
535 (maybe-emit-return))
536 ((drop) (let ((MV (make-label)) (POST (make-label)))
537 (emit-code src (make-glil-mv-call len MV))
538 (emit-code #f (make-glil-call 'drop 1))
539 (emit-branch #f 'br (or RA POST))
540 (emit-label MV)
05c51bcf 541 (emit-code #f (make-glil-mv-bind 0 #f))
230cfcfb
AW
542 (if RA
543 (emit-branch #f 'br RA)
544 (emit-label POST)))))))))
073bb617 545
b6d93b11 546 ((<conditional> src test consequent alternate)
073bb617
AW
547 ;; TEST
548 ;; (br-if-not L1)
b6d93b11 549 ;; consequent
073bb617 550 ;; (br L2)
b6d93b11 551 ;; L1: alternate
073bb617
AW
552 ;; L2:
553 (let ((L1 (make-label)) (L2 (make-label)))
b4a595a5
AW
554 ;; need a pattern matcher
555 (record-case test
556 ((<application> proc args)
557 (record-case proc
558 ((<primitive-ref> name)
559 (let ((len (length args)))
560 (cond
561
562 ((and (eq? name 'eq?) (= len 2))
563 (comp-push (car args))
564 (comp-push (cadr args))
565 (emit-branch src 'br-if-not-eq L1))
566
567 ((and (eq? name 'null?) (= len 1))
568 (comp-push (car args))
569 (emit-branch src 'br-if-not-null L1))
570
571 ((and (eq? name 'not) (= len 1))
572 (let ((app (car args)))
573 (record-case app
574 ((<application> proc args)
575 (let ((len (length args)))
576 (record-case proc
577 ((<primitive-ref> name)
578 (cond
579
580 ((and (eq? name 'eq?) (= len 2))
581 (comp-push (car args))
582 (comp-push (cadr args))
583 (emit-branch src 'br-if-eq L1))
584
585 ((and (eq? name 'null?) (= len 1))
586 (comp-push (car args))
587 (emit-branch src 'br-if-null L1))
588
589 (else
590 (comp-push app)
591 (emit-branch src 'br-if L1))))
592 (else
593 (comp-push app)
594 (emit-branch src 'br-if L1)))))
595 (else
596 (comp-push app)
597 (emit-branch src 'br-if L1)))))
598
599 (else
600 (comp-push test)
601 (emit-branch src 'br-if-not L1)))))
602 (else
603 (comp-push test)
604 (emit-branch src 'br-if-not L1))))
605 (else
606 (comp-push test)
607 (emit-branch src 'br-if-not L1)))
608
b6d93b11 609 (comp-tail consequent)
d97b69d9
AW
610 ;; if there is an RA, comp-tail will cause a jump to it -- just
611 ;; have to clean up here if there is no RA.
612 (if (and (not RA) (not (eq? context 'tail)))
613 (emit-branch #f 'br L2))
cf10678f 614 (emit-label L1)
b4a595a5 615 (comp-tail alternate)
d97b69d9
AW
616 (if (and (not RA) (not (eq? context 'tail)))
617 (emit-label L2))))
618
cf10678f 619 ((<primitive-ref> src name)
a1a482e0
AW
620 (cond
621 ((eq? (module-variable (fluid-ref *comp-module*) name)
622 (module-variable the-root-module name))
623 (case context
230cfcfb
AW
624 ((tail push vals)
625 (emit-code src (make-glil-toplevel 'ref name))))
626 (maybe-emit-return))
94ff26b9 627 ((module-variable the-root-module name)
a1a482e0 628 (case context
230cfcfb
AW
629 ((tail push vals)
630 (emit-code src (make-glil-module 'ref '(guile) name #f))))
94ff26b9
AW
631 (maybe-emit-return))
632 (else
633 (case context
634 ((tail push vals)
635 (emit-code src (make-glil-module
636 'ref (module-name (fluid-ref *comp-module*)) name #f))))
230cfcfb 637 (maybe-emit-return))))
cf10678f 638
e5f5113c 639 ((<lexical-ref> src gensym)
cf10678f 640 (case context
f4aa8d53 641 ((push vals tail)
9b29d607 642 (pmatch (hashq-ref (hashq-ref allocation gensym) self)
66d3e9a3
AW
643 ((,local? ,boxed? . ,index)
644 (emit-code src (make-glil-lexical local? boxed? 'ref index)))
645 (,loc
3b24aee6 646 (error "bad lexical allocation" x loc)))))
230cfcfb 647 (maybe-emit-return))
66d3e9a3 648
e5f5113c 649 ((<lexical-set> src gensym exp)
cf10678f 650 (comp-push exp)
9b29d607 651 (pmatch (hashq-ref (hashq-ref allocation gensym) self)
66d3e9a3
AW
652 ((,local? ,boxed? . ,index)
653 (emit-code src (make-glil-lexical local? boxed? 'set index)))
654 (,loc
3b24aee6 655 (error "bad lexical allocation" x loc)))
cf10678f 656 (case context
230cfcfb
AW
657 ((tail push vals)
658 (emit-code #f (make-glil-void))))
659 (maybe-emit-return))
cf10678f
AW
660
661 ((<module-ref> src mod name public?)
662 (emit-code src (make-glil-module 'ref mod name public?))
663 (case context
230cfcfb
AW
664 ((drop) (emit-code #f (make-glil-call 'drop 1))))
665 (maybe-emit-return))
cf10678f
AW
666
667 ((<module-set> src mod name public? exp)
668 (comp-push exp)
669 (emit-code src (make-glil-module 'set mod name public?))
670 (case context
230cfcfb
AW
671 ((tail push vals)
672 (emit-code #f (make-glil-void))))
673 (maybe-emit-return))
cf10678f
AW
674
675 ((<toplevel-ref> src name)
676 (emit-code src (make-glil-toplevel 'ref name))
677 (case context
230cfcfb
AW
678 ((drop) (emit-code #f (make-glil-call 'drop 1))))
679 (maybe-emit-return))
cf10678f
AW
680
681 ((<toplevel-set> src name exp)
682 (comp-push exp)
683 (emit-code src (make-glil-toplevel 'set name))
684 (case context
230cfcfb
AW
685 ((tail push vals)
686 (emit-code #f (make-glil-void))))
687 (maybe-emit-return))
cf10678f
AW
688
689 ((<toplevel-define> src name exp)
690 (comp-push exp)
691 (emit-code src (make-glil-toplevel 'define name))
692 (case context
230cfcfb
AW
693 ((tail push vals)
694 (emit-code #f (make-glil-void))))
695 (maybe-emit-return))
cf10678f
AW
696
697 ((<lambda>)
8a4ca0ea 698 (let ((free-locs (cdr (hashq-ref allocation x))))
66d3e9a3
AW
699 (case context
700 ((push vals tail)
9b29d607 701 (emit-code #f (flatten-lambda x #f allocation))
66d3e9a3
AW
702 (if (not (null? free-locs))
703 (begin
704 (for-each
705 (lambda (loc)
706 (pmatch loc
d773ba23 707 ((,local? ,boxed? . ,n)
66d3e9a3 708 (emit-code #f (make-glil-lexical local? #f 'ref n)))
3b24aee6 709 (else (error "bad lambda free var allocation" x loc))))
66d3e9a3 710 free-locs)
6f16379e
AW
711 (emit-code #f (make-glil-call 'make-closure
712 (length free-locs))))))))
230cfcfb 713 (maybe-emit-return))
66d3e9a3 714
93f63467 715 ((<lambda-case> src req opt rest kw inits gensyms alternate body)
899d37a6
AW
716 ;; o/~ feature on top of feature o/~
717 ;; req := (name ...)
b0c8c187 718 ;; opt := (name ...) | #f
899d37a6 719 ;; rest := name | #f
b0c8c187 720 ;; kw: (allow-other-keys? (keyword name var) ...) | #f
93f63467
AW
721 ;; gensyms: (sym ...)
722 ;; init: tree-il in context of gensyms
723 ;; gensyms map to named arguments in the following order:
899d37a6
AW
724 ;; required, optional (positional), rest, keyword.
725 (let* ((nreq (length req))
726 (nopt (if opt (length opt) 0))
727 (rest-idx (and rest (+ nreq nopt)))
b0c8c187 728 (opt-names (or opt '()))
899d37a6
AW
729 (allow-other-keys? (if kw (car kw) #f))
730 (kw-indices (map (lambda (x)
731 (pmatch x
b0c8c187 732 ((,key ,name ,var)
93f63467 733 (cons key (list-index gensyms var)))
899d37a6
AW
734 (else (error "bad kwarg" x))))
735 (if kw (cdr kw) '())))
b0c8c187
AW
736 (nargs (apply max (+ nreq nopt (if rest 1 0))
737 (map 1+ (map cdr kw-indices))))
899d37a6 738 (nlocs (cdr (hashq-ref allocation x)))
3a88cb3b 739 (alternate-label (and alternate (make-label))))
899d37a6 740 (or (= nargs
93f63467 741 (length gensyms)
b0c8c187 742 (+ nreq (length inits) (if rest 1 0)))
3b24aee6 743 (error "lambda-case gensyms don't correspond to args"
93f63467 744 req opt rest kw inits gensyms nreq nopt kw-indices nargs))
7e01997e
AW
745 ;; the prelude, to check args & reset the stack pointer,
746 ;; allowing room for locals
747 (emit-code
748 src
749 (cond
7e01997e 750 (kw
899d37a6 751 (make-glil-kw-prelude nreq nopt rest-idx kw-indices
3a88cb3b 752 allow-other-keys? nlocs alternate-label))
7e01997e 753 ((or rest opt)
3a88cb3b 754 (make-glil-opt-prelude nreq nopt rest-idx nlocs alternate-label))
7e01997e 755 (#t
3a88cb3b 756 (make-glil-std-prelude nreq nlocs alternate-label))))
7e01997e
AW
757 ;; box args if necessary
758 (for-each
759 (lambda (v)
760 (pmatch (hashq-ref (hashq-ref allocation v) self)
761 ((#t #t . ,n)
762 (emit-code #f (make-glil-lexical #t #f 'ref n))
763 (emit-code #f (make-glil-lexical #t #t 'box n)))))
93f63467 764 gensyms)
7e01997e 765 ;; write bindings info
93f63467 766 (if (not (null? gensyms))
7e01997e
AW
767 (emit-bindings
768 #f
769 (let lp ((kw (if kw (cdr kw) '()))
b0c8c187 770 (names (append (reverse opt-names) (reverse req)))
93f63467 771 (gensyms (list-tail gensyms (+ nreq nopt
7e01997e
AW
772 (if rest 1 0)))))
773 (pmatch kw
899d37a6 774 (()
93f63467 775 ;; fixme: check that gensyms is empty
899d37a6 776 (reverse (if rest (cons rest names) names)))
7e01997e 777 (((,key ,name ,var) . ,kw)
93f63467
AW
778 (if (memq var gensyms)
779 (lp kw (cons name names) (delq var gensyms))
780 (lp kw names gensyms)))
7e01997e 781 (,kw (error "bad keywords, yo" kw))))
93f63467 782 gensyms allocation self emit-code))
b0c8c187 783 ;; init optional/kw args
93f63467 784 (let lp ((inits inits) (n nreq) (gensyms (list-tail gensyms nreq)))
b0c8c187
AW
785 (cond
786 ((null? inits)) ; done
787 ((and rest-idx (= n rest-idx))
93f63467 788 (lp inits (1+ n) (cdr gensyms)))
b0c8c187 789 (#t
93f63467 790 (pmatch (hashq-ref (hashq-ref allocation (car gensyms)) self)
b0c8c187
AW
791 ((#t ,boxed? . ,n*) (guard (= n* n))
792 (let ((L (make-label)))
793 (emit-code #f (make-glil-lexical #t boxed? 'bound? n))
794 (emit-code #f (make-glil-branch 'br-if L))
795 (comp-push (car inits))
796 (emit-code #f (make-glil-lexical #t boxed? 'set n))
797 (emit-label L)
93f63467 798 (lp (cdr inits) (1+ n) (cdr gensyms))))
3b24aee6 799 (#t (error "bad arg allocation" (car gensyms) inits))))))
7e01997e
AW
800 ;; post-prelude case label for label calls
801 (emit-label (car (hashq-ref allocation x)))
8a4ca0ea 802 (comp-tail body)
93f63467 803 (if (not (null? gensyms))
8a4ca0ea 804 (emit-code #f (make-glil-unbind)))
3a88cb3b 805 (if alternate-label
8a4ca0ea 806 (begin
3a88cb3b 807 (emit-label alternate-label)
0083cb5e
AW
808 (flatten-lambda-case alternate allocation self self-label
809 fix-labels emit-code)))))
8a4ca0ea 810
93f63467 811 ((<let> src names gensyms vals body)
073bb617 812 (for-each comp-push vals)
93f63467 813 (emit-bindings src names gensyms allocation self emit-code)
cf10678f 814 (for-each (lambda (v)
9b29d607 815 (pmatch (hashq-ref (hashq-ref allocation v) self)
66d3e9a3
AW
816 ((#t #f . ,n)
817 (emit-code src (make-glil-lexical #t #f 'set n)))
818 ((#t #t . ,n)
819 (emit-code src (make-glil-lexical #t #t 'box n)))
3b24aee6 820 (,loc (error "bad let var allocation" x loc))))
93f63467 821 (reverse gensyms))
f4aa8d53 822 (comp-tail body)
fb135e12 823 (clear-stack-slots context gensyms)
cf10678f
AW
824 (emit-code #f (make-glil-unbind)))
825
60d4b224
AW
826 ((<letrec> src in-order? names gensyms vals body)
827 ;; First prepare heap storage slots.
66d3e9a3 828 (for-each (lambda (v)
9b29d607 829 (pmatch (hashq-ref (hashq-ref allocation v) self)
66d3e9a3
AW
830 ((#t #t . ,n)
831 (emit-code src (make-glil-lexical #t #t 'empty-box n)))
3b24aee6 832 (,loc (error "bad letrec var allocation" x loc))))
93f63467 833 gensyms)
60d4b224 834 ;; Even though the slots are empty, the bindings are valid.
93f63467 835 (emit-bindings src names gensyms allocation self emit-code)
60d4b224
AW
836 (cond
837 (in-order?
838 ;; For letrec*, bind values in order.
839 (for-each (lambda (name v val)
840 (pmatch (hashq-ref (hashq-ref allocation v) self)
841 ((#t #t . ,n)
842 (comp-push val)
843 (emit-code src (make-glil-lexical #t #t 'set n)))
3b24aee6 844 (,loc (error "bad letrec var allocation" x loc))))
60d4b224
AW
845 names gensyms vals))
846 (else
847 ;; But for letrec, eval all values, then bind.
848 (for-each comp-push vals)
849 (for-each (lambda (v)
850 (pmatch (hashq-ref (hashq-ref allocation v) self)
851 ((#t #t . ,n)
852 (emit-code src (make-glil-lexical #t #t 'set n)))
3b24aee6 853 (,loc (error "bad letrec var allocation" x loc))))
60d4b224 854 (reverse gensyms))))
f4aa8d53 855 (comp-tail body)
fb135e12 856 (clear-stack-slots context gensyms)
f4aa8d53
AW
857 (emit-code #f (make-glil-unbind)))
858
93f63467 859 ((<fix> src names gensyms vals body)
230cfcfb
AW
860 ;; The ideal here is to just render the lambda bodies inline, and
861 ;; wire the code together with gotos. We can do that if
862 ;; analyze-lexicals has determined that a given var has "label"
863 ;; allocation -- which is the case if it is in `fix-labels'.
864 ;;
865 ;; But even for closures that we can't inline, we can do some
866 ;; tricks to avoid heap-allocation for the binding itself. Since
867 ;; we know the vals are lambdas, we can set them to their local
868 ;; var slots first, then capture their bindings, mutating them in
869 ;; place.
7f7b85cb 870 (let ((new-RA (if (or (eq? context 'tail) RA) #f (make-label))))
230cfcfb
AW
871 (for-each
872 (lambda (x v)
873 (cond
874 ((hashq-ref allocation x)
875 ;; allocating a closure
876 (emit-code #f (flatten-lambda x v allocation))
6f16379e
AW
877 (let ((free-locs (cdr (hashq-ref allocation x))))
878 (if (not (null? free-locs))
879 ;; Need to make-closure first, so we have a fresh closure on
880 ;; the heap, but with a temporary free values.
881 (begin
882 (for-each (lambda (loc)
883 (emit-code #f (make-glil-const #f)))
884 free-locs)
885 (emit-code #f (make-glil-call 'make-closure
886 (length free-locs))))))
230cfcfb
AW
887 (pmatch (hashq-ref (hashq-ref allocation v) self)
888 ((#t #f . ,n)
889 (emit-code src (make-glil-lexical #t #f 'set n)))
3b24aee6 890 (,loc (error "bad fix var allocation" x loc))))
230cfcfb
AW
891 (else
892 ;; labels allocation: emit label & body, but jump over it
893 (let ((POST (make-label)))
894 (emit-branch #f 'br POST)
8a4ca0ea
AW
895 (let lp ((lcase (lambda-body x)))
896 (if lcase
897 (record-case lcase
93f63467 898 ((<lambda-case> src req gensyms body alternate)
8a4ca0ea
AW
899 (emit-label (car (hashq-ref allocation lcase)))
900 ;; FIXME: opt & kw args in the bindings
93f63467 901 (emit-bindings #f req gensyms allocation self emit-code)
8a4ca0ea
AW
902 (if src
903 (emit-code #f (make-glil-source src)))
904 (comp-fix body (or RA new-RA))
905 (emit-code #f (make-glil-unbind))
3a88cb3b 906 (lp alternate)))
8a4ca0ea 907 (emit-label POST)))))))
230cfcfb 908 vals
93f63467 909 gensyms)
230cfcfb 910 ;; Emit bindings metadata for closures
93f63467
AW
911 (let ((binds (let lp ((out '()) (gensyms gensyms) (names names))
912 (cond ((null? gensyms) (reverse! out))
913 ((assq (car gensyms) fix-labels)
914 (lp out (cdr gensyms) (cdr names)))
230cfcfb 915 (else
93f63467
AW
916 (lp (acons (car gensyms) (car names) out)
917 (cdr gensyms) (cdr names)))))))
230cfcfb
AW
918 (emit-bindings src (map cdr binds) (map car binds)
919 allocation self emit-code))
920 ;; Now go back and fix up the bindings for closures.
921 (for-each
922 (lambda (x v)
923 (let ((free-locs (if (hashq-ref allocation x)
8a4ca0ea 924 (cdr (hashq-ref allocation x))
230cfcfb
AW
925 ;; can hit this latter case for labels allocation
926 '())))
927 (if (not (null? free-locs))
928 (begin
929 (for-each
930 (lambda (loc)
931 (pmatch loc
d773ba23 932 ((,local? ,boxed? . ,n)
230cfcfb 933 (emit-code #f (make-glil-lexical local? #f 'ref n)))
3b24aee6 934 (else (error "bad free var allocation" x loc))))
230cfcfb 935 free-locs)
230cfcfb
AW
936 (pmatch (hashq-ref (hashq-ref allocation v) self)
937 ((#t #f . ,n)
938 (emit-code #f (make-glil-lexical #t #f 'fix n)))
3b24aee6 939 (,loc (error "bad fix var allocation" x loc)))))))
230cfcfb 940 vals
93f63467 941 gensyms)
230cfcfb 942 (comp-tail body)
7f7b85cb
AW
943 (if new-RA
944 (emit-label new-RA))
fb135e12 945 (clear-stack-slots context gensyms)
230cfcfb 946 (emit-code #f (make-glil-unbind))))
c21c89b1 947
8a4ca0ea
AW
948 ((<let-values> src exp body)
949 (record-case body
93f63467 950 ((<lambda-case> req opt kw rest gensyms body alternate)
3a88cb3b 951 (if (or opt kw alternate)
8a4ca0ea
AW
952 (error "unexpected lambda-case in let-values" x))
953 (let ((MV (make-label)))
954 (comp-vals exp MV)
955 (emit-code #f (make-glil-const 1))
956 (emit-label MV)
957 (emit-code src (make-glil-mv-bind
958 (vars->bind-list
959 (append req (if rest (list rest) '()))
93f63467 960 gensyms allocation self)
8a4ca0ea
AW
961 (and rest #t)))
962 (for-each (lambda (v)
963 (pmatch (hashq-ref (hashq-ref allocation v) self)
964 ((#t #f . ,n)
965 (emit-code src (make-glil-lexical #t #f 'set n)))
966 ((#t #t . ,n)
967 (emit-code src (make-glil-lexical #t #t 'box n)))
3b24aee6 968 (,loc (error "bad let-values var allocation" x loc))))
93f63467 969 (reverse gensyms))
8a4ca0ea 970 (comp-tail body)
fb135e12 971 (clear-stack-slots context gensyms)
c6601f10
AW
972 (emit-code #f (make-glil-unbind))))))
973
974 ;; much trickier than i thought this would be, at first, due to the need
975 ;; to have body's return value(s) on the stack while the unwinder runs,
976 ;; then proceed with returning or dropping or what-have-you, interacting
977 ;; with RA and MVRA. What have you, I say.
8da6ab34 978 ((<dynwind> src body winder unwinder)
c6601f10
AW
979 (comp-push winder)
980 (comp-push unwinder)
981 (comp-drop (make-application src winder '()))
982 (emit-code #f (make-glil-call 'wind 2))
983
984 (case context
985 ((tail)
986 (let ((MV (make-label)))
987 (comp-vals body MV)
988 ;; one value: unwind...
989 (emit-code #f (make-glil-call 'unwind 0))
990 (comp-drop (make-application src unwinder '()))
991 ;; ...and return the val
992 (emit-code #f (make-glil-call 'return 1))
993
994 (emit-label MV)
995 ;; multiple values: unwind...
996 (emit-code #f (make-glil-call 'unwind 0))
997 (comp-drop (make-application src unwinder '()))
998 ;; and return the values.
999 (emit-code #f (make-glil-call 'return/nvalues 1))))
1000
1001 ((push)
1002 ;; we only want one value. so ask for one value
1003 (comp-push body)
1004 ;; and unwind, leaving the val on the stack
1005 (emit-code #f (make-glil-call 'unwind 0))
1006 (comp-drop (make-application src unwinder '())))
1007
1008 ((vals)
1009 (let ((MV (make-label)))
1010 (comp-vals body MV)
1011 ;; one value: push 1 and fall through to MV case
1012 (emit-code #f (make-glil-const 1))
1013
1014 (emit-label MV)
1015 ;; multiple values: unwind...
1016 (emit-code #f (make-glil-call 'unwind 0))
1017 (comp-drop (make-application src unwinder '()))
1018 ;; and goto the MVRA.
1019 (emit-branch #f 'br MVRA)))
1020
1021 ((drop)
1022 ;; compile body, discarding values. then unwind...
1023 (comp-drop body)
1024 (emit-code #f (make-glil-call 'unwind 0))
1025 (comp-drop (make-application src unwinder '()))
1026 ;; and fall through, or goto RA if there is one.
b50511b4
AW
1027 (if RA
1028 (emit-branch #f 'br RA)))))
1029
1030 ((<dynlet> src fluids vals body)
1031 (for-each comp-push fluids)
1032 (for-each comp-push vals)
1033 (emit-code #f (make-glil-call 'wind-fluids (length fluids)))
1034
1035 (case context
1036 ((tail)
1037 (let ((MV (make-label)))
1038 ;; NB: in tail case, it is possible to preserve asymptotic tail
1039 ;; recursion, via merging unwind-fluids structures -- but we'd need
1040 ;; to compile in the body twice (once in tail context, assuming the
1041 ;; caller unwinds, and once with this trampoline thing, unwinding
1042 ;; ourselves).
1043 (comp-vals body MV)
1044 ;; one value: unwind and return
1045 (emit-code #f (make-glil-call 'unwind-fluids 0))
1046 (emit-code #f (make-glil-call 'return 1))
1047
1048 (emit-label MV)
1049 ;; multiple values: unwind and return values
1050 (emit-code #f (make-glil-call 'unwind-fluids 0))
1051 (emit-code #f (make-glil-call 'return/nvalues 1))))
1052
1053 ((push)
1054 (comp-push body)
1055 (emit-code #f (make-glil-call 'unwind-fluids 0)))
1056
1057 ((vals)
1058 (let ((MV (make-label)))
1059 (comp-vals body MV)
1060 ;; one value: push 1 and fall through to MV case
1061 (emit-code #f (make-glil-const 1))
1062
1063 (emit-label MV)
1064 ;; multiple values: unwind and goto MVRA
1065 (emit-code #f (make-glil-call 'unwind-fluids 0))
1066 (emit-branch #f 'br MVRA)))
1067
1068 ((drop)
1069 ;; compile body, discarding values. then unwind...
1070 (comp-drop body)
1071 (emit-code #f (make-glil-call 'unwind-fluids 0))
1072 ;; and fall through, or goto RA if there is one.
c6601f10
AW
1073 (if RA
1074 (emit-branch #f 'br RA)))))
1075
706a705e
AW
1076 ((<dynref> src fluid)
1077 (case context
1078 ((drop)
1079 (comp-drop fluid))
1080 ((push vals tail)
1081 (comp-push fluid)
1082 (emit-code #f (make-glil-call 'fluid-ref 1))))
1083 (maybe-emit-return))
1084
1085 ((<dynset> src fluid exp)
1086 (comp-push fluid)
1087 (comp-push exp)
1088 (emit-code #f (make-glil-call 'fluid-set 2))
1089 (case context
1090 ((push vals tail)
1091 (emit-code #f (make-glil-void))))
1092 (maybe-emit-return))
1093
c6601f10
AW
1094 ;; What's the deal here? The deal is that we are compiling the start of a
1095 ;; delimited continuation. We try to avoid heap allocation in the normal
1096 ;; case; so the body is an expression, not a thunk, and we try to render
1097 ;; the handler inline. Also we did some analysis, in analyze.scm, so that
1098 ;; if the continuation isn't referenced, we don't reify it. This makes it
1099 ;; possible to implement catch and throw with delimited continuations,
1100 ;; without any overhead.
07a0c7d5 1101 ((<prompt> src tag body handler)
c6601f10
AW
1102 (let ((H (make-label))
1103 (POST (make-label))
c6601f10
AW
1104 (escape-only? (hashq-ref allocation x)))
1105 ;; First, set up the prompt.
1106 (comp-push tag)
ea6b18e8 1107 (emit-code src (make-glil-prompt H escape-only?))
c6601f10
AW
1108
1109 ;; Then we compile the body, with its normal return path, unwinding
1110 ;; before proceeding.
1111 (case context
1112 ((tail)
1113 (let ((MV (make-label)))
1114 (comp-vals body MV)
1115 ;; one value: unwind and return
1116 (emit-code #f (make-glil-call 'unwind 0))
1117 (emit-code #f (make-glil-call 'return 1))
1118 ;; multiple values: unwind and return
1119 (emit-label MV)
1120 (emit-code #f (make-glil-call 'unwind 0))
1121 (emit-code #f (make-glil-call 'return/nvalues 1))))
1122
1123 ((push)
1124 ;; we only want one value. so ask for one value, unwind, and jump to
1125 ;; post
1126 (comp-push body)
1127 (emit-code #f (make-glil-call 'unwind 0))
9dadfa47 1128 (emit-branch #f 'br (or RA POST)))
c6601f10
AW
1129
1130 ((vals)
1131 (let ((MV (make-label)))
1132 (comp-vals body MV)
1133 ;; one value: push 1 and fall through to MV case
1134 (emit-code #f (make-glil-const 1))
1135 ;; multiple values: unwind and goto MVRA
1136 (emit-label MV)
1137 (emit-code #f (make-glil-call 'unwind 0))
1138 (emit-branch #f 'br MVRA)))
1139
1140 ((drop)
1141 ;; compile body, discarding values, then unwind & fall through.
1142 (comp-drop body)
1143 (emit-code #f (make-glil-call 'unwind 0))
1144 (emit-branch #f 'br (or RA POST))))
1145
c6601f10 1146 (emit-label H)
ea6b18e8
AW
1147 ;; Now the handler. The stack is now made up of the continuation, and
1148 ;; then the args to the continuation (pushed separately), and then the
1149 ;; number of args, including the continuation.
1150 (record-case handler
93f63467 1151 ((<lambda-case> req opt kw rest gensyms body alternate)
ea6b18e8
AW
1152 (if (or opt kw alternate)
1153 (error "unexpected lambda-case in prompt" x))
1154 (emit-code src (make-glil-mv-bind
1155 (vars->bind-list
1156 (append req (if rest (list rest) '()))
93f63467 1157 gensyms allocation self)
ea6b18e8
AW
1158 (and rest #t)))
1159 (for-each (lambda (v)
1160 (pmatch (hashq-ref (hashq-ref allocation v) self)
1161 ((#t #f . ,n)
1162 (emit-code src (make-glil-lexical #t #f 'set n)))
1163 ((#t #t . ,n)
1164 (emit-code src (make-glil-lexical #t #t 'box n)))
3b24aee6
AW
1165 (,loc
1166 (error "bad prompt handler arg allocation" x loc))))
93f63467 1167 (reverse gensyms))
ea6b18e8
AW
1168 (comp-tail body)
1169 (emit-code #f (make-glil-unbind))))
c6601f10 1170
9dadfa47
AW
1171 (if (and (not RA)
1172 (or (eq? context 'push) (eq? context 'drop)))
c6601f10
AW
1173 (emit-label POST))))
1174
2d026f04 1175 ((<abort> src tag args tail)
c6601f10 1176 (comp-push tag)
6e84cb95 1177 (for-each comp-push args)
2d026f04 1178 (comp-push tail)
eaefabee
AW
1179 (emit-code src (make-glil-call 'abort (length args)))
1180 ;; so, the abort can actually return. if it does, the values will be on
1181 ;; the stack, then the MV marker, just as in an MV context.
1182 (case context
1183 ((tail)
1184 ;; Return values.
1185 (emit-code #f (make-glil-call 'return/nvalues 1)))
1186 ((drop)
1187 ;; Drop all values and goto RA, or otherwise fall through.
05c51bcf 1188 (emit-code #f (make-glil-mv-bind 0 #f))
eaefabee
AW
1189 (if RA (emit-branch #f 'br RA)))
1190 ((push)
1191 ;; Truncate to one value.
05c51bcf 1192 (emit-code #f (make-glil-mv-bind 1 #f)))
eaefabee
AW
1193 ((vals)
1194 ;; Go to MVRA.
1195 (emit-branch #f 'br MVRA)))))))