Change `write-bytecode' to accept a bytevector.
[bpt/guile.git] / module / language / assembly / decompile-bytecode.scm
CommitLineData
7b107cce
AW
1;;; Guile VM code converters
2
9b7ca73c 3;; Copyright (C) 2001, 2009, 2010 Free Software Foundation, Inc.
7b107cce 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
7b107cce
AW
18
19;;; Code:
20
21(define-module (language assembly decompile-bytecode)
22 #:use-module (system vm instruction)
23 #:use-module (system base pmatch)
24 #:use-module (srfi srfi-4)
15939985 25 #:use-module (rnrs bytevector)
7b107cce 26 #:use-module (language assembly)
6cf48307 27 #:use-module ((system vm objcode) #:select (byte-order))
7b107cce
AW
28 #:export (decompile-bytecode))
29
30(define (decompile-bytecode x env opts)
31 (let ((i 0) (size (u8vector-length x)))
32 (define (pop)
33 (let ((b (cond ((< i size) (u8vector-ref x i))
34 ((= i size) #f)
35 (else (error "tried to decode too many bytes")))))
36 (if b (set! i (1+ i)))
37 b))
38 (let ((ret (decode-load-program pop)))
39 (if (= i size)
40 (values ret env)
41 (error "bad bytecode: only decoded ~a out of ~a bytes" i size)))))
42
6fe6a2a2
AW
43(define (br-instruction? x)
44 (memq x '(br br-if br-if-not br-if-eq br-if-not-eq br-if-null br-if-not-null)))
8b652112
AW
45(define (br-nargs-instruction? x)
46 (memq x '(br-if-nargs-ne br-if-nargs-lt br-if-nargs-gt)))
6fe6a2a2 47
97fcf583
AW
48(define (bytes->s24 a b c)
49 (let ((x (+ (ash a 16) (ash b 8) c)))
50 (if (zero? (logand (ash 1 23) x))
6fe6a2a2 51 x
97fcf583 52 (- x (ash 1 24)))))
6fe6a2a2 53
ccf77d95 54;; FIXME: this is a little-endian disassembly!!!
7b107cce 55(define (decode-load-program pop)
56164a5a 56 (let* ((a (pop)) (b (pop)) (c (pop)) (d (pop))
9aeaabdc 57 (e (pop)) (f (pop)) (g (pop)) (h (pop))
7b107cce 58 (len (+ a (ash b 8) (ash c 16) (ash d 24)))
9aeaabdc 59 (metalen (+ e (ash f 8) (ash g 16) (ash h 24)))
6fe6a2a2 60 (labels '())
7b107cce 61 (i 0))
97fcf583
AW
62 (define (ensure-label rel1 rel2 rel3)
63 (let ((where (+ i (bytes->s24 rel1 rel2 rel3))))
6fe6a2a2
AW
64 (or (assv-ref labels where)
65 (begin
66 (let ((l (gensym ":L")))
67 (set! labels (acons where l labels))
68 l)))))
7b107cce 69 (define (sub-pop) ;; ...records. ha. ha.
1f1ec13b
AW
70 (let ((b (cond ((< i len) (pop))
71 ((= i len) #f)
7b107cce
AW
72 (else (error "tried to decode too many bytes")))))
73 (if b (set! i (1+ i)))
74 b))
75 (let lp ((out '()))
1f1ec13b 76 (cond ((> i len)
7b107cce 77 (error "error decoding program -- read too many bytes" out))
1f1ec13b 78 ((= i len)
56164a5a 79 `(load-program ,(map (lambda (x) (cons (cdr x) (car x)))
6fe6a2a2
AW
80 (reverse labels))
81 ,len
1f1ec13b 82 ,(if (zero? metalen) #f (decode-load-program pop))
7b107cce
AW
83 ,@(reverse! out)))
84 (else
85 (let ((exp (decode-bytecode sub-pop)))
6fe6a2a2 86 (pmatch exp
97fcf583
AW
87 ((,br ,rel1 ,rel2 ,rel3) (guard (br-instruction? br))
88 (lp (cons `(,br ,(ensure-label rel1 rel2 rel3)) out)))
8b652112
AW
89 ((,br ,hi ,lo ,rel1 ,rel2 ,rel3) (guard (br-nargs-instruction? br))
90 (lp (cons `(,br ,hi ,lo ,(ensure-label rel1 rel2 rel3)) out)))
97fcf583 91 ((mv-call ,n ,rel1 ,rel2 ,rel3)
3c365b8e 92 (lp (cons `(mv-call ,n ,(ensure-label rel1 rel2 rel3)) out)))
9b7ca73c
AW
93 ((prompt ,n0 ,n1 ,rel1 ,rel2 ,rel3)
94 (lp (cons `(prompt ,n0 ,n1 ,(ensure-label rel1 rel2 rel3)) out)))
6fe6a2a2
AW
95 (else
96 (lp (cons exp out))))))))))
7b107cce
AW
97
98(define (decode-bytecode pop)
99 (and=> (pop)
100 (lambda (opcode)
101 (let ((inst (opcode->instruction opcode)))
102 (cond
103 ((eq? inst 'load-program)
104 (decode-load-program pop))
6cf48307 105
7b107cce 106 ((< (instruction-length inst) 0)
6cf48307
MG
107 ;; the negative length indicates a variable length
108 ;; instruction
15939985 109 (let* ((make-sequence
94ff26b9 110 (if (or (memq inst '(load-array load-wide-string)))
15939985
LC
111 make-bytevector
112 make-string))
113 (sequence-set!
94ff26b9 114 (if (or (memq inst '(load-array load-wide-string)))
15939985
LC
115 bytevector-u8-set!
116 (lambda (str pos value)
117 (string-set! str pos (integer->char value)))))
15939985 118 (len (let* ((a (pop)) (b (pop)) (c (pop)))
8403b9f5 119 (+ (ash a 16) (ash b 8) c)))
15939985 120 (seq (make-sequence len)))
7b107cce
AW
121 (let lp ((i 0))
122 (if (= i len)
94ff26b9 123 `(,inst ,(if (eq? inst 'load-wide-string)
b158c2c3 124 (utf32->string seq (native-endianness))
94ff26b9 125 seq))
7b107cce 126 (begin
94ff26b9 127 (sequence-set! seq i (pop))
7b107cce
AW
128 (lp (1+ i)))))))
129 (else
130 ;; fixed length
131 (let lp ((n (instruction-length inst)) (out (list inst)))
132 (if (zero? n)
133 (reverse! out)
134 (lp (1- n) (cons (pop) out))))))))))