[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
What happened to the ex-Guile VM?
From: |
Keisuke Nishida |
Subject: |
What happened to the ex-Guile VM? |
Date: |
Mon, 19 Mar 2001 19:08:08 -0500 |
User-agent: |
Wanderlust/2.4.0 (Rio) SEMI/1.13.7 (Awazu) FLIM/1.13.2 (Kasanui) Emacs/21.0.99 (i686-pc-linux-gnu) MULE/5.0 (SAKAKI) |
Hello,
I found somebody was working on a bytecode interpreter (VM) for
Guile around 1997. What happened to it? Why does it not exist
now? The message I read was about the VM's unsatisfactory
efficiency. Was it the only reason that Guile did not adopt a
VM? Or is there any fatal reason of not supporting a VM?
Anyway, this is a brief summary of the current status of my VM.
In my VM implementation, a VM is a first-class object. You can
create any number of VMs and run them separately, which I guess
helps supporting multithread programming in future.
The current VM has two different "engines". One is for fast
execution, and one is for debugging execution. The slowdown in
the debug engine seems to be about 30%, so probably most people
will be satisfied with the debug engine. I use it by default.
Let's see the execution speed in a simple recursion:
% guile ;; debug evaluator
guile> (define (fib n) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))
guile> (time (fib 30))
clock utime stime cutime cstime gctime
23.81 23.53 0.14 0.00 0.00 12.76
$2 = 1346269
% guile-vm ;; debug engine
address@hidden> ,time (fib 30)
$3 = 1346269
clock utime stime cutime cstime gctime
3.12 3.11 0.00 0.00 0.00 0.00
% rep ;; version 0.13.4
user> ,time (fib 30)
1346269
Elapsed: 4.372812 seconds
% bigloo -O6 fib.scm ;; version 2.2b
% time a.out
1346269
real 0m0.271s
user 0m0.240s
sys 0m0.020s
Evaluation of an expression is done in the following 6 steps:
1. Read
"(let ((x 1) (y 2)) (+ x y))" -> (let ((x 1) (y 2)) (+ x y))
2. Expansion
-> ((lambda (x y) (+ x y)) 1 2)
3. Translation
-> ((@lambda (x y) (@+ x y)) 1 2)
4. Compilation
-> (@asm ()
(const 1)
(const 2)
(@asm (x y)
(ref x)
(ref y)
(add)
(return))
(tail-call 2))
5. Assemblage
#<program 0>
0 make-int8 1 ;; 1
2 make-int8 2 ;; 2
4 object-ref:0 ;; #<program 1>
5 tail-call:2
#<program 1>
0 local-ref:1 ;; (ref x)
1 local-ref:0 ;; (ref y)
2 add
3 return
6. Execution
=> 3
(In practice, these steps are done more efficiently.)
Compiled code is converted into a loadable bytecode and
loaded/linked by the VM. For example, the following code
foo
is compiled into the assembly
(@asm ()
(ref foo)
(return))
which is converted into the loadable code
load-symbol 3 "foo"
link/module
vector 1
make-program 3 "%#&"
which can be saved in a file. Compiled files have become much
smaller than before. The dump routine is written in Scheme
(80 lines) and the undump routine has become part of the VM
(50 lines). I hope the loading speed will become quite fast.
As shown above, symbols can be linked with modules at loading
time (or otherwise, they are delayed until run time), so there
is no run-time lookup of variables. The VM-level module support
is as follows.
There are four kinds of variables:
local variable - allocated in the stack
external variable - allocated in the heap
module variable - allocated in a module
global variable - looked up in the module hierarchy
If you enter a symbol at top level, it is inserted into the
current module (yes, I'll support it). Modules are usually
organized into a hierarchy and have their global names.
Hence, variables can also be reached by their global names.
The VM provides an instruction `global-ref', which does
global lookup and finds a value cell. This is all the VM
does for a module system.
More advanced stuff like importing/exporting variables is
supported by the intermediate language and the compiler.
All variables are statically identified at compile time,
and the compiler produces `global-ref' as necessary. The
compiler must also take care of run-time recompilation of
pre-compiled code during an interactive session.
All languages, including Scheme, are to be translated into an
intermediate language, called GCIL (formerly called iScheme).
The following code is part of the definition of the R5RS core
environment, written in GCIL:
(@define-module Language::R5RS::core)
(@define car (@lambda (x) (@car x)))
(@define cdr (@lambda (x) (@cdr x)))
...
The following is the definition of the language R5RS:
(define-language r5rs
:title "Standard Scheme (R5RS + syntax-case)"
:version "0.3"
:reader read
:expander expand
:translator translate
:printer write
:environment (global-ref 'Language::R5RS::core)
)
The following procedures are provided:
(read-in PORT LANG)
(compile-in FORM ENV LANG . OPTS)
(compile-file-in SOURCE TARGET LANG . OPTS)
(eval-in FORM ENV LANG)
(load-in FILE LANG)
(print-in VAL PORT LANG)
And the new repl manages the current language and modules...
I think I need more time to complete this project. I haven't
completed my new module system yet. I haven't implemented
exception handling yet. The compiler is far from self-compiling
yet. I want to at least make part of the compiler self-compilable
before the next snapshot.
I'm getting busy these days and stopping programming for a while.
Hopefully, I will be able to concentrate on this project next year.
I'm going to major in computer languages at a graduate school.
Sorry about my explanation being unclear. I just wanted to let you
know I am still working on Guile VM and going to continue doing ;)
Kei
- What happened to the ex-Guile VM?,
Keisuke Nishida <=