Carbone Ruby VM

			 The Carbone Ruby VM

Carbone  is a  vmgen based,  efficient virtual  machine for  Ruby.  It
targets compatibility, performance and portability.

Anton  Ertl's vmgen  is  originally  the build  tool  for Gforth,  the
fastest portable Forth implementation. It produces VMs that use direct
threaded  code  and  support   various  optimizations  that  make  the
execution of a virtual machine less virtual (i.e. faster).

There is lots  of flexibility gained in the decision  to use vmgen; to
name the most important: VM instructions can be coded in C

What's already working in the Carbone VM is:
  * sending
  * generically calling C functions
  * parts of the Ruby object system
  * defining classes
  * defining methods
  * defining procs
  * calling methods, procs
  * instance variables for classes
  * Fixnum

This  is a  developers-only prerelease  of  Carbone. BTW  there is  no
compiler  yet.    Neither  forward  nor   backwards  compatibility  is
guaranteed! You have been warned.

Carbone is released under the GPL.  Parts will be under LPGL.  I think
about adopting the Guile Copyright.

The preferred way for support and especially the exchange of ideas and
patches is

and more occasionally than regularly irc (#ruby-lang).

Carbone's author till now is Markus Liedl <>


(in about the order I will continue)

	mixins ivars (already prepared)
	super with arguments
	full constants support
	singleton classes
	optional arguments
	rest array arguments
	parallel assignment
 	full eval support (esp. introduction of new variables)
	builtin classes like String, ...
	special variables ($' $: ...)

(and somewhere in  between this list I will start  to build a frontend
using the RubyInRuby Parser --- if I find no better parser)


  Gforth snapshot from May 2001,
  which includes vmgen
                    also see the paper there.

  Bison, Flex

  Ruby, MétaRuby    for preprocessing Fixnum-Builtins to C/vmgen code
                    (also changes neccessary in configuration.rb:
                      $options[:metaruby] = "/..../src/lib/metaruby")

  GCC               preferably version 3; but 2.x works also fine
		    (you may have to adjust configuration.rb:
                      $options[:has_gcc_3_0] = true; ...)

  Boehm GC          optional; for example Debians libgc6 and libgc6-dev

  Till now it's running it on Linux.

Build Process

  get the sources:

  cvs \
  cvs -z3 \
    co carbone

  $EDITOR carbone/configuration.rb
  cd carbone
  make gen

  ./gen -h
  ./gen -c tests/fib.lg
  make tests
  make all-tests

and to build an optimized VM:
  change to `DEBUG = false' in carbone/configuration.rb

  make opt t=tests/fib.lg

this will profile the VM using the given code; measure the unoptimized
VM  and then  re-compile it  with appropriate  super-instructions. The
resulting  VM is  named `$(t).vm',  so in  the example  this  would be
`tests/fib.lg.vm'.  You can see  that by running `tests/fib.lg.vm -V',
which will tell you something like:

| Carbone v0.1 -- A efficient Ruby VM
|   # of superinstructions : 39
|   class-method cache     : hash
| initialized

Note  that the number  of super-instructions  is not  0.  The  list of
super-instructions  rests in  vm/rb-super.vmg; and  one can  see which
super-instructions got applied to some code by using the -c flag.

Global  configuration data  is  kept in  configuration.rb.  The  files
configuration.h  and Makefile.conf are  produced when  executing `ruby
configure.rb' (but  this is done automatically  if configuration.rb is
changed; and in this case old *.o files are also swept away).

Input Language

The input language  - Carbone's first native language  - is Lisp-like,
corresponding to a subset of LGram level 1.

It is parsed and precompiled Ruby code.

see doc/input_language.txt


./gen [options] [ file | -e string ]
-h      Print this message and exit
-c      dump compiled code before execution
-t      trace execution
-e      use commandline for input
-p      profile VM code sequences >stderr
-i      inspect compilation of vm builtins
-V      version info plus details about VM internals
-S      don't use superinstructions
-s      print statistics

for example:

[.../carbone] ./gen -sScte "(send (lit 1) + ((lit 2)))"
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
send (lit 1) + ((lit 2))
-   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -
0x849d0d0: lit 0x1  
0x849d0d8: lit 0x2  
0x849d0e0: swap
0x849d0e4: lit 0x7c  
0x849d0ec: lit 0x1  
0x849d0f4: send
0x849d0f8: nip
0x849d0fc: end
-   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -   -
entering engine(0x849d0d0,0x863887c,(nil))
0x849d0d0: lit     , fp=(nil), sp=0x863887c i=0x1   -- 
0x849d0d8: lit     , fp=(nil), sp=0x8638878 i=0x2   -- 
0x849d0e0: swap    , fp=(nil), sp=0x8638874 i1=0x1   i2=0x2   -- 
0x849d0e4: lit     , fp=(nil), sp=0x8638874 i=0x7c   -- 
0x849d0ec: lit     , fp=(nil), sp=0x8638870 i=0x1   -- 
0x849d0f4: send    , fp=(nil), sp=0x863886c rcv=0x1   sel=+<0x7c>
               inpar=0x1   --  retip=0xbffff97c   oldfp=0x400aeb78  
0x849d0f4: fixnumPlus, fp=(nil), sp=0x8638868 other=0x2   rcv=0x1
               inpar=0x1   retip=0xbffff97c   oldfp=0x400aeb78   --  ires=0x3  
0x849d0f8: nip     , fp=(nil), sp=0x8638874 i1=0x2   i=0x3   -- 
0x849d0fc: end     , fp=(nil), sp=0x8638878 i=0x3  
   ==> 0x3 (3)
.uncached method searches: 1

`send' is the interesting instruction, that transfers control to the
implementation of Fixnum#+, which is a instruction named `fixnumPlus' in
the current implementation. The `lit' instructs before it exist "only"
to push receiver, selector, parameters and number of parameters in a
well defined order, so that send and the method implementation can
refind them.

`nip'   is  necessary   to  throw   away  the   parameter   (which  is
responsability of the caller); The stack effect of `nip' is

  `( i1 i -- i )'       (as seen in vm/rb-inst.vmg)

which means:

left side of `--'    pop stack-top into variable i
                     pop next stack-top into variable i1

right side of `--'   push i as new stack-top

The net  effect is to pull out  the stack element under  the top stack
element (which  is the result of  the called method,  Fixnum#+ in this
case).  The instruction generator puts in one `nip' for each parameter
(as seen in comp/generator.c#374)

The GForth manual is a good read.


I see Carbone running about seven times faster than matz' Ruby machine
(on PentiumIII hardware). This  happens especially with code that does
not use  lots of  builtins (like Fixnum#+,  ...); They are  compiled C
code like in matz' Ruby machine). But with code that recurses or calls
other methods that are implemented  in Ruby (better said: Carbon input
language).  From obvious reasons  the mentioned improvment factor will
go down to zero when spending  all the time in builtins; (long running
builtins, not Fixnum#+;  but this effect begins with  it). One may say
snippets that do  no work are producing larger  speed improvments; but
this is  also the kind  of code one  calls object oriented;  i.e. many
levels of indirection, abstraction .....

Some of the files in  carbone/tests/ may be interesting. (I hope there
are no more  logical errors in this  code, so I will no  more report a
speed improvment factor of twenty,  when this only happens because the
corresponding Ruby code was different and doing the double work ... )

The produced assembler code for each VM instruction:

  cd carbone/vm; make engine.gdis; less engine.gdis