summaryrefslogtreecommitdiff
path: root/module/system/vm/conv.scm
diff options
context:
space:
mode:
Diffstat (limited to 'module/system/vm/conv.scm')
-rw-r--r--module/system/vm/conv.scm196
1 files changed, 196 insertions, 0 deletions
diff --git a/module/system/vm/conv.scm b/module/system/vm/conv.scm
new file mode 100644
index 000000000..89993f6a3
--- /dev/null
+++ b/module/system/vm/conv.scm
@@ -0,0 +1,196 @@
+;;; Guile VM code converters
+
+;; Copyright (C) 2001 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(define-module (system vm conv)
+ :use-module ((system vm core)
+ :select (instruction? instruction-length
+ instruction->opcode opcode->instruction))
+ :use-module (system base pmatch)
+ :use-module (ice-9 regex)
+ :use-module (srfi srfi-4)
+ :use-module (srfi srfi-1)
+ :export (code-pack code-unpack object->code code->object code->bytes
+ make-byte-decoder))
+
+;;;
+;;; Code compress/decompression
+;;;
+
+(define (code-pack code)
+ (pmatch code
+ ((inst ,n) (guard (integer? n))
+ (cond ((< n 10)
+ (let ((abbrev (string->symbol (format #f "~A:~A" inst n))))
+ (if (instruction? abbrev) (list abbrev) code)))
+ (else code)))
+ (else code)))
+
+(define (code-unpack code)
+ (let ((inst (symbol->string (car code))))
+ (cond
+ ((string-match "^([^:]*):([0-9]+)$" inst) =>
+ (lambda (data)
+ (cons* (string->symbol (match:substring data 1))
+ (string->number (match:substring data 2))
+ (cdr code))))
+ (else code))))
+
+
+;;;
+;;; Encoder/decoder
+;;;
+
+(define (object->code x)
+ (cond ((eq? x #t) `(make-true))
+ ((eq? x #f) `(make-false))
+ ((null? x) `(make-eol))
+ ((and (integer? x) (exact? x))
+ (cond ((and (<= -128 x) (< x 128))
+ `(make-int8 ,(modulo x 256)))
+ ((and (<= -32768 x) (< x 32768))
+ (let ((n (if (< x 0) (+ x 65536) x)))
+ `(make-int16 ,(quotient n 256) ,(modulo n 256))))
+ (else #f)))
+ ((char? x) `(make-char8 ,(char->integer x)))
+ (else #f)))
+
+(define (code->object code)
+ (pmatch code
+ ((make-true) #t)
+ ((make-false) #f) ;; FIXME: Same as the `else' case!
+ ((make-eol) '())
+ ((make-int8 ,n)
+ (if (< n 128) n (- n 256)))
+ ((make-int16 ,n1 ,n2)
+ (let ((n (+ (* n1 256) n2)))
+ (if (< n 32768) n (- n 65536))))
+ ((make-char8 ,n)
+ (integer->char n))
+ ((load-string ,s) s)
+ ((load-symbol ,s) (string->symbol s))
+ ((load-keyword ,s) (symbol->keyword (string->symbol s)))
+ (else #f)))
+
+; (let ((c->o code->object))
+; (set! code->object
+; (lambda (code)
+; (format #t "code->object: ~a~%" code)
+; (let ((ret (c->o code)))
+; (format #t "code->object returned ~a~%" ret)
+; ret))))
+
+(define (code->bytes code)
+ (define (string->u8vector str)
+ (apply u8vector (map char->integer (string->list str))))
+
+ (let* ((code (code-pack code))
+ (inst (car code))
+ (rest (cdr code))
+ (len (instruction-length inst))
+ (head (instruction->opcode inst)))
+ (cond ((< len 0)
+ ;; Variable-length code
+ ;; Typical instructions are `link' and `load-program'.
+ (if (string? (car rest))
+ (set-car! rest (string->u8vector (car rest))))
+ (let* ((str (car rest))
+ (str-len (u8vector-length str))
+ (encoded-len (encode-length str-len))
+ (encoded-len-len (u8vector-length encoded-len)))
+ (apply u8vector
+ (append (cons head (u8vector->list encoded-len))
+ (u8vector->list str)))))
+ ((= len (length rest))
+ ;; Fixed-length code
+ (apply u8vector (cons head rest)))
+ (else
+ (error "Invalid code:" code)))))
+
+; (let ((c->b code->bytes))
+; ;; XXX: Debugging output
+; (set! code->bytes
+; (lambda (code)
+; (format #t "code->bytes: ~a~%" code)
+; (let ((result (c->b code)))
+; (format #t "code->bytes: returned ~a~%" result)
+; result))))
+
+
+(define (make-byte-decoder bytes)
+ (let ((addr 0) (size (u8vector-length bytes)))
+ (define (pop)
+ (let ((byte (u8vector-ref bytes addr)))
+ (set! addr (1+ addr))
+ byte))
+ (define (sublist lst start end)
+ (take (drop lst start) (- end start)))
+ (lambda ()
+ (if (< addr size)
+ (let* ((start addr)
+ (inst (opcode->instruction (pop)))
+ (n (instruction-length inst))
+ (code (if (< n 0)
+ ;; variable length
+ (let* ((end (+ (decode-length pop) addr))
+ (subbytes (sublist
+ (u8vector->list bytes)
+ addr end))
+ (->string? (not (eq? inst 'load-program))))
+ (set! addr end)
+ (list inst
+ (if ->string?
+ (list->string
+ (map integer->char subbytes))
+ (apply u8vector subbytes))))
+ ;; fixed length
+ (do ((n n (1- n))
+ (l '() (cons (pop) l)))
+ ((= n 0) (cons* inst (reverse! l)))))))
+ (values start code))
+ #f))))
+
+
+;;;
+;;; Variable-length interface
+;;;
+
+;; NOTE: decoded in vm_fetch_length in vm.c as well.
+
+(define (encode-length len)
+ (cond ((< len 254) (u8vector len))
+ ((< len (* 256 256))
+ (u8vector 254 (quotient len 256) (modulo len 256)))
+ ((< len most-positive-fixnum)
+ (u8vector 255
+ (quotient len (* 256 256 256))
+ (modulo (quotient len (* 256 256)) 256)
+ (modulo (quotient len 256) 256)
+ (modulo len 256)))
+ (else (error "Too long code length:" len))))
+
+(define (decode-length pop)
+ (let ((len (pop)))
+ (cond ((< len 254) len)
+ ((= len 254) (+ (* (pop) 256) (pop)))
+ (else (+ (* (pop) 256 256 256)
+ (* (pop) 256 256)
+ (* (pop) 256)
+ (pop))))))