*** empty log message ***
[bpt/guile.git] / module / system / vm / assemble.scm
CommitLineData
17e90c5e
KN
1;;; Guile VM assembler
2
3;; Copyright (C) 2001 Free Software Foundation, Inc.
4
5;; This program is free software; you can redistribute it and/or modify
6;; it under the terms of the GNU General Public License as published by
7;; the Free Software Foundation; either version 2, or (at your option)
8;; any later version.
9;;
10;; This program 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
13;; GNU General Public License for more details.
14;;
15;; You should have received a copy of the GNU General Public License
16;; along with this program; see the file COPYING. If not, write to
17;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18;; Boston, MA 02111-1307, USA.
19
20;;; Code:
21
22(define-module (system vm assemble)
23 :use-syntax (system base syntax)
17e90c5e
KN
24 :use-module (system il glil)
25 :use-module (system vm core)
26 :use-module (system vm conv)
27 :use-module (ice-9 match)
28 :use-module (ice-9 regex)
29 :use-module (ice-9 common-list)
30 :export (assemble))
31
32(define (assemble glil env . opts)
4bfb26f5 33 (codegen (preprocess glil #f) #t))
17e90c5e
KN
34
35\f
36;;;
37;;; Types
38;;;
39
40(define-structure (<vm-asm> venv glil body))
41(define-structure (venv parent nexts closure?))
42(define-structure (vmod id))
43(define-structure (vlink module name))
3d5ee0cd 44(define-structure (bytespec nargs nrest nlocs nexts bytes objs))
17e90c5e
KN
45
46\f
47;;;
48;;; Stage 1: Preprocess
49;;;
50
51(define (preprocess x e)
52 (match x
53 (($ <glil-asm> nargs nrest nlocs nexts body)
54 (let* ((venv (make-venv e nexts #f))
55 (body (map (lambda (x) (preprocess x venv)) body)))
56 (make-<vm-asm> venv x body)))
57 (($ <glil-external> op depth index)
58 (do ((d depth (1- d))
59 (e e (venv-parent e)))
60 ((= d 0))
61 (set-venv-closure?! e #t))
62 x)
63 (else x)))
64
65\f
66;;;
67;;; Stage 2: Bytecode generation
68;;;
69
70(define (codegen glil toplevel)
71 (match glil
72 (($ <vm-asm> venv ($ <glil-asm> nargs nrest nlocs nexts _) body)
73 (let ((stack '())
74 (label-alist '())
3616e9e9 75 (object-alist '()))
17e90c5e
KN
76 (define (push-code! code)
77 (set! stack (optimizing-push code stack)))
206a0622 78 (define (push-object! x)
880ed584
KN
79 (cond ((object->code x) => push-code!)
80 (toplevel
81 ;; top-level object-dump
82 (cond ((object-assoc x object-alist) =>
83 (lambda (obj+index)
84 (cond ((not (cdr obj+index))
85 (set-cdr! obj+index nlocs)
86 (set! nlocs (+ nlocs 1))))
87 (push-code! `(local-ref ,(cdr obj+index)))))
88 (else
89 (set! object-alist (acons x #f object-alist))
90 (push-code! `(object-dump ,x)))))
f0c99935 91 (else
880ed584
KN
92 ;; local object-ref
93 (let ((i (cond ((object-assoc x object-alist) => cdr)
94 (else
95 (let ((i (length object-alist)))
96 (set! object-alist (acons x i object-alist))
97 i)))))
98 (push-code! `(object-ref ,i))))))
17e90c5e
KN
99 (define (label-ref key)
100 (assq-ref label-alist key))
206a0622
KN
101 (define (label-set key)
102 (let ((addr (apply + (map length stack))))
103 (set! label-alist (assq-set! label-alist key addr))))
17e90c5e
KN
104 (define (generate-code x)
105 (match x
bd098a1a 106 (($ <vm-asm> venv)
f0c99935 107 (push-object! (codegen x #f))
bd098a1a 108 (if (venv-closure? venv) (push-code! `(make-closure))))
17e90c5e
KN
109
110 (($ <glil-void>)
111 (push-code! `(void)))
112
113 (($ <glil-const> x)
f0c99935 114 (push-object! x))
17e90c5e
KN
115
116 (($ <glil-argument> op index)
f0c99935 117 (if (eq? op 'ref)
532565b0
KN
118 (push-code! `(local-ref ,index))
119 (push-code! `(local-set ,index))))
17e90c5e
KN
120
121 (($ <glil-local> op index)
f0c99935
KN
122 (if (eq? op 'ref)
123 (push-code! `(local-ref ,(+ nargs index)))
124 (push-code! `(local-set ,(+ nargs index)))))
17e90c5e
KN
125
126 (($ <glil-external> op depth index)
127 (do ((e venv (venv-parent e))
128 (d depth (1- d))
3616e9e9 129 (n 0 (+ n (venv-nexts e))))
17e90c5e 130 ((= d 0)
f0c99935
KN
131 (if (eq? op 'ref)
132 (push-code! `(external-ref ,(+ n index)))
133 (push-code! `(external-set ,(+ n index)))))))
17e90c5e
KN
134
135 (($ <glil-module> op module name)
880ed584 136 (push-object! (make-vlink #f name)) ;; FIXME: (make-vmod module)
f0c99935
KN
137 (if (eq? op 'ref)
138 (push-code! '(variable-ref))
139 (push-code! '(variable-set))))
17e90c5e
KN
140
141 (($ <glil-label> label)
206a0622 142 (label-set label))
17e90c5e
KN
143
144 (($ <glil-branch> inst label)
206a0622 145 (let ((setter (lambda (addr) (- (label-ref label) addr))))
17e90c5e
KN
146 (push-code! (list inst setter))))
147
46cd9a34 148 (($ <glil-call> inst nargs)
17e90c5e 149 (if (instruction? inst)
46cd9a34
KN
150 (let ((pops (instruction-pops inst)))
151 (cond ((< pops 0)
152 (push-code! (list inst nargs)))
153 ((= pops nargs)
154 (push-code! (list inst)))
155 (else
156 (error "Wrong number of arguments:" inst nargs))))
17e90c5e
KN
157 (error "Unknown instruction:" inst)))))
158 ;;
159 ;; main
17e90c5e 160 (for-each generate-code body)
880ed584
KN
161 (if toplevel
162 ;; top-level
163 (let ((new '()))
164 (define (push-code! x)
165 (set! new (cons x new)))
166 (do ((stack (reverse! stack) (cdr stack)))
167 ((null? stack)
168 (make-dumpcode nlocs nexts (stack->bytes (reverse! new))))
169 (if (eq? (caar stack) 'object-dump)
170 (let ((x (cadar stack)))
171 (dump-object! push-code! x)
172 (cond ((object-assoc x object-alist) =>
173 (lambda (obj+index)
174 (cond ((cdr obj+index) =>
175 (lambda (n)
f349065e 176 (push-code! '(dup))
880ed584
KN
177 (push-code! `(local-set ,n)))))))))
178 (push-code! (car stack)))))
179 ;; closures
180 (let ((bytes (stack->bytes (reverse! stack)))
181 (objs (map car (reverse! object-alist))))
4bfb26f5 182 (make-bytespec nargs nrest nlocs nexts bytes objs)))))))
17e90c5e 183
880ed584
KN
184(define (object-assoc x alist)
185 (if (vlink? x) (assoc x alist) (assq x alist)))
186
4bfb26f5 187(define (stack->bytes stack)
880ed584 188 (let loop ((result '()) (stack stack) (addr 0))
206a0622 189 (if (null? stack)
4bfb26f5 190 (apply string-append (reverse! result))
206a0622
KN
191 (let* ((orig (car stack))
192 (addr (+ addr (length orig)))
193 (code (if (and (pair? (cdr orig)) (procedure? (cadr orig)))
194 `(,(car orig) ,((cadr orig) addr))
195 orig)))
4bfb26f5 196 (loop (cons (code->bytes code) result) (cdr stack) addr)))))
17e90c5e 197
4bfb26f5
KN
198\f
199;;;
200;;; Bytecode optimization
201;;;
17e90c5e 202
4bfb26f5 203(define *optimization-table*
17e90c5e
KN
204 '((not (not . not-not)
205 (eq? . not-eq?)
206 (null? . not-null?)
207 (not-not . not)
208 (not-eq? . eq?)
209 (not-null? . null?))
210 (br-if (not . br-if-not)
211 (eq? . br-if-eq)
212 (null? . br-if-null)
213 (not-not . br-if)
214 (not-eq? . br-if-not-eq)
215 (not-null? . br-if-not-null))
216 (br-if-not (not . br-if)
217 (eq? . br-if-not-eq)
218 (null? . br-if-not-null)
219 (not-not . br-if-not)
220 (not-eq? . br-if-eq)
221 (not-null? . br-if-null))))
222
223(define (optimizing-push code stack)
4bfb26f5 224 (let ((alist (assq-ref *optimization-table* (car code))))
206a0622
KN
225 (cond ((and alist (pair? stack) (assq-ref alist (caar stack))) =>
226 (lambda (inst) (cons (cons inst (cdr code)) (cdr stack))))
227 (else (cons (code-pack code) stack)))))
17e90c5e
KN
228
229\f
230;;;
4bfb26f5 231;;; Object dump
17e90c5e
KN
232;;;
233
4bfb26f5 234;; NOTE: undumpped in vm_load.c.
17e90c5e 235
f0c99935 236(define (dump-object! push-code! x)
bd098a1a
KN
237 (let dump! ((x x))
238 (cond
239 ((object->code x) => push-code!)
240 ((bytespec? x)
4bfb26f5
KN
241 (match x
242 (($ bytespec nargs nrest nlocs nexts bytes objs)
243 ;; dump parameters
244 (cond
245 ((and (< nargs 4) (< nlocs 8) (< nexts 4))
246 ;; 8-bit representation
247 (let ((x (+ (* nargs 64) (* nrest 32) (* nlocs 4) nexts)))
248 (push-code! `(make-int8 ,x))))
249 ((and (< nargs 16) (< nlocs 128) (< nexts 16))
250 ;; 16-bit representation
251 (let ((x (+ (* nargs 4096) (* nrest 2048) (* nlocs 16) nexts)))
252 (push-code! `(make-int16 ,(quotient x 256) ,(modulo x 256)))))
253 (else
254 ;; Other cases
255 (push-code! (object->code nargs))
256 (push-code! (object->code nrest))
257 (push-code! (object->code nlocs))
258 (push-code! (object->code nexts))
259 (push-code! (object->code #f))))
260 ;; dump object table
261 (cond ((not (null? objs))
262 (for-each dump! objs)
263 (push-code! `(vector ,(length objs)))))
264 ;; dump bytecode
265 (push-code! `(load-program ,bytes)))))
bd098a1a 266 ((vlink? x)
be2d2946 267 (dump! (vlink-module x))
bd098a1a 268 (dump! (vlink-name x))
c0a25ecc
KN
269 (push-code! `(link)))
270 ((vmod? x)
271 (push-code! `(load-module ,(vmod-id x))))
a80be762 272 ((and (integer? x) (exact? x))
bd098a1a
KN
273 (let ((str (do ((n x (quotient n 256))
274 (l '() (cons (modulo n 256) l)))
275 ((= n 0)
276 (list->string (map integer->char l))))))
277 (push-code! `(load-integer ,str))))
a80be762
KN
278 ((number? x)
279 (push-code! `(load-number ,(number->string x))))
bd098a1a
KN
280 ((string? x)
281 (push-code! `(load-string ,x)))
282 ((symbol? x)
283 (push-code! `(load-symbol ,(symbol->string x))))
284 ((keyword? x)
285 (push-code! `(load-keyword ,(symbol->string (keyword-dash-symbol x)))))
286 ((list? x)
287 (for-each dump! x)
288 (push-code! `(list ,(length x))))
289 ((pair? x)
290 (dump! (car x))
291 (dump! (cdr x))
292 (push-code! `(cons)))
293 ((vector? x)
294 (for-each dump! (vector->list x))
295 (push-code! `(vector ,(vector-length x))))
296 (else
297 (error "Cannot dump:" x)))))