allow compilation of #@2(1 2 3)
[bpt/guile.git] / module / language / glil / compile-assembly.scm
CommitLineData
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