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