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