Commit | Line | Data |
---|---|---|
f1d7723b AW |
1 | ;;; Guile VM assembler |
2 | ||
5a9c6dcb | 3 | ;; Copyright (C) 2001, 2009, 2010 Free Software Foundation, Inc. |
f1d7723b | 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 | |
f1d7723b AW |
18 | |
19 | ;;; Code: | |
20 | ||
21 | (define-module (language glil compile-assembly) | |
22 | #:use-module (system base syntax) | |
23 | #:use-module (system base pmatch) | |
24 | #:use-module (language glil) | |
25 | #:use-module (language assembly) | |
26 | #:use-module (system vm instruction) | |
27 | #:use-module ((system vm program) #:select (make-binding)) | |
f1d7723b AW |
28 | #:use-module (ice-9 receive) |
29 | #:use-module ((srfi srfi-1) #:select (fold)) | |
782a82ee | 30 | #:use-module (rnrs bytevector) |
f1d7723b AW |
31 | #:export (compile-assembly)) |
32 | ||
33 | ;; Variable cache cells go in the object table, and serialize as their | |
34 | ;; keys. The reason we wrap the keys in these records is so they don't | |
35 | ;; compare as `equal?' to other objects in the object table. | |
36 | ;; | |
37 | ;; `key' is either a symbol or the list (MODNAME SYM PUBLIC?) | |
38 | ||
39 | (define-record <variable-cache-cell> key) | |
40 | ||
41 | ;; Subprograms can be loaded into an object table as well. We need a | |
2cf1705c AW |
42 | ;; disjoint type here too. (Subprograms have their own object tables -- |
43 | ;; though probably we should just make one table per compilation unit.) | |
f1d7723b | 44 | |
2cf1705c | 45 | (define-record <subprogram> table prog) |
f1d7723b AW |
46 | |
47 | ||
028e3d06 AW |
48 | (define (limn-sources sources) |
49 | (let lp ((in sources) (out '()) (filename #f)) | |
50 | (if (null? in) | |
51 | (reverse! out) | |
52 | (let ((addr (caar in)) | |
53 | (new-filename (assq-ref (cdar in ) 'filename)) | |
54 | (line (assq-ref (cdar in) 'line)) | |
55 | (column (assq-ref (cdar in) 'column))) | |
56 | (cond | |
57 | ((not (equal? new-filename filename)) | |
58 | (lp (cdr in) | |
59 | `((,addr . (,line . ,column)) | |
ff33605d | 60 | (filename . ,new-filename) |
028e3d06 AW |
61 | . ,out) |
62 | new-filename)) | |
63 | ((or (null? out) (not (equal? (cdar out) `(,line . ,column)))) | |
64 | (lp (cdr in) | |
65 | `((,addr . (,line . ,column)) | |
66 | . ,out) | |
67 | filename)) | |
68 | (else | |
69 | (lp (cdr in) out filename))))))) | |
70 | ||
6c6a4439 | 71 | (define (make-meta bindings sources arities tail) |
8986ff7a AW |
72 | ;; sounds silly, but the only case in which we have no arities is when |
73 | ;; compiling a meta procedure. | |
74 | (if (and (null? bindings) (null? sources) (null? arities) (null? tail)) | |
f1d7723b | 75 | #f |
ac47d5f6 | 76 | (compile-assembly |
56164a5a | 77 | (make-glil-program '() |
ac47d5f6 | 78 | (list |
6c6a4439 | 79 | (make-glil-const `(,bindings ,sources ,arities ,@tail)) |
131f7d6c | 80 | (make-glil-call 'return 1)))))) |
f1d7723b AW |
81 | |
82 | ;; A functional stack of names of live variables. | |
66d3e9a3 AW |
83 | (define (make-open-binding name boxed? index) |
84 | (list name boxed? index)) | |
f1d7723b AW |
85 | (define (make-closed-binding open-binding start end) |
86 | (make-binding (car open-binding) (cadr open-binding) | |
87 | (caddr open-binding) start end)) | |
cf10678f | 88 | (define (open-binding bindings vars start) |
f1d7723b AW |
89 | (cons |
90 | (acons start | |
91 | (map | |
92 | (lambda (v) | |
93 | (pmatch v | |
66d3e9a3 AW |
94 | ((,name ,boxed? ,i) |
95 | (make-open-binding name boxed? i)) | |
cf10678f | 96 | (else (error "unknown binding type" v)))) |
f1d7723b AW |
97 | vars) |
98 | (car bindings)) | |
99 | (cdr bindings))) | |
100 | (define (close-binding bindings end) | |
101 | (pmatch bindings | |
102 | ((((,start . ,closing) . ,open) . ,closed) | |
103 | (cons open | |
104 | (fold (lambda (o tail) | |
105 | ;; the cons is for dsu sort | |
106 | (acons start (make-closed-binding o start end) | |
107 | tail)) | |
108 | closed | |
109 | closing))) | |
110 | (else (error "broken bindings" bindings)))) | |
111 | (define (close-all-bindings bindings end) | |
112 | (if (null? (car bindings)) | |
113 | (map cdr | |
114 | (stable-sort (reverse (cdr bindings)) | |
115 | (lambda (x y) (< (car x) (car y))))) | |
116 | (close-all-bindings (close-binding bindings end) end))) | |
117 | ||
118 | ;; A functional object table. | |
ac47d5f6 | 119 | (define *module* 1) |
53e28ed9 AW |
120 | (define (assoc-ref-or-acons alist x make-y) |
121 | (cond ((assoc-ref alist x) | |
f1d7723b AW |
122 | => (lambda (y) (values y alist))) |
123 | (else | |
124 | (let ((y (make-y x alist))) | |
53e28ed9 | 125 | (values y (acons x y alist)))))) |
f1d7723b | 126 | (define (object-index-and-alist x alist) |
53e28ed9 | 127 | (assoc-ref-or-acons alist x |
f1d7723b | 128 | (lambda (x alist) |
ac47d5f6 | 129 | (+ (length alist) *module*)))) |
ac47d5f6 AW |
130 | (define (make-object-table objects) |
131 | (and (not (null? objects)) | |
132 | (list->vector (cons #f objects)))) | |
f1d7723b | 133 | |
df435c83 | 134 | ;; A functional arities thingamajiggy. |
899d37a6 | 135 | ;; arities := ((ip nreq [[nopt] [[rest] [kw]]]]) ...) |
df435c83 | 136 | (define (open-arity addr nreq nopt rest kw arities) |
6c6a4439 AW |
137 | (cons |
138 | (cond | |
899d37a6 AW |
139 | (kw (list addr nreq nopt rest kw)) |
140 | (rest (list addr nreq nopt rest)) | |
6c6a4439 | 141 | (nopt (list addr nreq nopt)) |
258344b4 | 142 | (nreq (list addr nreq)) |
6c6a4439 AW |
143 | (else (list addr))) |
144 | arities)) | |
df435c83 AW |
145 | (define (close-arity addr arities) |
146 | (pmatch arities | |
147 | (() '()) | |
148 | (((,start . ,tail) . ,rest) | |
149 | `((,start ,addr . ,tail) . ,rest)) | |
150 | (else (error "bad arities" arities)))) | |
151 | (define (begin-arity end start nreq nopt rest kw arities) | |
152 | (open-arity start nreq nopt rest kw (close-arity end arities))) | |
153 | ||
154 | (define (compile-assembly glil) | |
155 | (receive (code . _) | |
156 | (glil->assembly glil #t '(()) '() '() #f '() -1) | |
157 | (car code))) | |
6c6a4439 | 158 | |
476e3572 | 159 | (define (glil->assembly glil toplevel? bindings |
6c6a4439 | 160 | source-alist label-alist object-alist arities addr) |
f1d7723b | 161 | (define (emit-code x) |
6c6a4439 | 162 | (values x bindings source-alist label-alist object-alist arities)) |
f1d7723b | 163 | (define (emit-code/object x object-alist) |
6c6a4439 | 164 | (values x bindings source-alist label-alist object-alist arities)) |
899d37a6 | 165 | (define (emit-code/arity x nreq nopt rest kw) |
6c6a4439 | 166 | (values x bindings source-alist label-alist object-alist |
df435c83 | 167 | (begin-arity addr (addr+ addr x) nreq nopt rest kw arities))) |
258344b4 | 168 | |
f1d7723b | 169 | (record-case glil |
56164a5a | 170 | ((<glil-program> meta body) |
476e3572 AW |
171 | (define (process-body) |
172 | (let lp ((body body) (code '()) (bindings '(())) (source-alist '()) | |
6c6a4439 AW |
173 | (label-alist '()) (object-alist (if toplevel? #f '())) |
174 | (arities '()) (addr 0)) | |
476e3572 AW |
175 | (cond |
176 | ((null? body) | |
177 | (values (reverse code) | |
178 | (close-all-bindings bindings addr) | |
179 | (limn-sources (reverse! source-alist)) | |
180 | (reverse label-alist) | |
181 | (and object-alist (map car (reverse object-alist))) | |
df435c83 | 182 | (reverse (close-arity addr arities)) |
476e3572 AW |
183 | addr)) |
184 | (else | |
6c6a4439 AW |
185 | (receive (subcode bindings source-alist label-alist object-alist |
186 | arities) | |
476e3572 | 187 | (glil->assembly (car body) #f bindings |
6c6a4439 AW |
188 | source-alist label-alist object-alist |
189 | arities addr) | |
476e3572 | 190 | (lp (cdr body) (append (reverse subcode) code) |
6c6a4439 | 191 | bindings source-alist label-alist object-alist arities |
476e3572 AW |
192 | (addr+ addr subcode))))))) |
193 | ||
6c6a4439 | 194 | (receive (code bindings sources labels objects arities len) |
476e3572 | 195 | (process-body) |
6c6a4439 | 196 | (let* ((meta (make-meta bindings sources arities meta)) |
28b119ee | 197 | (meta-pad (if meta (modulo (- 8 (modulo len 8)) 8) 0)) |
56164a5a | 198 | (prog `(load-program ,labels |
28b119ee AW |
199 | ,(+ len meta-pad) |
200 | ,meta | |
201 | ,@code | |
202 | ,@(if meta | |
203 | (make-list meta-pad '(nop)) | |
204 | '())))) | |
476e3572 AW |
205 | (cond |
206 | (toplevel? | |
207 | ;; toplevel bytecode isn't loaded by the vm, no way to do | |
208 | ;; object table or closure capture (not in the bytecode, | |
209 | ;; anyway) | |
210 | (emit-code (align-program prog addr))) | |
211 | (else | |
9efc2d14 | 212 | (let ((table (make-object-table objects))) |
53e28ed9 | 213 | (cond |
476e3572 AW |
214 | (object-alist |
215 | ;; if we are being compiled from something with an object | |
216 | ;; table, cache the program there | |
217 | (receive (i object-alist) | |
218 | (object-index-and-alist (make-subprogram table prog) | |
219 | object-alist) | |
220 | (emit-code/object `(,(if (< i 256) | |
221 | `(object-ref ,i) | |
222 | `(long-object-ref ,(quotient i 256) | |
223 | ,(modulo i 256)))) | |
224 | object-alist))) | |
53e28ed9 | 225 | (else |
476e3572 | 226 | ;; otherwise emit a load directly |
9efc2d14 AW |
227 | (let ((table-code (dump-object table addr))) |
228 | (emit-code | |
229 | `(,@table-code | |
230 | ,@(align-program prog (addr+ addr table-code))))))))))))) | |
f1d7723b | 231 | |
258344b4 AW |
232 | ((<glil-std-prelude> nreq nlocs else-label) |
233 | (emit-code/arity | |
234 | `(,(if else-label | |
235 | `(br-if-nargs-ne ,(quotient nreq 256) | |
236 | ,(modulo nreq 256) | |
237 | ,else-label) | |
238 | `(assert-nargs-ee ,(quotient nreq 256) | |
239 | ,(modulo nreq 256))) | |
240 | (reserve-locals ,(quotient nlocs 256) | |
241 | ,(modulo nlocs 256))) | |
242 | nreq #f #f #f)) | |
243 | ||
899d37a6 | 244 | ((<glil-opt-prelude> nreq nopt rest nlocs else-label) |
258344b4 AW |
245 | (let ((bind-required |
246 | (if else-label | |
247 | `((br-if-nargs-lt ,(quotient nreq 256) | |
248 | ,(modulo nreq 256) | |
249 | ,else-label)) | |
250 | `((assert-nargs-ge ,(quotient nreq 256) | |
251 | ,(modulo nreq 256))))) | |
252 | (bind-optionals | |
253 | (if (zero? nopt) | |
254 | '() | |
255 | `((bind-optionals ,(quotient (+ nopt nreq) 256) | |
256 | ,(modulo (+ nreq nopt) 256))))) | |
257 | (bind-rest | |
258 | (cond | |
899d37a6 AW |
259 | (rest |
260 | `((push-rest ,(quotient (+ nreq nopt) 256) | |
258344b4 AW |
261 | ,(modulo (+ nreq nopt) 256)))) |
262 | (else | |
263 | (if else-label | |
7e01997e | 264 | `((br-if-nargs-gt ,(quotient (+ nreq nopt) 256) |
258344b4 AW |
265 | ,(modulo (+ nreq nopt) 256) |
266 | ,else-label)) | |
267 | `((assert-nargs-ee ,(quotient (+ nreq nopt) 256) | |
268 | ,(modulo (+ nreq nopt) 256)))))))) | |
269 | (emit-code/arity | |
270 | `(,@bind-required | |
271 | ,@bind-optionals | |
272 | ,@bind-rest | |
273 | (reserve-locals ,(quotient nlocs 256) | |
274 | ,(modulo nlocs 256))) | |
899d37a6 | 275 | nreq nopt rest #f))) |
258344b4 | 276 | |
899d37a6 | 277 | ((<glil-kw-prelude> nreq nopt rest kw allow-other-keys? nlocs else-label) |
258344b4 | 278 | (receive (kw-idx object-alist) |
b0c8c187 AW |
279 | (object-index-and-alist kw object-alist) |
280 | (let* ((bind-required | |
281 | (if else-label | |
282 | `((br-if-nargs-lt ,(quotient nreq 256) | |
283 | ,(modulo nreq 256) | |
284 | ,else-label)) | |
285 | `((assert-nargs-ge ,(quotient nreq 256) | |
286 | ,(modulo nreq 256))))) | |
287 | (ntotal (apply max (+ nreq nopt) (map 1+ (map cdr kw)))) | |
288 | (bind-optionals-and-shuffle | |
289 | `((bind-optionals/shuffle | |
290 | ,(quotient nreq 256) | |
291 | ,(modulo nreq 256) | |
292 | ,(quotient (+ nreq nopt) 256) | |
293 | ,(modulo (+ nreq nopt) 256) | |
294 | ,(quotient ntotal 256) | |
295 | ,(modulo ntotal 256)))) | |
296 | (bind-kw | |
297 | ;; when this code gets called, all optionals are filled | |
298 | ;; in, space has been made for kwargs, and the kwargs | |
299 | ;; themselves have been shuffled above the slots for all | |
300 | ;; req/opt/kwargs locals. | |
301 | `((bind-kwargs | |
302 | ,(quotient kw-idx 256) | |
303 | ,(modulo kw-idx 256) | |
304 | ,(quotient ntotal 256) | |
305 | ,(modulo ntotal 256) | |
306 | ,(logior (if rest 2 0) | |
307 | (if allow-other-keys? 1 0))))) | |
308 | (bind-rest | |
309 | (if rest | |
310 | `((bind-rest ,(quotient ntotal 256) | |
311 | ,(modulo ntotal 256) | |
312 | ,(quotient rest 256) | |
313 | ,(modulo rest 256))) | |
314 | '()))) | |
258344b4 AW |
315 | |
316 | (let ((code `(,@bind-required | |
317 | ,@bind-optionals-and-shuffle | |
318 | ,@bind-kw | |
319 | ,@bind-rest | |
320 | (reserve-locals ,(quotient nlocs 256) | |
321 | ,(modulo nlocs 256))))) | |
322 | (values code bindings source-alist label-alist object-alist | |
df435c83 | 323 | (begin-arity addr (addr+ addr code) nreq nopt rest |
b0c8c187 AW |
324 | (and kw (cons allow-other-keys? kw)) |
325 | arities)))))) | |
258344b4 | 326 | |
f1d7723b AW |
327 | ((<glil-bind> vars) |
328 | (values '() | |
cf10678f | 329 | (open-binding bindings vars addr) |
f1d7723b AW |
330 | source-alist |
331 | label-alist | |
6c6a4439 AW |
332 | object-alist |
333 | arities)) | |
f1d7723b AW |
334 | |
335 | ((<glil-mv-bind> vars rest) | |
336 | (values `((truncate-values ,(length vars) ,(if rest 1 0))) | |
cf10678f | 337 | (open-binding bindings vars addr) |
f1d7723b AW |
338 | source-alist |
339 | label-alist | |
6c6a4439 AW |
340 | object-alist |
341 | arities)) | |
f1d7723b AW |
342 | |
343 | ((<glil-unbind>) | |
344 | (values '() | |
345 | (close-binding bindings addr) | |
346 | source-alist | |
347 | label-alist | |
6c6a4439 AW |
348 | object-alist |
349 | arities)) | |
f1d7723b | 350 | |
028e3d06 | 351 | ((<glil-source> props) |
f1d7723b AW |
352 | (values '() |
353 | bindings | |
028e3d06 | 354 | (acons addr props source-alist) |
f1d7723b | 355 | label-alist |
6c6a4439 AW |
356 | object-alist |
357 | arities)) | |
f1d7723b AW |
358 | |
359 | ((<glil-void>) | |
360 | (emit-code '((void)))) | |
361 | ||
362 | ((<glil-const> obj) | |
363 | (cond | |
4b318482 | 364 | ((object->assembly obj) |
f1d7723b AW |
365 | => (lambda (code) |
366 | (emit-code (list code)))) | |
367 | ((not object-alist) | |
368 | (emit-code (dump-object obj addr))) | |
369 | (else | |
370 | (receive (i object-alist) | |
371 | (object-index-and-alist obj object-alist) | |
a9b0f876 AW |
372 | (emit-code/object (if (< i 256) |
373 | `((object-ref ,i)) | |
374 | `((long-object-ref ,(quotient i 256) | |
375 | ,(modulo i 256)))) | |
f1d7723b AW |
376 | object-alist))))) |
377 | ||
66d3e9a3 AW |
378 | ((<glil-lexical> local? boxed? op index) |
379 | (emit-code | |
80545853 AW |
380 | (if local? |
381 | (if (< index 256) | |
c21c89b1 AW |
382 | (case op |
383 | ((ref) (if boxed? | |
384 | `((local-boxed-ref ,index)) | |
385 | `((local-ref ,index)))) | |
386 | ((set) (if boxed? | |
387 | `((local-boxed-set ,index)) | |
388 | `((local-set ,index)))) | |
389 | ((box) `((box ,index))) | |
390 | ((empty-box) `((empty-box ,index))) | |
391 | ((fix) `((fix-closure 0 ,index))) | |
b0c8c187 AW |
392 | ((bound?) (if boxed? |
393 | `((local-ref ,index) | |
394 | (variable-bound?)) | |
395 | `((local-bound? ,index)))) | |
c21c89b1 | 396 | (else (error "what" op))) |
84012ef4 LC |
397 | (let ((a (quotient index 256)) |
398 | (b (modulo index 256))) | |
c21c89b1 AW |
399 | `((,(case op |
400 | ((ref) | |
401 | (if boxed? | |
402 | `((long-local-ref ,a ,b) | |
403 | (variable-ref)) | |
404 | `((long-local-ref ,a ,b)))) | |
405 | ((set) | |
406 | (if boxed? | |
407 | `((long-local-ref ,a ,b) | |
408 | (variable-set)) | |
409 | `((long-local-set ,a ,b)))) | |
410 | ((box) | |
411 | `((make-variable) | |
412 | (variable-set) | |
413 | (long-local-set ,a ,b))) | |
414 | ((empty-box) | |
415 | `((make-variable) | |
416 | (long-local-set ,a ,b))) | |
417 | ((fix) | |
418 | `((fix-closure ,a ,b))) | |
b0c8c187 AW |
419 | ((bound?) |
420 | (if boxed? | |
421 | `((long-local-ref ,a ,b) | |
422 | (variable-bound?)) | |
423 | `((long-local-bound? ,a ,b)))) | |
c21c89b1 AW |
424 | (else (error "what" op))) |
425 | ,index)))) | |
80545853 | 426 | `((,(case op |
57ab0671 AW |
427 | ((ref) (if boxed? 'free-boxed-ref 'free-ref)) |
428 | ((set) (if boxed? 'free-boxed-set (error "what." glil))) | |
80545853 AW |
429 | (else (error "what" op))) |
430 | ,index))))) | |
66d3e9a3 | 431 | |
f1d7723b AW |
432 | ((<glil-toplevel> op name) |
433 | (case op | |
434 | ((ref set) | |
435 | (cond | |
436 | ((not object-alist) | |
437 | (emit-code `(,@(dump-object name addr) | |
438 | (link-now) | |
439 | ,(case op | |
440 | ((ref) '(variable-ref)) | |
441 | ((set) '(variable-set)))))) | |
442 | (else | |
443 | (receive (i object-alist) | |
444 | (object-index-and-alist (make-variable-cache-cell name) | |
445 | object-alist) | |
a9b0f876 AW |
446 | (emit-code/object (if (< i 256) |
447 | `((,(case op | |
448 | ((ref) 'toplevel-ref) | |
449 | ((set) 'toplevel-set)) | |
450 | ,i)) | |
451 | `((,(case op | |
452 | ((ref) 'long-toplevel-ref) | |
453 | ((set) 'long-toplevel-set)) | |
454 | ,(quotient i 256) | |
455 | ,(modulo i 256)))) | |
f1d7723b AW |
456 | object-alist))))) |
457 | ((define) | |
94ff26b9 AW |
458 | (emit-code `(,@(dump-object name addr) |
459 | (define)))) | |
f1d7723b AW |
460 | (else |
461 | (error "unknown toplevel var kind" op name)))) | |
462 | ||
463 | ((<glil-module> op mod name public?) | |
464 | (let ((key (list mod name public?))) | |
465 | (case op | |
466 | ((ref set) | |
467 | (cond | |
468 | ((not object-alist) | |
469 | (emit-code `(,@(dump-object key addr) | |
470 | (link-now) | |
471 | ,(case op | |
472 | ((ref) '(variable-ref)) | |
473 | ((set) '(variable-set)))))) | |
474 | (else | |
475 | (receive (i object-alist) | |
53e28ed9 | 476 | (object-index-and-alist (make-variable-cache-cell key) |
f1d7723b AW |
477 | object-alist) |
478 | (emit-code/object (case op | |
479 | ((ref) `((toplevel-ref ,i))) | |
480 | ((set) `((toplevel-set ,i)))) | |
481 | object-alist))))) | |
482 | (else | |
483 | (error "unknown module var kind" op key))))) | |
484 | ||
485 | ((<glil-label> label) | |
e5dc27b8 AW |
486 | (let ((code (align-block addr))) |
487 | (values code | |
488 | bindings | |
489 | source-alist | |
490 | (acons label (addr+ addr code) label-alist) | |
6c6a4439 AW |
491 | object-alist |
492 | arities))) | |
f1d7723b AW |
493 | |
494 | ((<glil-branch> inst label) | |
495 | (emit-code `((,inst ,label)))) | |
496 | ||
497 | ;; nargs is number of stack args to insn. probably should rename. | |
498 | ((<glil-call> inst nargs) | |
499 | (if (not (instruction? inst)) | |
500 | (error "Unknown instruction:" inst)) | |
501 | (let ((pops (instruction-pops inst))) | |
502 | (cond ((< pops 0) | |
c11f46af AW |
503 | (case (instruction-length inst) |
504 | ((1) (emit-code `((,inst ,nargs)))) | |
505 | ((2) (emit-code `((,inst ,(quotient nargs 256) | |
506 | ,(modulo nargs 256))))) | |
507 | (else (error "Unknown length for variable-arg instruction:" | |
508 | inst (instruction-length inst))))) | |
f1d7723b AW |
509 | ((= pops nargs) |
510 | (emit-code `((,inst)))) | |
511 | (else | |
512 | (error "Wrong number of stack arguments to instruction:" inst nargs))))) | |
513 | ||
514 | ((<glil-mv-call> nargs ra) | |
515 | (emit-code `((mv-call ,nargs ,ra)))))) | |
516 | ||
f1d7723b AW |
517 | (define (dump-object x addr) |
518 | (define (too-long x) | |
519 | (error (string-append x " too long"))) | |
520 | ||
2cf1705c AW |
521 | (cond |
522 | ((object->assembly x) => list) | |
523 | ((variable-cache-cell? x) (dump-object (variable-cache-cell-key x) addr)) | |
524 | ((subprogram? x) | |
9efc2d14 AW |
525 | (let ((table-code (dump-object (subprogram-table x) addr))) |
526 | `(,@table-code | |
527 | ,@(align-program (subprogram-prog x) | |
528 | (addr+ addr table-code))))) | |
2cf1705c AW |
529 | ((number? x) |
530 | `((load-number ,(number->string x)))) | |
531 | ((string? x) | |
f8ba2bb9 | 532 | (case (string-bytes-per-char x) |
94ff26b9 AW |
533 | ((1) `((load-string ,x))) |
534 | ((4) (align-code `(load-wide-string ,x) addr 4 4)) | |
f8ba2bb9 | 535 | (else (error "bad string bytes per char" x)))) |
2cf1705c | 536 | ((symbol? x) |
94ff26b9 | 537 | (let ((str (symbol->string x))) |
f8ba2bb9 | 538 | (case (string-bytes-per-char str) |
94ff26b9 AW |
539 | ((1) `((load-symbol ,str))) |
540 | ((4) `(,@(dump-object str addr) | |
541 | (make-symbol))) | |
f8ba2bb9 | 542 | (else (error "bad string bytes per char" str))))) |
2cf1705c | 543 | ((keyword? x) |
94ff26b9 AW |
544 | `(,@(dump-object (keyword->symbol x) addr) |
545 | (make-keyword))) | |
2cf1705c AW |
546 | ((list? x) |
547 | (let ((tail (let ((len (length x))) | |
548 | (if (>= len 65536) (too-long "list")) | |
549 | `((list ,(quotient len 256) ,(modulo len 256)))))) | |
550 | (let dump-objects ((objects x) (codes '()) (addr addr)) | |
551 | (if (null? objects) | |
552 | (fold append tail codes) | |
553 | (let ((code (dump-object (car objects) addr))) | |
554 | (dump-objects (cdr objects) (cons code codes) | |
555 | (addr+ addr code))))))) | |
556 | ((pair? x) | |
557 | (let ((kar (dump-object (car x) addr))) | |
558 | `(,@kar | |
559 | ,@(dump-object (cdr x) (addr+ addr kar)) | |
560 | (cons)))) | |
5a9c6dcb AW |
561 | ((and (vector? x) |
562 | (equal? (array-shape x) (list (list 0 (1- (vector-length x)))))) | |
2cf1705c AW |
563 | (let* ((len (vector-length x)) |
564 | (tail (if (>= len 65536) | |
565 | (too-long "vector") | |
566 | `((vector ,(quotient len 256) ,(modulo len 256)))))) | |
567 | (let dump-objects ((i 0) (codes '()) (addr addr)) | |
568 | (if (>= i len) | |
569 | (fold append tail codes) | |
570 | (let ((code (dump-object (vector-ref x i) addr))) | |
571 | (dump-objects (1+ i) (cons code codes) | |
572 | (addr+ addr code))))))) | |
782a82ee AW |
573 | ((and (array? x) (symbol? (array-type x))) |
574 | (let* ((type (dump-object (array-type x) addr)) | |
575 | (shape (dump-object (array-shape x) (addr+ addr type)))) | |
576 | `(,@type | |
577 | ,@shape | |
578 | ,@(align-code | |
579 | `(load-array ,(uniform-array->bytevector x)) | |
580 | (addr+ (addr+ addr type) shape) | |
581 | 8 | |
582 | 4)))) | |
73788ca8 AW |
583 | ((array? x) |
584 | ;; an array of generic scheme values | |
585 | (let* ((contents (array-contents x)) | |
586 | (len (vector-length contents))) | |
587 | (let dump-objects ((i 0) (codes '()) (addr addr)) | |
588 | (if (< i len) | |
589 | (let ((code (dump-object (vector-ref x i) addr))) | |
590 | (dump-objects (1+ i) (cons code codes) | |
591 | (addr+ addr code))) | |
592 | (fold append | |
593 | `(,@(dump-object (array-shape x) addr) | |
594 | (make-array ,(quotient (ash len -16) 256) | |
595 | ,(logand #xff (ash len -8)) | |
596 | ,(logand #xff len))) | |
597 | codes))))) | |
2cf1705c AW |
598 | (else |
599 | (error "assemble: unrecognized object" x)))) | |
f1d7723b | 600 |