3 ;; Copyright (C) 2001 Free Software Foundation, Inc.
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)
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.
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.
22 (define-module (system vm assemble)
23 :use-syntax (system base syntax)
24 :use-module (system base module)
25 :use-module (system il glil)
26 :use-module (system vm core)
27 :use-module (system vm conv)
28 :use-module (ice-9 match)
29 :use-module (ice-9 regex)
30 :use-module (ice-9 common-list)
33 (define (assemble glil env . opts)
34 (dump (codegen (preprocess glil #f) #t)))
41 (define-structure (<vm-asm> venv glil body))
42 (define-structure (venv parent nexts closure?))
43 (define-structure (vmod id))
44 (define-structure (vlink module name))
45 (define-structure (bytespec nargs nrest nlocs bytes objs))
49 ;;; Stage 1: Preprocess
52 (define (preprocess x e)
54 (($ <glil-asm> nargs nrest nlocs nexts body)
55 (let* ((venv (make-venv e nexts #f))
56 (body (map (lambda (x) (preprocess x venv)) body)))
57 (make-<vm-asm> venv x body)))
58 (($ <glil-external> op depth index)
60 (e e (venv-parent e)))
62 (set-venv-closure?! e #t))
68 ;;; Stage 2: Bytecode generation
71 (define (codegen glil toplevel)
73 (($ <vm-asm> venv ($ <glil-asm> nargs nrest nlocs nexts _) body)
77 (nvars (+ nargs nlocs -1)))
78 (define (current-address) (length stack))
79 (define (push-code! code)
80 (set! stack (optimizing-push code stack)))
81 (define (object-index obj)
82 (cond ((assq-ref object-alist obj))
83 (else (let ((index (length object-alist)))
84 (set! object-alist (acons obj index object-alist))
86 (define (label-ref key)
87 (assq-ref label-alist key))
88 (define (label-set key pos)
89 (set! label-alist (assq-set! label-alist key pos)))
90 (define (generate-code x)
93 (push-code! `(object-ref ,(object-index (codegen x #f))))
94 (if (venv-closure? env) (push-code! `(make-closure))))
101 (for-each push-code! (object->dump-code x))
102 (cond ((object->code x) => push-code!)
103 (else (push-code! `(object-ref ,(object-index x)))))))
105 (($ <glil-argument> op index)
106 (push-code! (list (symbol-append 'local- op)
109 (($ <glil-local> op index)
110 (push-code! (list (symbol-append 'local- op)
111 (- nvars (+ nargs index)))))
113 (($ <glil-external> op depth index)
114 (do ((e venv (venv-parent e))
116 (i 0 (+ i (venv-nexts e))))
118 (push-code! (list (symbol-append 'external- op)
121 (($ <glil-module> op module name)
122 (let ((mod (make-vmod module)))
125 ;; (push-code! `(load-module ,module))
126 (push-code! `(load-symbol ,name))
127 (push-code! `(link/current-module)))
128 (let ((vlink (make-vlink mod name)))
129 (push-code! `(object-ref ,(object-index vlink)))))
130 (push-code! (list (symbol-append 'variable- op)))))
132 (($ <glil-label> label)
133 (label-set label (current-address)))
135 (($ <glil-branch> inst label)
136 (let ((setter (lambda (addr) (- (label-ref label) (1+ addr)))))
137 (push-code! (list inst setter))))
139 (($ <glil-call> inst n)
140 (push-code! (list inst n)))
142 (($ <glil-inst> inst)
143 (if (instruction? inst)
144 (push-code! (list inst))
145 (error "Unknown instruction:" inst)))))
148 (if (> nexts 0) (push-code! `(external ,nexts)))
149 (for-each generate-code body)
150 (let ((bytes (code->bytes
151 (map/index (lambda (v n) (if (procedure? v) (v n) v))
153 (objs (map car (reverse! object-alist))))
154 (make-bytespec nargs nrest nlocs bytes objs))))))
156 (define (map/index f l)
159 (r '() (cons (f (car l) n) r)))
160 ((null? l) (reverse! r))))
164 (define *optimize-table*
165 '((not (not . not-not)
171 (br-if (not . br-if-not)
175 (not-eq? . br-if-not-eq)
176 (not-null? . br-if-not-null))
177 (br-if-not (not . br-if)
179 (null? . br-if-not-null)
180 (not-not . br-if-not)
182 (not-null? . br-if-null))))
184 (define (optimizing-push code stack)
185 (let ((alist (assq-ref *optimize-table* (car code))))
186 (cond ((and alist (pair? stack) (assq-ref alist (car stack))) =>
187 (lambda (inst) (append! (reverse! (cons inst (cdr code)))
189 (else (append! (reverse! (code-finalize code)) stack)))))
193 ;;; Stage3: Dumpcode generation
196 (define (dump bytespec)
197 (let* ((table (build-object-table bytespec))
198 (bytes (bytespec->bytecode bytespec table '(return))))
201 (let ((spec (make-bytespec 0 0 (length table) bytes '())))
202 (bytespec->bytecode spec '() '(tail-call 0))))))
204 (define (bytespec->bytecode bytespec object-table last-code)
206 (define (push-code! x)
207 (set! stack (cons x stack)))
208 (define (object-index x)
209 (cond ((object-find object-table x) => cdr)
211 (define (dump-table-object! obj+index)
212 (let dump! ((x (car obj+index)))
215 ;; (push-code! `(local-ref ,(object-index (vlink-module x))))
216 (push-code! `(load-symbol ,(vlink-name x)))
217 (push-code! `(link/current-module)))
219 (push-code! `(load-module ,(vmod-id x))))
221 (for-each push-code! (object->dump-code x)))))
222 (push-code! `(local-set ,(cdr obj+index))))
223 (define (dump-object! x)
226 ((bytespec? x) (dump-bytecode! x))
227 ((object-index x) => (lambda (i) (push-code! `(local-ref ,i))))
229 (error "Cannot dump:" x)))))
230 (define (dump-bytecode! spec)
231 (let ((nargs (bytespec-nargs spec))
232 (nrest (bytespec-nrest spec))
233 (nlocs (bytespec-nlocs spec))
234 (objs (bytespec-objs spec)))
235 (if (and (null? objs) (< nargs 4) (< nlocs 16))
236 ;; zero-object encoding
237 (push-code! (object->code (+ (* nargs 32) (* nrest 16) nlocs)))
240 (push-code! (object->code nargs))
241 (push-code! (object->code nrest))
242 (push-code! (object->code nlocs))
244 (cond ((null? objs) (push-code! (object->code #f)))
247 (for-each dump-object! objs)
248 (push-code! `(vector))))))
250 (push-code! `(load-program ,(bytespec-bytes spec)))))
253 (for-each dump-table-object! object-table)
254 (dump-bytecode! bytespec)
255 (push-code! last-code)
256 (code->bytes (apply append! (map code-finalize (reverse! stack))))))
260 (define (object-find table x)
261 ((if (or (vlink? x) (vmod? x)) assoc assq) x table))
263 (define (build-object-table bytespec)
264 (let ((table '()) (index 0))
266 (if (vlink? x) (begin (insert! (vlink-module x))))
267 (if (not (object-find table x))
269 (set! table (acons x index table))
270 (set! index (1+ index)))))
271 (let loop ((spec bytespec))
272 (for-each (lambda (x)
273 (if (bytespec? x) (loop x) (insert! x)))
274 (bytespec-objs spec)))
279 (define (code-finalize code)
281 ((inst (? symbol? s))
282 (let ((str (symbol->string s)))
283 `(,inst ,(string-length str) ,str)))
284 ((inst (? string? s))
285 `(,inst ,(string-length s) ,s))
286 (else (code-pack code))))
288 (define (integer->string n) (make-string 1 (integer->char n)))
290 (define (length->string len)
291 (define C integer->char)
293 (cond ((< len 254) (list (C len)))
295 (list (C 254) (C (quotient len 256)) (C (modulo len 256))))
296 ((< len most-positive-fixnum)
298 (C (quotient len (* 256 256 256)))
299 (C (modulo (quotient len (* 256 256)) 256))
300 (C (modulo (quotient len 256) 256))
301 (C (modulo len 256))))
302 (else (error "Too long" len)))))
304 (define (code->bytes code)
305 (let* ((code (list->vector code))
306 (size (vector-length code)))
309 (apply string-append (vector->list code))
310 (let ((inst (vector-ref code i)))
311 (if (not (instruction? inst))
312 (error "Unknown instruction:" inst))
313 (vector-set! code i (integer->string (instruction->opcode inst)))
314 (let ((bytes (instruction-length inst)))
317 (integer->string (instruction->opcode inst)))
318 (vector-set! code (+ i 1)
319 (length->string (vector-ref code (1+ i))))
321 ((= bytes 0) (loop (+ i 1)))
323 (let ((end (+ i 1 bytes)))
324 (do ((j (+ i 1) (1+ j)))
325 ((= j end) (loop end))
326 (vector-set! code j (integer->string
327 (vector-ref code j)))))))))))))