dotgnu-pnet-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[dotgnu-pnet-commits] libjit ChangeLog jitruby/README jitruby/generat...


From: Aleksey Demakov
Subject: [dotgnu-pnet-commits] libjit ChangeLog jitruby/README jitruby/generat...
Date: Fri, 12 Dec 2008 11:31:06 +0000

CVSROOT:        /sources/dotgnu-pnet
Module name:    libjit
Changes by:     Aleksey Demakov <avd>   08/12/12 11:31:05

Modified files:
        .              : ChangeLog 
Added files:
        jitruby        : README generate_rdoc.rb metaconfig 
                         post-install.rb post-setup.rb 
                         ruby-libjit.gemspec run_tests.rb setup.rb 
        jitruby/ext    : extconf.rb insns.inc.rpp jit.c 
                         method_data.c.rpp method_data.h minimal_node.c 
                         minimal_node.h rubyjit.h rubypp.rb 
        jitruby/lib    : jit.rb 
        jitruby/lib/jit: array.rb function.rb pointer.rb struct.rb 
                         value.rb 
        jitruby/sample : fib.rb gcd_benchmark.rb simple.rb 
        jitruby/test   : assertions.rb test_jit_array.rb 
                         test_jit_function.rb test_jit_pointer.rb 
                         test_jit_struct.rb test_jit_value.rb 

Log message:
        add Paul Brannan's ruby-libjit

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/libjit/ChangeLog?cvsroot=dotgnu-pnet&r1=1.397&r2=1.398
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/README?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/generate_rdoc.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/metaconfig?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/post-install.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/post-setup.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/ruby-libjit.gemspec?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/run_tests.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/setup.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/ext/extconf.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/ext/insns.inc.rpp?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/ext/jit.c?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/ext/method_data.c.rpp?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/ext/method_data.h?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/ext/minimal_node.c?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/ext/minimal_node.h?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/ext/rubyjit.h?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/ext/rubypp.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/lib/jit.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/lib/jit/array.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/lib/jit/function.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/lib/jit/pointer.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/lib/jit/struct.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/lib/jit/value.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/sample/fib.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/sample/gcd_benchmark.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/sample/simple.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/test/assertions.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/test/test_jit_array.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/test/test_jit_function.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/test/test_jit_pointer.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/test/test_jit_struct.rb?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/libjit/jitruby/test/test_jit_value.rb?cvsroot=dotgnu-pnet&rev=1.1

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/ChangeLog,v
retrieving revision 1.397
retrieving revision 1.398
diff -u -b -r1.397 -r1.398
--- ChangeLog   10 Dec 2008 20:44:24 -0000      1.397
+++ ChangeLog   12 Dec 2008 11:30:57 -0000      1.398
@@ -1,3 +1,7 @@
+2008-12-12  Aleksey Demakov  <address@hidden>
+
+       * jitruby/*: add Paul Brannan's ruby-libjit.
+
 2008-12-11  Juan Jesus Garcia de Soria  <address@hidden>
 
        * jit/jit-insn.c (jit_insn_call_native): extend small int return

Index: jitruby/README
===================================================================
RCS file: jitruby/README
diff -N jitruby/README
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/README      12 Dec 2008 11:30:57 -0000      1.1
@@ -0,0 +1,50 @@
+Ruby-libjit 0.1.0
+Copyright (C) 2008 Paul Brannan
+
+Ruby-libjit is a wrapper for the libjit library.  It provides basic
+functionality for jit-compiling functions, including integrating those
+functions as callable methods from within Ruby.  Abstractions are also
+provided so that jit code may be written in a ruby-like manner.
+
+Please see the file COPYING for license information.
+
+A simple example:
+
+  :include: sample/simple.rb
+
+Looping structures and other abstractions are provided to make writing
+jit code easier:
+
+  :include: sample/fib.rb
+
+To build ruby-libjit, you will need to install libjit.  If it is not
+available pre-compiled for your platform, you may build the latest
+release like this:
+
+  $ wget ftp://ftp.gnu.org/gnu/dotgnu/pnet/libjit-0.1.0.tar.gz
+  $ tar xvfz libjit-0.1.0.tar.gz
+  $ cd libjit-0.1.0
+  $ ./configure
+  $ make
+  $ sudo make install
+
+Or the latest development version like this:
+
+  $ cvs -z3 -d:pserver:address@hidden:/sources/dotgnu-pnet co libjit
+  $ cd libjit
+  $ ./auto_gen.sh
+  $ ./configure
+  $ make
+  $ sudo make install
+
+To build ruby-libjit, run setup.rb:
+
+  $ ruby setup.rb config
+  $ ruby setup.rb setup
+  $ sudo ruby setup.rb install
+
+For a more complete JIT framework and compiler for Ruby code, please
+take a look at Ludicrous:
+
+  http://rubystuff.org/ludicrous/
+

Index: jitruby/generate_rdoc.rb
===================================================================
RCS file: jitruby/generate_rdoc.rb
diff -N jitruby/generate_rdoc.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/generate_rdoc.rb    12 Dec 2008 11:30:58 -0000      1.1
@@ -0,0 +1,33 @@
+require 'find'
+
+def list_files(dir, pattern)
+  arr = []
+  Find.find(dir) do |filename|
+    if filename =~ pattern then
+      arr.push(filename)
+    end
+  end
+  return arr
+end
+
+def generate_rdoc(*options)
+  begin
+    require 'rdoc/rdoc'
+  rescue LoadError
+    puts "WARNING: RDoc not installed; skipping generation of docs"
+    return
+  end
+
+  r = RDoc::RDoc.new
+  rdoc_files = []
+  rdoc_files.concat [ 'README' ]
+  rdoc_files.concat list_files('lib', /\.rb$/) if File.exist?('lib')
+  rdoc_files.concat list_files('ext', /\.c$/)  if File.exist?('ext')
+  rdoc_files.reject! { |file| file =~ %r{^ext/cached/} }
+  r.document(options + rdoc_files)
+end
+
+if __FILE__ == $0 then
+  generate_rdoc(*ARGV)
+end
+

Index: jitruby/metaconfig
===================================================================
RCS file: jitruby/metaconfig
diff -N jitruby/metaconfig
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/metaconfig  12 Dec 2008 11:30:58 -0000      1.1
@@ -0,0 +1,4 @@
+add_bool_config(
+  'without-tests',
+  false,
+  'does not run tests')

Index: jitruby/post-install.rb
===================================================================
RCS file: jitruby/post-install.rb
diff -N jitruby/post-install.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/post-install.rb     12 Dec 2008 11:30:58 -0000      1.1
@@ -0,0 +1,4 @@
+require 'generate_rdoc'
+
+generate_rdoc('--ri-site')
+

Index: jitruby/post-setup.rb
===================================================================
RCS file: jitruby/post-setup.rb
diff -N jitruby/post-setup.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/post-setup.rb       12 Dec 2008 11:30:58 -0000      1.1
@@ -0,0 +1,7 @@
+require 'run_tests'
+require 'generate_rdoc'
+
+if config('without-tests') != 'yes' then
+  run_tests()
+end
+

Index: jitruby/ruby-libjit.gemspec
===================================================================
RCS file: jitruby/ruby-libjit.gemspec
diff -N jitruby/ruby-libjit.gemspec
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/ruby-libjit.gemspec 12 Dec 2008 11:30:58 -0000      1.1
@@ -0,0 +1,39 @@
+require 'enumerator'
+
+spec = Gem::Specification.new do |s|
+  s.name = 'ruby-libjit'
+  s.version = '0.1.0'
+  s.summary = 'A wrapper for the libjit library'
+  s.homepage = 'http://ruby-libjit.rubyforge.org'
+  s.rubyforge_project = 'ruby-libjit'
+  s.author = 'Paul Brannan'
+  s.email = 'address@hidden'
+
+  s.description = <<-END
+A wrapper for the libjit library
+  END
+
+
+  patterns = [
+    'COPYING',
+    'LGPL',
+    'LICENSE',
+    'README',
+    'lib/*.rb',
+    'lib/jit/*.rb',
+    'ext/*.rb',
+    'ext/*.c',
+    'ext/*.h',
+    'ext/*.rpp',
+    'sample/*.rb',
+  ]
+
+  s.files = patterns.collect { |p| Dir.glob(p) }.flatten
+
+  s.test_files = Dir.glob('test/test_*.rb')
+
+  s.extensions = 'ext/extconf.rb'
+
+  s.has_rdoc = true
+end
+

Index: jitruby/run_tests.rb
===================================================================
RCS file: jitruby/run_tests.rb
diff -N jitruby/run_tests.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/run_tests.rb        12 Dec 2008 11:30:58 -0000      1.1
@@ -0,0 +1,81 @@
+$mini_unit_exit_code = 0
+
+def disable_mini_unit_auto_run
+  MiniTest::Unit.class_eval do
+    alias :run_ :run
+    def run(*args)
+      return $mini_unit_exit_code
+    end
+  end
+end
+
+def run_tests_with_mini_unit
+  begin
+    test = MiniTest::Unit.new
+    args = ARGV.dup
+    args << '-v'
+    $mini_unit_exit_code = test.run(args)
+    exit($mini_unit_exit_code)
+  ensure
+    disable_mini_unit_auto_run
+  end
+end
+
+def run_tests_with_test_unit
+  tests = []
+  ObjectSpace.each_object(Class) do |o|
+    if o < Test::Unit::TestCase then
+      tests << o
+    end
+  end
+
+  suite = Test::Unit::TestSuite.new("RubyInternal")
+  tests.each do |test|
+    test.suite.tests.each do |testcase|
+      suite << testcase
+    end
+  end
+
+  require 'test/unit/ui/console/testrunner'
+  verbose = nil
+  begin
+    verbose = Test::Unit::UI.const_get(:VERBOSE)
+  rescue NameError
+    verbose = Test::Unit::UI::Console::TestRunner.const_get(:VERBOSE)
+  end
+
+  result = Test::Unit::UI::Console::TestRunner.run(
+      suite,
+      verbose)
+  exit(result.error_count + result.failure_count)
+end
+
+def run_tests
+  begin
+    require 'test/unit'
+  rescue LoadError
+    puts "WARNING: Test::Unit not installed; skipping tests"
+    return
+  end
+
+  $:.unshift(File.join(Dir.pwd, 'ext'))
+  $:.unshift(File.join(Dir.pwd, 'lib'))
+  Dir.chdir('test')
+  tests = Dir['test_*.rb']
+  tests.each do |test|
+    load test
+  end
+
+  if defined?(MiniTest) then
+    run_tests_with_mini_unit
+  else
+    run_tests_with_test_unit
+  end
+end
+
+if __FILE__ == $0 then
+  require 'timeout'
+  result = nil
+  timeout(600) { run_tests() }
+end
+

Index: jitruby/setup.rb
===================================================================
RCS file: jitruby/setup.rb
diff -N jitruby/setup.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/setup.rb    12 Dec 2008 11:30:58 -0000      1.1
@@ -0,0 +1,1599 @@
+#
+# setup.rb
+#
+# Copyright (c) 2000-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+#
+
+unless Enumerable.method_defined?(:map)   # Ruby 1.4.6
+  module Enumerable
+    alias map collect
+  end
+end
+
+unless File.respond_to?(:read)   # Ruby 1.6
+  def File.read(fname)
+    open(fname) {|f|
+      return f.read
+    }
+  end
+end
+
+unless Errno.const_defined?(:ENOTEMPTY)   # Windows?
+  module Errno
+    class ENOTEMPTY
+      # We do not raise this exception, implementation is not needed.
+    end
+  end
+end
+
+def File.binread(fname)
+  open(fname, 'rb') {|f|
+    return f.read
+  }
+end
+
+# for corrupted Windows' stat(2)
+def File.dir?(path)
+  File.directory?((path[-1,1] == '/') ? path : path + '/')
+end
+
+
+class ConfigTable
+
+  include Enumerable
+
+  def initialize(rbconfig)
+    @rbconfig = rbconfig
+    @items = []
+    @table = {}
+    # options
+    @install_prefix = nil
+    @config_opt = nil
+    @verbose = true
+    @no_harm = false
+  end
+
+  attr_accessor :install_prefix
+  attr_accessor :config_opt
+
+  attr_writer :verbose
+
+  def verbose?
+    @verbose
+  end
+
+  attr_writer :no_harm
+
+  def no_harm?
+    @no_harm
+  end
+
+  def [](key)
+    lookup(key).resolve(self)
+  end
+
+  def []=(key, val)
+    lookup(key).set val
+  end
+
+  def names
+    @items.map {|i| i.name }
+  end
+
+  def each(&block)
+    @items.each(&block)
+  end
+
+  def key?(name)
+    @table.key?(name)
+  end
+
+  def lookup(name)
+    @table[name] or setup_rb_error "no such config item: #{name}"
+  end
+
+  def add(item)
+    @items.push item
+    @table[item.name] = item
+  end
+
+  def remove(name)
+    item = lookup(name)
+    @items.delete_if {|i| i.name == name }
+    @table.delete_if {|name, i| i.name == name }
+    item
+  end
+
+  def load_script(path, inst = nil)
+    if File.file?(path)
+      MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
+    end
+  end
+
+  def savefile
+    '.config'
+  end
+
+  def load_savefile
+    begin
+      File.foreach(savefile()) do |line|
+        k, v = *line.split(/=/, 2)
+        self[k] = v.strip
+      end
+    rescue Errno::ENOENT
+      setup_rb_error $!.message + "\n#{File.basename($0)} config first"
+    end
+  end
+
+  def save
+    @items.each {|i| i.value }
+    File.open(savefile(), 'w') {|f|
+      @items.each do |i|
+        f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
+      end
+    }
+  end
+
+  def load_standard_entries
+    standard_entries(@rbconfig).each do |ent|
+      add ent
+    end
+  end
+
+  def standard_entries(rbconfig)
+    c = rbconfig
+
+    rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
+
+    major = c['MAJOR'].to_i
+    minor = c['MINOR'].to_i
+    teeny = c['TEENY'].to_i
+    version = "#{major}.#{minor}"
+
+    # ruby ver. >= 1.4.4?
+    newpath_p = ((major >= 2) or
+                 ((major == 1) and
+                  ((minor >= 5) or
+                   ((minor == 4) and (teeny >= 4)))))
+
+    if c['rubylibdir']
+      # V > 1.6.3
+      libruby         = "#{c['prefix']}/lib/ruby"
+      librubyver      = c['rubylibdir']
+      librubyverarch  = c['archdir']
+      siteruby        = c['sitedir']
+      siterubyver     = c['sitelibdir']
+      siterubyverarch = c['sitearchdir']
+    elsif newpath_p
+      # 1.4.4 <= V <= 1.6.3
+      libruby         = "#{c['prefix']}/lib/ruby"
+      librubyver      = "#{c['prefix']}/lib/ruby/#{version}"
+      librubyverarch  = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
+      siteruby        = c['sitedir']
+      siterubyver     = "$siteruby/#{version}"
+      siterubyverarch = "$siterubyver/#{c['arch']}"
+    else
+      # V < 1.4.4
+      libruby         = "#{c['prefix']}/lib/ruby"
+      librubyver      = "#{c['prefix']}/lib/ruby/#{version}"
+      librubyverarch  = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
+      siteruby        = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
+      siterubyver     = siteruby
+      siterubyverarch = "$siterubyver/#{c['arch']}"
+    end
+    parameterize = lambda {|path|
+      path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
+    }
+
+    if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ 
arg }
+      makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
+    else
+      makeprog = 'make'
+    end
+
+    [
+      ExecItem.new('installdirs', 'std/site/home',
+                   'std: install under libruby; site: install under site_ruby; 
home: install under $HOME')\
+          {|val, table|
+            case val
+            when 'std'
+              table['rbdir'] = '$librubyver'
+              table['sodir'] = '$librubyverarch'
+            when 'site'
+              table['rbdir'] = '$siterubyver'
+              table['sodir'] = '$siterubyverarch'
+            when 'home'
+              setup_rb_error '$HOME was not set' unless ENV['HOME']
+              table['prefix'] = ENV['HOME']
+              table['rbdir'] = '$libdir/ruby'
+              table['sodir'] = '$libdir/ruby'
+            end
+          },
+      PathItem.new('prefix', 'path', c['prefix'],
+                   'path prefix of target environment'),
+      PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
+                   'the directory for commands'),
+      PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
+                   'the directory for libraries'),
+      PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
+                   'the directory for shared data'),
+      PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
+                   'the directory for man pages'),
+      PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
+                   'the directory for system configuration files'),
+      PathItem.new('localstatedir', 'path', 
parameterize.call(c['localstatedir']),
+                   'the directory for local state data'),
+      PathItem.new('libruby', 'path', libruby,
+                   'the directory for ruby libraries'),
+      PathItem.new('librubyver', 'path', librubyver,
+                   'the directory for standard ruby libraries'),
+      PathItem.new('librubyverarch', 'path', librubyverarch,
+                   'the directory for standard ruby extensions'),
+      PathItem.new('siteruby', 'path', siteruby,
+          'the directory for version-independent aux ruby libraries'),
+      PathItem.new('siterubyver', 'path', siterubyver,
+                   'the directory for aux ruby libraries'),
+      PathItem.new('siterubyverarch', 'path', siterubyverarch,
+                   'the directory for aux ruby binaries'),
+      PathItem.new('rbdir', 'path', '$siterubyver',
+                   'the directory for ruby scripts'),
+      PathItem.new('sodir', 'path', '$siterubyverarch',
+                   'the directory for ruby extentions'),
+      PathItem.new('rubypath', 'path', rubypath,
+                   'the path to set to #! line'),
+      ProgramItem.new('rubyprog', 'name', rubypath,
+                      'the ruby program using for installation'),
+      ProgramItem.new('makeprog', 'name', makeprog,
+                      'the make program to compile ruby extentions'),
+      SelectItem.new('shebang', 'all/ruby/never', 'ruby',
+                     'shebang line (#!) editing mode'),
+      BoolItem.new('without-ext', 'yes/no', 'no',
+                   'does not compile/install ruby extentions')
+    ]
+  end
+  private :standard_entries
+
+  def load_multipackage_entries
+    multipackage_entries().each do |ent|
+      add ent
+    end
+  end
+
+  def multipackage_entries
+    [
+      PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
+                               'package names that you want to install'),
+      PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
+                               'package names that you do not want to install')
+    ]
+  end
+  private :multipackage_entries
+
+  ALIASES = {
+    'std-ruby'         => 'librubyver',
+    'stdruby'          => 'librubyver',
+    'rubylibdir'       => 'librubyver',
+    'archdir'          => 'librubyverarch',
+    'site-ruby-common' => 'siteruby',     # For backward compatibility
+    'site-ruby'        => 'siterubyver',  # For backward compatibility
+    'bin-dir'          => 'bindir',
+    'bin-dir'          => 'bindir',
+    'rb-dir'           => 'rbdir',
+    'so-dir'           => 'sodir',
+    'data-dir'         => 'datadir',
+    'ruby-path'        => 'rubypath',
+    'ruby-prog'        => 'rubyprog',
+    'ruby'             => 'rubyprog',
+    'make-prog'        => 'makeprog',
+    'make'             => 'makeprog'
+  }
+
+  def fixup
+    ALIASES.each do |ali, name|
+      @table[ali] = @table[name]
+    end
+  end
+
+  def options_re
+    /\A--(address@hidden('|')})(?:=(.*))?\z/
+  end
+
+  def parse_opt(opt)
+    m = options_re().match(opt) or setup_rb_error "config: unknown option 
#{opt}"
+    m.to_a[1,2]
+  end
+
+  def dllext
+    @rbconfig['DLEXT']
+  end
+
+  def value_config?(name)
+    lookup(name).value?
+  end
+
+  class Item
+    def initialize(name, template, default, desc)
+      @name = name.freeze
+      @template = template
+      @value = default
+      @default = default
+      @description = desc
+    end
+
+    attr_reader :name
+    attr_reader :description
+
+    attr_accessor :default
+    alias help_default default
+
+    def help_opt
+      "address@hidden@template}"
+    end
+
+    def value?
+      true
+    end
+
+    def value
+      @value
+    end
+
+    def resolve(table)
+      @value.gsub(%r<\$([^/]+)>) { table[$1] }
+    end
+
+    def set(val)
+      @value = check(val)
+    end
+
+    private
+
+    def check(val)
+      setup_rb_error "config: --#{name} requires argument" unless val
+      val
+    end
+  end
+
+  class BoolItem < Item
+    def config_type
+      'bool'
+    end
+
+    def help_opt
+      "address@hidden"
+    end
+
+    private
+
+    def check(val)
+      return 'yes' unless val
+      case val
+      when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
+      when /\An(o)?\z/i, /\Af(alse)\z/i  then 'no'
+      else
+        setup_rb_error "config: address@hidden accepts only yes/no for 
argument"
+      end
+    end
+  end
+
+  class PathItem < Item
+    def config_type
+      'path'
+    end
+
+    private
+
+    def check(path)
+      setup_rb_error "config: address@hidden requires argument"  unless path
+      path[0,1] == '$' ? path : File.expand_path(path)
+    end
+  end
+
+  class ProgramItem < Item
+    def config_type
+      'program'
+    end
+  end
+
+  class SelectItem < Item
+    def initialize(name, selection, default, desc)
+      super
+      @ok = selection.split('/')
+    end
+
+    def config_type
+      'select'
+    end
+
+    private
+
+    def check(val)
+      unless @ok.include?(val.strip)
+        setup_rb_error "config: use address@hidden@template} (#{val})"
+      end
+      val.strip
+    end
+  end
+
+  class ExecItem < Item
+    def initialize(name, selection, desc, &block)
+      super name, selection, nil, desc
+      @ok = selection.split('/')
+      @action = block
+    end
+
+    def config_type
+      'exec'
+    end
+
+    def value?
+      false
+    end
+
+    def resolve(table)
+      setup_rb_error "$#{name()} wrongly used as option value"
+    end
+
+    undef set
+
+    def evaluate(val, table)
+      v = val.strip.downcase
+      unless @ok.include?(v)
+        setup_rb_error "invalid option address@hidden (use address@hidden)"
+      end
+      @action.call v, table
+    end
+  end
+
+  class PackageSelectionItem < Item
+    def initialize(name, template, default, help_default, desc)
+      super name, template, default, desc
+      @help_default = help_default
+    end
+
+    attr_reader :help_default
+
+    def config_type
+      'package'
+    end
+
+    private
+
+    def check(val)
+      unless File.dir?("packages/#{val}")
+        setup_rb_error "config: no such package: #{val}"
+      end
+      val
+    end
+  end
+
+  class MetaConfigEnvironment
+    def initialize(config, installer)
+      @config = config
+      @installer = installer
+    end
+
+    def config_names
+      @config.names
+    end
+
+    def config?(name)
+      @config.key?(name)
+    end
+
+    def bool_config?(name)
+      @config.lookup(name).config_type == 'bool'
+    end
+
+    def path_config?(name)
+      @config.lookup(name).config_type == 'path'
+    end
+
+    def value_config?(name)
+      @config.lookup(name).config_type != 'exec'
+    end
+
+    def add_config(item)
+      @config.add item
+    end
+
+    def add_bool_config(name, default, desc)
+      @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
+    end
+
+    def add_path_config(name, default, desc)
+      @config.add PathItem.new(name, 'path', default, desc)
+    end
+
+    def set_config_default(name, default)
+      @config.lookup(name).default = default
+    end
+
+    def remove_config(name)
+      @config.remove(name)
+    end
+
+    # For only multipackage
+    def packages
+      raise '[setup.rb fatal] multi-package metaconfig API packages() called 
for single-package; contact application package vendor' unless @installer
+      @installer.packages
+    end
+
+    # For only multipackage
+    def declare_packages(list)
+      raise '[setup.rb fatal] multi-package metaconfig API declare_packages() 
called for single-package; contact application package vendor' unless @installer
+      @installer.packages = list
+    end
+  end
+
+end   # class ConfigTable
+
+
+# This module requires: #verbose?, #no_harm?
+module FileOperations
+
+  def mkdir_p(dirname, prefix = nil)
+    dirname = prefix + File.expand_path(dirname) if prefix
+    $stderr.puts "mkdir -p #{dirname}" if verbose?
+    return if no_harm?
+
+    # Does not check '/', it's too abnormal.
+    dirs = File.expand_path(dirname).split(%r<(?=/)>)
+    if /\A[a-z]:\z/i =~ dirs[0]
+      disk = dirs.shift
+      dirs[0] = disk + dirs[0]
+    end
+    dirs.each_index do |idx|
+      path = dirs[0..idx].join('')
+      Dir.mkdir path unless File.dir?(path)
+    end
+  end
+
+  def rm_f(path)
+    $stderr.puts "rm -f #{path}" if verbose?
+    return if no_harm?
+    force_remove_file path
+  end
+
+  def rm_rf(path)
+    $stderr.puts "rm -rf #{path}" if verbose?
+    return if no_harm?
+    remove_tree path
+  end
+
+  def remove_tree(path)
+    if File.symlink?(path)
+      remove_file path
+    elsif File.dir?(path)
+      remove_tree0 path
+    else
+      force_remove_file path
+    end
+  end
+
+  def remove_tree0(path)
+    Dir.foreach(path) do |ent|
+      next if ent == '.'
+      next if ent == '..'
+      entpath = "#{path}/#{ent}"
+      if File.symlink?(entpath)
+        remove_file entpath
+      elsif File.dir?(entpath)
+        remove_tree0 entpath
+      else
+        force_remove_file entpath
+      end
+    end
+    begin
+      Dir.rmdir path
+    rescue Errno::ENOTEMPTY
+      # directory may not be empty
+    end
+  end
+
+  def move_file(src, dest)
+    force_remove_file dest
+    begin
+      File.rename src, dest
+    rescue
+      File.open(dest, 'wb') {|f|
+        f.write File.binread(src)
+      }
+      File.chmod File.stat(src).mode, dest
+      File.unlink src
+    end
+  end
+
+  def force_remove_file(path)
+    begin
+      remove_file path
+    rescue
+    end
+  end
+
+  def remove_file(path)
+    File.chmod 0777, path
+    File.unlink path
+  end
+
+  def install(from, dest, mode, prefix = nil)
+    $stderr.puts "install #{from} #{dest}" if verbose?
+    return if no_harm?
+
+    realdest = prefix ? prefix + File.expand_path(dest) : dest
+    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
+    str = File.binread(from)
+    if diff?(str, realdest)
+      verbose_off {
+        rm_f realdest if File.exist?(realdest)
+      }
+      File.open(realdest, 'wb') {|f|
+        f.write str
+      }
+      File.chmod mode, realdest
+
+      File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
+        if prefix
+          f.puts realdest.sub(prefix, '')
+        else
+          f.puts realdest
+        end
+      }
+    end
+  end
+
+  def diff?(new_content, path)
+    return true unless File.exist?(path)
+    new_content != File.binread(path)
+  end
+
+  def command(*args)
+    $stderr.puts args.join(' ') if verbose?
+    system(*args) or raise RuntimeError,
+        "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
+  end
+
+  def ruby(*args)
+    command config('rubyprog'), *args
+  end
+  
+  def make(task = nil)
+    command(*[config('makeprog'), task].compact)
+  end
+
+  def extdir?(dir)
+    File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
+  end
+
+  def files_of(dir)
+    Dir.open(dir) {|d|
+      return d.select {|ent| File.file?("#{dir}/#{ent}") }
+    }
+  end
+
+  DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
+
+  def directories_of(dir)
+    Dir.open(dir) {|d|
+      return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
+    }
+  end
+
+end
+
+
+# This module requires: #srcdir_root, #objdir_root, #relpath
+module HookScriptAPI
+
+  def get_config(key)
+    @config[key]
+  end
+
+  alias config get_config
+
+  # obsolete: use metaconfig to change configuration
+  def set_config(key, val)
+    @config[key] = val
+  end
+
+  #
+  # srcdir/objdir (works only in the package directory)
+  #
+
+  def curr_srcdir
+    "#{srcdir_root()}/#{relpath()}"
+  end
+
+  def curr_objdir
+    "#{objdir_root()}/#{relpath()}"
+  end
+
+  def srcfile(path)
+    "#{curr_srcdir()}/#{path}"
+  end
+
+  def srcexist?(path)
+    File.exist?(srcfile(path))
+  end
+
+  def srcdirectory?(path)
+    File.dir?(srcfile(path))
+  end
+  
+  def srcfile?(path)
+    File.file?(srcfile(path))
+  end
+
+  def srcentries(path = '.')
+    Dir.open("#{curr_srcdir()}/#{path}") {|d|
+      return d.to_a - %w(. ..)
+    }
+  end
+
+  def srcfiles(path = '.')
+    srcentries(path).select {|fname|
+      File.file?(File.join(curr_srcdir(), path, fname))
+    }
+  end
+
+  def srcdirectories(path = '.')
+    srcentries(path).select {|fname|
+      File.dir?(File.join(curr_srcdir(), path, fname))
+    }
+  end
+
+end
+
+
+class ToplevelInstaller
+
+  Version   = '3.4.1'
+  Copyright = 'Copyright (c) 2000-2006 Minero Aoki'
+
+  TASKS = [
+    [ 'all',      'do config, setup, then install' ],
+    [ 'config',   'saves your configurations' ],
+    [ 'show',     'shows current configuration' ],
+    [ 'setup',    'compiles ruby extentions and others' ],
+    [ 'install',  'installs files' ],
+    [ 'test',     'run all tests in test/' ],
+    [ 'clean',    "does `make clean' for each extention" ],
+    [ 'distclean',"does `make distclean' for each extention" ]
+  ]
+
+  def ToplevelInstaller.invoke
+    config = ConfigTable.new(load_rbconfig())
+    config.load_standard_entries
+    config.load_multipackage_entries if multipackage?
+    config.fixup
+    klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
+    klass.new(File.dirname($0), config).invoke
+  end
+
+  def ToplevelInstaller.multipackage?
+    File.dir?(File.dirname($0) + '/packages')
+  end
+
+  def ToplevelInstaller.load_rbconfig
+    if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
+      ARGV.delete(arg)
+      load File.expand_path(arg.split(/=/, 2)[1])
+      $".push 'rbconfig.rb'
+    else
+      require 'rbconfig'
+    end
+    ::Config::CONFIG
+  end
+
+  def initialize(ardir_root, config)
+    @ardir = File.expand_path(ardir_root)
+    @config = config
+    # cache
+    @valid_task_re = nil
+  end
+
+  def config(key)
+    @config[key]
+  end
+
+  def inspect
+    "#<#{self.class} #{__id__()}>"
+  end
+
+  def invoke
+    run_metaconfigs
+    case task = parsearg_global()
+    when nil, 'all'
+      parsearg_config
+      init_installers
+      exec_config
+      exec_setup
+      exec_install
+    else
+      case task
+      when 'config', 'test'
+        ;
+      when 'clean', 'distclean'
+        @config.load_savefile if File.exist?(@config.savefile)
+      else
+        @config.load_savefile
+      end
+      __send__ "parsearg_#{task}"
+      init_installers
+      __send__ "exec_#{task}"
+    end
+  end
+  
+  def run_metaconfigs
+    @config.load_script "address@hidden/metaconfig"
+  end
+
+  def init_installers
+    @installer = Installer.new(@config, @ardir, File.expand_path('.'))
+  end
+
+  #
+  # Hook Script API bases
+  #
+
+  def srcdir_root
+    @ardir
+  end
+
+  def objdir_root
+    '.'
+  end
+
+  def relpath
+    '.'
+  end
+
+  #
+  # Option Parsing
+  #
+
+  def parsearg_global
+    while arg = ARGV.shift
+      case arg
+      when /\A\w+\z/
+        setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
+        return arg
+      when '-q', '--quiet'
+        @config.verbose = false
+      when '--verbose'
+        @config.verbose = true
+      when '--help'
+        print_usage $stdout
+        exit 0
+      when '--version'
+        puts "#{File.basename($0)} version #{Version}"
+        exit 0
+      when '--copyright'
+        puts Copyright
+        exit 0
+      else
+        setup_rb_error "unknown global option '#{arg}'"
+      end
+    end
+    nil
+  end
+
+  def valid_task?(t)
+    valid_task_re() =~ t
+  end
+
+  def valid_task_re
+    @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
+  end
+
+  def parsearg_no_options
+    unless ARGV.empty?
+      task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
+      setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
+    end
+  end
+
+  alias parsearg_show       parsearg_no_options
+  alias parsearg_setup      parsearg_no_options
+  alias parsearg_test       parsearg_no_options
+  alias parsearg_clean      parsearg_no_options
+  alias parsearg_distclean  parsearg_no_options
+
+  def parsearg_config
+    evalopt = []
+    set = []
+    @config.config_opt = []
+    while i = ARGV.shift
+      if /\A--?\z/ =~ i
+        @config.config_opt = ARGV.dup
+        break
+      end
+      name, value = address@hidden(i)
+      if @config.value_config?(name)
+        @config[name] = value
+      else
+        evalopt.push [name, value]
+      end
+      set.push name
+    end
+    evalopt.each do |name, value|
+      @config.lookup(name).evaluate value, @config
+    end
+    # Check if configuration is valid
+    set.each do |n|
+      @config[n] if @config.value_config?(n)
+    end
+  end
+
+  def parsearg_install
+    @config.no_harm = false
+    @config.install_prefix = ''
+    while a = ARGV.shift
+      case a
+      when '--no-harm'
+        @config.no_harm = true
+      when /\A--prefix=/
+        path = a.split(/=/, 2)[1]
+        path = File.expand_path(path) unless path[0,1] == '/'
+        @config.install_prefix = path
+      else
+        setup_rb_error "install: unknown option #{a}"
+      end
+    end
+  end
+
+  def print_usage(out)
+    out.puts 'Typical Installation Procedure:'
+    out.puts "  $ ruby #{File.basename $0} config"
+    out.puts "  $ ruby #{File.basename $0} setup"
+    out.puts "  # ruby #{File.basename $0} install (may require root 
privilege)"
+    out.puts
+    out.puts 'Detailed Usage:'
+    out.puts "  ruby #{File.basename $0} <global option>"
+    out.puts "  ruby #{File.basename $0} [<global options>] <task> [<task 
options>]"
+
+    fmt = "  %-24s %s\n"
+    out.puts
+    out.puts 'Global options:'
+    out.printf fmt, '-q,--quiet',   'suppress message outputs'
+    out.printf fmt, '   --verbose', 'output messages verbosely'
+    out.printf fmt, '   --help',    'print this message'
+    out.printf fmt, '   --version', 'print version and quit'
+    out.printf fmt, '   --copyright',  'print copyright and quit'
+    out.puts
+    out.puts 'Tasks:'
+    TASKS.each do |name, desc|
+      out.printf fmt, name, desc
+    end
+
+    fmt = "  %-24s %s [%s]\n"
+    out.puts
+    out.puts 'Options for CONFIG or ALL:'
+    @config.each do |item|
+      out.printf fmt, item.help_opt, item.description, item.help_default
+    end
+    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
+    out.puts
+    out.puts 'Options for INSTALL:'
+    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
+    out.printf fmt, '--prefix=path',  'install path prefix', ''
+    out.puts
+  end
+
+  #
+  # Task Handlers
+  #
+
+  def exec_config
+    @installer.exec_config
+    @config.save   # must be final
+  end
+
+  def exec_setup
+    @installer.exec_setup
+  end
+
+  def exec_install
+    @installer.exec_install
+  end
+
+  def exec_test
+    @installer.exec_test
+  end
+
+  def exec_show
+    @config.each do |i|
+      printf "%-20s %s\n", i.name, i.value if i.value?
+    end
+  end
+
+  def exec_clean
+    @installer.exec_clean
+  end
+
+  def exec_distclean
+    @installer.exec_distclean
+  end
+
+end   # class ToplevelInstaller
+
+
+class ToplevelInstallerMulti < ToplevelInstaller
+
+  include FileOperations
+
+  def initialize(ardir_root, config)
+    super
+    @packages = directories_of("address@hidden/packages")
+    raise 'no package exists' if @packages.empty?
+    @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
+  end
+
+  def run_metaconfigs
+    @config.load_script "address@hidden/metaconfig", self
+    @packages.each do |name|
+      @config.load_script "address@hidden/packages/#{name}/metaconfig"
+    end
+  end
+
+  attr_reader :packages
+
+  def packages=(list)
+    raise 'package list is empty' if list.empty?
+    list.each do |name|
+      raise "directory packages/#{name} does not exist"\
+              unless File.dir?("address@hidden/packages/#{name}")
+    end
+    @packages = list
+  end
+
+  def init_installers
+    @installers = {}
+    @packages.each do |pack|
+      @installers[pack] = Installer.new(@config,
+                                       "address@hidden/packages/#{pack}",
+                                       "packages/#{pack}")
+    end
+    with    = extract_selection(config('with'))
+    without = extract_selection(config('without'))
+    @selected = @installers.keys.select {|name|
+                  (with.empty? or with.include?(name)) \
+                      and not without.include?(name)
+                }
+  end
+
+  def extract_selection(list)
+    a = list.split(/,/)
+    a.each do |name|
+      setup_rb_error "no such package: #{name}"  unless @installers.key?(name)
+    end
+    a
+  end
+
+  def print_usage(f)
+    super
+    f.puts 'Inluded packages:'
+    f.puts '  ' + @packages.sort.join(' ')
+    f.puts
+  end
+
+  #
+  # Task Handlers
+  #
+
+  def exec_config
+    run_hook 'pre-config'
+    each_selected_installers {|inst| inst.exec_config }
+    run_hook 'post-config'
+    @config.save   # must be final
+  end
+
+  def exec_setup
+    run_hook 'pre-setup'
+    each_selected_installers {|inst| inst.exec_setup }
+    run_hook 'post-setup'
+  end
+
+  def exec_install
+    run_hook 'pre-install'
+    each_selected_installers {|inst| inst.exec_install }
+    run_hook 'post-install'
+  end
+
+  def exec_test
+    run_hook 'pre-test'
+    each_selected_installers {|inst| inst.exec_test }
+    run_hook 'post-test'
+  end
+
+  def exec_clean
+    rm_f @config.savefile
+    run_hook 'pre-clean'
+    each_selected_installers {|inst| inst.exec_clean }
+    run_hook 'post-clean'
+  end
+
+  def exec_distclean
+    rm_f @config.savefile
+    run_hook 'pre-distclean'
+    each_selected_installers {|inst| inst.exec_distclean }
+    run_hook 'post-distclean'
+  end
+
+  #
+  # lib
+  #
+
+  def each_selected_installers
+    Dir.mkdir 'packages' unless File.dir?('packages')
+    @selected.each do |pack|
+      $stderr.puts "Processing the package `#{pack}' ..." if verbose?
+      Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
+      Dir.chdir "packages/#{pack}"
+      yield @installers[pack]
+      Dir.chdir '../..'
+    end
+  end
+
+  def run_hook(id)
+    @root_installer.run_hook id
+  end
+
+  # module FileOperations requires this
+  def verbose?
+    @config.verbose?
+  end
+
+  # module FileOperations requires this
+  def no_harm?
+    @config.no_harm?
+  end
+
+end   # class ToplevelInstallerMulti
+
+
+class Installer
+
+  FILETYPES = %w( bin lib ext data conf man )
+
+  include FileOperations
+  include HookScriptAPI
+
+  def initialize(config, srcroot, objroot)
+    @config = config
+    @srcdir = File.expand_path(srcroot)
+    @objdir = File.expand_path(objroot)
+    @currdir = '.'
+  end
+
+  def inspect
+    "#<#{self.class} #{File.basename(@srcdir)}>"
+  end
+
+  def noop(rel)
+  end
+
+  #
+  # Hook Script API base methods
+  #
+
+  def srcdir_root
+    @srcdir
+  end
+
+  def objdir_root
+    @objdir
+  end
+
+  def relpath
+    @currdir
+  end
+
+  #
+  # Config Access
+  #
+
+  # module FileOperations requires this
+  def verbose?
+    @config.verbose?
+  end
+
+  # module FileOperations requires this
+  def no_harm?
+    @config.no_harm?
+  end
+
+  def verbose_off
+    begin
+      save, @config.verbose = @config.verbose?, false
+      yield
+    ensure
+      @config.verbose = save
+    end
+  end
+
+  #
+  # TASK config
+  #
+
+  def exec_config
+    exec_task_traverse 'config'
+  end
+
+  alias config_dir_bin noop
+  alias config_dir_lib noop
+
+  def config_dir_ext(rel)
+    extconf if extdir?(curr_srcdir())
+  end
+
+  alias config_dir_data noop
+  alias config_dir_conf noop
+  alias config_dir_man noop
+
+  def extconf
+    ruby "#{curr_srcdir()}/extconf.rb", address@hidden
+  end
+
+  #
+  # TASK setup
+  #
+
+  def exec_setup
+    exec_task_traverse 'setup'
+  end
+
+  def setup_dir_bin(rel)
+    files_of(curr_srcdir()).each do |fname|
+      update_shebang_line "#{curr_srcdir()}/#{fname}"
+    end
+  end
+
+  alias setup_dir_lib noop
+
+  def setup_dir_ext(rel)
+    make if extdir?(curr_srcdir())
+  end
+
+  alias setup_dir_data noop
+  alias setup_dir_conf noop
+  alias setup_dir_man noop
+
+  def update_shebang_line(path)
+    return if no_harm?
+    return if config('shebang') == 'never'
+    old = Shebang.load(path)
+    if old
+      $stderr.puts "warning: #{path}: Shebang line includes too many args.  It 
is not portable and your program may not work." if old.args.size > 1
+      new = new_shebang(old)
+      return if new.to_s == old.to_s
+    else
+      return unless config('shebang') == 'all'
+      new = Shebang.new(config('rubypath'))
+    end
+    $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
+    open_atomic_writer(path) {|output|
+      File.open(path, 'rb') {|f|
+        f.gets if old   # discard
+        output.puts new.to_s
+        output.print f.read
+      }
+    }
+  end
+
+  def new_shebang(old)
+    if /\Aruby/ =~ File.basename(old.cmd)
+      Shebang.new(config('rubypath'), old.args)
+    elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
+      Shebang.new(config('rubypath'), old.args[1..-1])
+    else
+      return old unless config('shebang') == 'all'
+      Shebang.new(config('rubypath'))
+    end
+  end
+
+  def open_atomic_writer(path, &block)
+    tmpfile = File.basename(path) + '.tmp'
+    begin
+      File.open(tmpfile, 'wb', &block)
+      File.rename tmpfile, File.basename(path)
+    ensure
+      File.unlink tmpfile if File.exist?(tmpfile)
+    end
+  end
+
+  class Shebang
+    def Shebang.load(path)
+      line = nil
+      File.open(path) {|f|
+        line = f.gets
+      }
+      return nil unless /\A#!/ =~ line
+      parse(line)
+    end
+
+    def Shebang.parse(line)
+      cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
+      new(cmd, args)
+    end
+
+    def initialize(cmd, args = [])
+      @cmd = cmd
+      @args = args
+    end
+
+    attr_reader :cmd
+    attr_reader :args
+
+    def to_s
+      "#! address@hidden" + (@args.empty? ? '' : " address@hidden(' ')}")
+    end
+  end
+
+  #
+  # TASK install
+  #
+
+  def exec_install
+    rm_f 'InstalledFiles'
+    exec_task_traverse 'install'
+  end
+
+  def install_dir_bin(rel)
+    install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755, strip_ext?
+  end
+
+  def strip_ext?
+    /mswin|mingw/ !~ RUBY_PLATFORM
+  end
+
+  def install_dir_lib(rel)
+    install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
+  end
+
+  def install_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    install_files rubyextentions('.'),
+                  "#{config('sodir')}/#{File.dirname(rel)}",
+                  0555
+  end
+
+  def install_dir_data(rel)
+    install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
+  end
+
+  def install_dir_conf(rel)
+    # FIXME: should not remove current config files
+    # (rename previous file to .old/.org)
+    install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
+  end
+
+  def install_dir_man(rel)
+    install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
+  end
+
+  def install_files(list, dest, mode, stripext = false)
+    mkdir_p dest, @config.install_prefix
+    list.each do |fname|
+      if stripext
+        install fname, "#{dest}/#{File.basename(fname, '.*')}",
+                mode, @config.install_prefix
+      else
+        install fname, dest, mode, @config.install_prefix
+      end
+    end
+  end
+
+  def libfiles
+    glob_reject(%w(*.y *.output), targetfiles())
+  end
+
+  def rubyextentions(dir)
+    ents = glob_select("address@hidden", targetfiles())
+    if ents.empty?
+      setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
+    end
+    ents
+  end
+
+  def targetfiles
+    mapdir(existfiles() - hookfiles())
+  end
+
+  def mapdir(ents)
+    ents.map {|ent|
+      if File.exist?(ent)
+      then ent                         # objdir
+      else "#{curr_srcdir()}/#{ent}"   # srcdir
+      end
+    }
+  end
+
+  # picked up many entries from cvs-1.11.1/src/ignore.c
+  JUNK_FILES = %w( 
+    core RCSLOG tags TAGS .make.state
+    .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
+    *~ *.old *.bak *.BAK *.orig *.rej _$* *$
+
+    *.org *.in .*
+  )
+
+  def existfiles
+    glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
+  end
+
+  def hookfiles
+    %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
+      %w( config setup install clean distclean ).map {|t| sprintf(fmt, t) }
+    }.flatten
+  end
+
+  def glob_select(pat, ents)
+    re = globs2re([pat])
+    ents.select {|ent| re =~ ent }
+  end
+
+  def glob_reject(pats, ents)
+    re = globs2re(pats)
+    ents.reject {|ent| re =~ ent }
+  end
+
+  GLOB2REGEX = {
+    '.' => '\.',
+    '$' => '\$',
+    '#' => '\#',
+    '*' => '.*'
+  }
+
+  def globs2re(pats)
+    /\A(?:#{
+      pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
+    })\z/
+  end
+
+  #
+  # TASK test
+  #
+
+  TESTDIR = 'test'
+
+  def exec_test
+    unless File.directory?('test')
+      $stderr.puts 'no test in this package' if verbose?
+      return
+    end
+    $stderr.puts 'Running tests...' if verbose?
+    begin
+      require 'test/unit'
+    rescue LoadError
+      setup_rb_error 'test/unit cannot loaded.  You need Ruby 1.8 or later to 
invoke this task.'
+    end
+    runner = Test::Unit::AutoRunner.new(true)
+    runner.to_run << TESTDIR
+    runner.run
+  end
+
+  #
+  # TASK clean
+  #
+
+  def exec_clean
+    exec_task_traverse 'clean'
+    rm_f @config.savefile
+    rm_f 'InstalledFiles'
+  end
+
+  alias clean_dir_bin noop
+  alias clean_dir_lib noop
+  alias clean_dir_data noop
+  alias clean_dir_conf noop
+  alias clean_dir_man noop
+
+  def clean_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    make 'clean' if File.file?('Makefile')
+  end
+
+  #
+  # TASK distclean
+  #
+
+  def exec_distclean
+    exec_task_traverse 'distclean'
+    rm_f @config.savefile
+    rm_f 'InstalledFiles'
+  end
+
+  alias distclean_dir_bin noop
+  alias distclean_dir_lib noop
+
+  def distclean_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    make 'distclean' if File.file?('Makefile')
+  end
+
+  alias distclean_dir_data noop
+  alias distclean_dir_conf noop
+  alias distclean_dir_man noop
+
+  #
+  # Traversing
+  #
+
+  def exec_task_traverse(task)
+    run_hook "pre-#{task}"
+    FILETYPES.each do |type|
+      if type == 'ext' and config('without-ext') == 'yes'
+        $stderr.puts 'skipping ext/* by user option' if verbose?
+        next
+      end
+      traverse task, type, "#{task}_dir_#{type}"
+    end
+    run_hook "post-#{task}"
+  end
+
+  def traverse(task, rel, mid)
+    dive_into(rel) {
+      run_hook "pre-#{task}"
+      __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
+      directories_of(curr_srcdir()).each do |d|
+        traverse task, "#{rel}/#{d}", mid
+      end
+      run_hook "post-#{task}"
+    }
+  end
+
+  def dive_into(rel)
+    return unless File.dir?("address@hidden/#{rel}")
+
+    dir = File.basename(rel)
+    Dir.mkdir dir unless File.dir?(dir)
+    prevdir = Dir.pwd
+    Dir.chdir dir
+    $stderr.puts '---> ' + rel if verbose?
+    @currdir = rel
+    yield
+    Dir.chdir prevdir
+    $stderr.puts '<--- ' + rel if verbose?
+    @currdir = File.dirname(rel)
+  end
+
+  def run_hook(id)
+    path = [ "#{curr_srcdir()}/#{id}",
+             "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
+    return unless path
+    $stderr.puts "invoking hook script #{path}" if verbose?
+    begin
+      instance_eval File.read(path), path, 1
+    rescue
+      raise if $DEBUG
+      setup_rb_error "hook #{path} failed:\n" + $!.message
+    end
+  end
+
+end   # class Installer
+
+
+class SetupError < StandardError; end
+
+def setup_rb_error(msg)
+  raise SetupError, msg
+end
+
+# $DEBUG = true
+
+if $0 == __FILE__
+    ToplevelInstaller.invoke
+    # begin
+    #   ToplevelInstaller.invoke
+    # rescue SetupError
+    #   raise if $DEBUG
+    #   $stderr.puts $!.message
+    #   $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
+    #   exit 1
+    # end
+end

Index: jitruby/ext/extconf.rb
===================================================================
RCS file: jitruby/ext/extconf.rb
diff -N jitruby/ext/extconf.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/ext/extconf.rb      12 Dec 2008 11:30:58 -0000      1.1
@@ -0,0 +1,108 @@
+require 'mkmf'
+require 'rbconfig'
+
+if Config::CONFIG['host_os'] =~ /cygwin|win32|windows/ then
+  need_windows_h = [ 'windows.h' ]
+  $defs << ' -DNEED_WINDOWS_H'
+else
+  need_windows_h = [ ]
+end
+
+if not have_library('jit', 'jit_init', need_windows_h + ["jit/jit.h"]) then
+  $stderr.puts "libjit not found"
+  exit 1
+end
+
+if not have_macro("SIZEOF_VALUE", "ruby.h") then
+  check_sizeof("VALUE", "ruby.h")
+end
+
+if not have_macro("SIZEOF_ID", "ruby.h") then
+  check_sizeof("ID", "ruby.h")
+end
+
+if have_macro("_GNU_SOURCE", "ruby.h") then
+  $defs.push("-DRUBY_DEFINES_GNU_SOURCE")
+end
+
+have_func("rb_class_boot", "ruby.h")
+have_func("rb_errinfo", "ruby.h")
+have_func('fmemopen')
+have_func("rb_ensure", "ruby.h")
+
+if have_header('ruby/node.h') then
+  # ruby.h defines HAVE_RUBY_NODE_H, even though it is not there
+  $defs.push("-DREALLY_HAVE_RUBY_NODE_H")
+elsif have_header('node.h') then
+  # okay
+else
+  $defs.push("-DNEED_MINIMAL_NODE")
+end
+
+have_header('env.h')
+
+checking_for("whether VALUE is a pointer") do
+  if not try_link(<<"SRC")
+#include <ruby.h>
+int main()
+{
+  VALUE v;
+  v /= 5;
+}
+SRC
+  then
+    $defs.push("-DVALUE_IS_PTR");
+  end
+end
+
+if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'rbx' then
+  $defs.push("-DHAVE_RUBINIUS")
+end
+
+rb_files = Dir['*.rb']
+rpp_files = Dir['*.rpp']
+generated_files = rpp_files.map { |f| f.sub(/\.rpp$/, '') }
+
+srcs = Dir['*.c']
+generated_files.each do |f|
+  if f =~ /\.c$/ then
+    srcs << f
+  end
+end
+srcs.uniq!
+$objs = srcs.map { |f| f.sub(/\.c$/, ".#{$OBJEXT}") }
+
+if Config::CONFIG['CC'] == 'gcc' then
+  # $CFLAGS << ' -Wall -g -pedantic -Wno-long-long'
+  $CFLAGS << ' -Wall -g'
+end
+
+create_makefile("jit")
+
+append_to_makefile = ''
+
+rpp_files.each do |rpp_file|
+dest_file = rpp_file.sub(/\.rpp$/, '')
+append_to_makefile << <<END
+#{dest_file}: #{rpp_file} #{rb_files.join(' ')}
+       $(RUBY) rubypp.rb #{rpp_file} #{dest_file}
+END
+end
+
+generated_headers = generated_files.select { |x| x =~ /\.h$/ || x =~ /\.inc$/ }
+append_to_makefile << <<END
+$(OBJS): #{generated_headers.join(' ')}
+clean: clean_generated_files
+clean_generated_files:
+       @$(RM) #{generated_files.join(' ')}
+
+install: $(includedir)/rubyjit.h
+
+$(includedir)/rubyjit.h: rubyjit.h
+       $(INSTALL_PROG) rubyjit.h $(includedir)
+END
+
+File.open('Makefile', 'a') do |makefile|
+  makefile.puts(append_to_makefile)
+end
+

Index: jitruby/ext/insns.inc.rpp
===================================================================
RCS file: jitruby/ext/insns.inc.rpp
diff -N jitruby/ext/insns.inc.rpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/ext/insns.inc.rpp   12 Dec 2008 11:31:02 -0000      1.1
@@ -0,0 +1,203 @@
+#ruby <<END
+
+V = :value
+L = :label_ptr
+B = :label
+N = :nint
+T = :type_t
+_ = :void
+
+def incoming_args(arg_types)
+  num_args = arg_types.length
+  return (1..num_args).map { |n| ", VALUE arg#{n}" }.join
+end
+
+def declaration(name, type)
+  case type
+  when V then return "jit_value_t #{name};"
+  when L then return "jit_label_t * #{name};"
+  when B then return "jit_label_t * #{name};"
+  when N then return "jit_nint #{name};"
+  when T then return "jit_type_t #{name};"
+  when :void then nil
+  else raise "Invalid type #{type}"
+  end
+end
+
+def write_declaration(name, type, indent)
+  d = declaration(name, type)
+  if d then
+    puts "#{' '*indent}#{d}"
+  end
+end
+
+def ruby_type(type)
+  case type
+  when V then return "rb_cValue"
+  when L then return "rb_cLabel"
+  when B then return "rb_cLabel"
+  when N then return "rb_cFixnum"
+  when T then return "rb_cType"
+  else raise "Invalid type #{type}"
+  end
+end
+
+def jit_type(type)
+  case type
+  when V then return "struct _jit_value"
+  when L then return "jit_label_t"
+  when B then return "jit_label_t"
+  when T then return "struct _jit_type"
+  else raise "Invalid type #{type}"
+  end
+end
+
+def get_value(type, arg, j_arg)
+  case type
+  when N then
+    return "#{j_arg} = NUM2INT(#{arg})"
+  else
+    return "Data_Get_Struct(#{arg}, #{jit_type(type)}, #{j_arg})"
+  end
+end
+
+def jit_insn_args(arg_types)
+  num_args = arg_types.length
+  arg_list = (1..num_args).map do |n|
+    case arg_types[n-1]
+    when B then ", *j_arg#{n}"
+    else ", j_arg#{n}"
+    end
+  end
+  return arg_list.join
+end
+
+def write_insn(name, retval_type, arg_types)
+  num_args = arg_types.length
+  an = [?a, ?e, ?i, ?o, ?u].include?(name[0])
+  puts "/* Generate a#{an} #{name} instruction (see the libjit documentation 
for more"
+  puts " * details. */"
+  puts "static VALUE function_insn_#{name}(VALUE 
self#{incoming_args(arg_types)})"
+  puts "{"
+  puts "  jit_function_t function;"
+  write_declaration('retval', retval_type, 2)
+  arg_types.each_with_index do |type, n|
+    write_declaration("j_arg#{n+1}", type, 2)
+  end
+  puts
+  arg_types.each_with_index do |type, n|
+    puts "  check_type(\"arg#{n+1}\", #{ruby_type(type)}, arg#{n+1});"
+  end
+  puts
+  puts "  Data_Get_Struct(self, struct _jit_function, function);"
+  arg_types.each_with_index do |type, n|
+    puts "  " + get_value(type, "arg#{n+1}", "j_arg#{n+1}") + ";"
+  end
+  puts
+  if retval_type == V then
+    puts "  retval = jit_insn_#{name}(function#{jit_insn_args(arg_types)});"
+    puts "  return Data_Wrap_Struct(rb_cValue, 0, 0, retval);"
+  elsif retval_type == :void then
+    puts "  jit_insn_#{name}(function#{jit_insn_args(arg_types)});"
+    puts "  return Qnil;"
+  else
+    raise "Invalid retval type #{retval_type}"
+  end
+  puts "}"
+end
+
+insns = [
+  [ 'load'                 , V, V       ] ,
+  [ 'store'                , _, V, V    ] ,
+  [ 'dup'                  , V, V       ] ,
+  [ 'add'                  , V, V, V    ] , 
+  [ 'add_ovf'              , V, V, V    ] , 
+  [ 'sub'                  , V, V, V    ] , 
+  [ 'sub_ovf'              , V, V, V    ] , 
+  [ 'mul'                  , V, V, V    ] , 
+  [ 'mul_ovf'              , V, V, V    ] , 
+  [ 'div'                  , V, V, V    ] , 
+  [ 'rem'                  , V, V, V    ] , 
+  [ 'rem_ieee'             , V, V, V    ] , 
+  [ 'neg'                  , V, V       ] , 
+  [ 'and'                  , V, V, V    ] , 
+  [ 'or'                   , V, V, V    ] , 
+  [ 'xor'                  , V, V, V    ] , 
+  [ 'not'                  , V, V       ] , 
+  [ 'shl'                  , V, V, V    ] , 
+  [ 'shr'                  , V, V, V    ] , 
+  [ 'ushr'                 , V, V, V    ] , 
+  [ 'sshr'                 , V, V, V    ] , 
+  [ 'eq'                   , V, V, V    ] , 
+  [ 'ne'                   , V, V, V    ] , 
+  [ 'lt'                   , V, V, V    ] , 
+  [ 'le'                   , V, V, V    ] , 
+  [ 'gt'                   , V, V, V    ] , 
+  [ 'ge'                   , V, V, V    ] , 
+  [ 'cmpl'                 , V, V, V    ] , 
+  [ 'cmpg'                 , V, V, V    ] , 
+  [ 'to_bool'              , V, V       ] , 
+  [ 'to_not_bool'          , V, V       ] , 
+  [ 'acos'                 , V, V       ] , 
+  [ 'asin'                 , V, V       ] , 
+  [ 'atan'                 , V, V       ] , 
+  [ 'atan2'                , V, V, V    ] ,
+  [ 'ceil'                 , V, V       ] , 
+  [ 'cos'                  , V, V       ] , 
+  [ 'cosh'                 , V, V       ] , 
+  [ 'exp'                  , V, V       ] , 
+  [ 'floor'                , V, V       ] , 
+  [ 'log'                  , V, V       ] , 
+  [ 'log10'                , V, V       ] , 
+  [ 'pow'                  , V, V, V    ] ,
+  [ 'rint'                 , V, V       ] , 
+  [ 'round'                , V, V       ] , 
+  [ 'sin'                  , V, V       ] , 
+  [ 'sinh'                 , V, V       ] , 
+  [ 'sqrt'                 , V, V       ] , 
+  [ 'tan'                  , V, V       ] , 
+  [ 'tanh'                 , V, V       ] , 
+  [ 'is_nan'               , V, V       ] , 
+  [ 'is_finite'            , V, V       ] , 
+  [ 'is_inf'               , V, V       ] , 
+  [ 'abs'                  , V, V       ] , 
+  [ 'min'                  , V, V, V    ] , 
+  [ 'max'                  , V, V, V    ] , 
+  [ 'sign'                 , V, V       ] , 
+  [ 'branch'               , _, L       ] ,
+  [ 'branch_if'            , _, V, L    ] ,
+  [ 'branch_if_not'        , _, V, L    ] ,
+  [ 'label'                , _, L       ] ,
+  [ 'address_of'           , V, V       ] ,
+  [ 'address_of_label'     , V, L       ] ,
+  [ 'store_relative'       , _, V, N, V ] ,
+  [ 'load_relative'        , V, V, N, T ] ,
+  [ 'add_relative'         , V ,V, N    ] ,
+  [ 'memcpy'               , _, V, V, V ] ,
+  [ 'memmove'              , _, V, V, V ] ,
+  [ 'memset'               , _, V, V, V ] ,
+  [ 'alloca'               , V, V       ] ,
+  [ 'load_elem'            , V, V, V, T ] ,
+  [ 'store_elem'           , _, V, V, V ] ,
+  [ 'move_blocks_to_end'   , _, B, B    ] ,
+  [ 'move_blocks_to_start' , _, B, B    ] ,
+  [ 'push'                 , _, V       ] ,
+  [ 'push_ptr'             , _, V, T    ] ,
+  [ 'pop_stack'            , _, N       ] ,
+]
+
+insns.each do |name, retval_type, *arg_types|
+  write_insn(name, retval_type, arg_types)
+  puts
+end
+
+puts "static void init_insns()"
+puts "{"
+insns.each do |name, retval_type, *arg_types|
+  num_args = arg_types.length
+  puts "  rb_define_method(rb_cFunction, \"insn_#{name}\", 
function_insn_#{name}, #{num_args});"
+end
+puts "}"
+
+END
+

Index: jitruby/ext/jit.c
===================================================================
RCS file: jitruby/ext/jit.c
diff -N jitruby/ext/jit.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/ext/jit.c   12 Dec 2008 11:31:03 -0000      1.1
@@ -0,0 +1,1552 @@
+#ifndef RUBY_DEFINES_GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifdef NEED_WINDOWS_H
+#include <windows.h>
+#endif
+
+#include <ruby.h>
+
+#include <stdio.h>
+
+#include <jit/jit.h>
+#include <jit/jit-dump.h>
+
+#include "rubyjit.h"
+#include "method_data.h"
+
+#ifdef NEED_MINIMAL_NODE
+#include "minimal_node.h"
+#endif
+
+#ifndef RARRAY_LEN
+#define RARRAY_LEN(a) RARRAY(a)->len
+#endif
+
+#ifndef RARRAY_PTR
+#define RARRAY_PTR(a) RARRAY(a)->ptr
+#endif
+
+static VALUE rb_mJIT;
+static VALUE rb_cContext;
+static VALUE rb_cFunction;
+static VALUE rb_cType;
+static VALUE rb_mABI;
+static VALUE rb_cValue;
+static VALUE rb_cLabel;
+static VALUE rb_mCall;
+static VALUE rb_cClosure;
+
+jit_type_t jit_type_VALUE;
+jit_type_t jit_type_ID;
+jit_type_t jit_type_Function_Ptr;
+
+static jit_type_t ruby_vararg_signature;
+
+typedef void (*Void_Function_Ptr)();
+
+struct Closure
+{
+  VALUE function;
+  Void_Function_Ptr function_ptr;
+};
+
+#ifdef VALUE_IS_PTR
+/* Rubinius */
+typedef jit_ptr jit_VALUE;
+#define jit_underlying_type_VALUE jit_type_void_ptr
+#define SET_CONSTANT_VALUE(c, v) (c.un.ptr_value = v)
+
+#elif SIZEOF_VALUE == 4
+/* 32-bit */
+typedef jit_uint jit_VALUE;
+#define jit_underlying_type_VALUE jit_type_uint
+#define SET_CONSTANT_VALUE(c, v) (c.un.uint_value = v)
+
+#elif SIZEOF_VALUE == 8
+/* 64-bit */
+typedef jit_ulong jit_VALUE;
+#define jit_underlying_type_VALUE jit_type_ulong
+#define SET_CONSTANT_VALUE(c, v) (c.un.ulong_value = v)
+
+#else
+#error "Unsupported size for VALUE"
+#endif
+
+#if SIZEOF_ID == 4
+/* 32-bit */
+typedef jit_uint jit_ID;
+#define jit_underlying_type_ID jit_type_uint
+#define SET_CONSTANT_ID(c, v) (c.un.uint_value = v)
+#elif SIZEOF_ID == 8
+/* 64-bit */
+typedef jit_ulong jit_ID;
+#define jit_underlying_type_ID jit_type_ulong
+#define SET_CONSTANT_ID(c, v) (c.un.ulong_value = v)
+#else
+#error "Unsupported size for ID"
+#endif
+
+typedef jit_ptr jit_Function_Ptr;
+#define jit_underlying_type_void_ptr jit_type_void_ptr
+#define SET_FUNCTION_POINTER_VALUE(c, v) (c.un.ptr_value = v)
+
+#ifdef HAVE_RB_ERRINFO
+#define ruby_errinfo rb_errinfo()
+#endif
+
+/* ---------------------------------------------------------------------------
+ * Utility functions
+ * ---------------------------------------------------------------------------
+ */
+
+static VALUE lookup_const(VALUE module, VALUE symbol)
+{
+  if(SYMBOL_P(symbol))
+  {
+    return rb_const_get(module, SYM2ID(symbol));
+  }
+  else
+  {
+    return symbol;
+  }
+}
+
+static void check_type(char const * param_name, VALUE expected_klass, VALUE 
val)
+{
+  if(!rb_obj_is_kind_of(val, expected_klass))
+  {
+    rb_raise(
+        rb_eTypeError,
+        "Wrong type for %s; expected %s but got %s",
+        param_name,
+        rb_class2name(expected_klass),
+        rb_class2name(CLASS_OF(val)));
+  }
+}
+
+void raise_memory_error_if_zero(void * v)
+{
+  if(!v)
+  {
+    rb_raise(rb_eNoMemError, "Out of memory");
+  }
+}
+
+/* ---------------------------------------------------------------------------
+ * Context
+ * ---------------------------------------------------------------------------
+ */
+
+static void context_mark(jit_context_t context)
+{
+  VALUE functions = (VALUE)jit_context_get_meta(context, RJT_FUNCTIONS);
+  rb_gc_mark(functions);
+}
+
+/* 
+ * call-seq:
+ *   context = Context.new
+ *
+ * Create a new context.
+ */
+static VALUE context_s_new(VALUE klass)
+{
+  jit_context_t context = jit_context_create();
+  jit_context_set_meta(context, RJT_FUNCTIONS, (void*)rb_ary_new(), 0);
+  return Data_Wrap_Struct(rb_cContext, context_mark, jit_context_destroy, 
context);
+}
+
+/* 
+ * call-seq:
+ *   context.build { ... }
+ *
+ * Acquire a lock on the context so it can be used to build a function.
+ */
+static VALUE context_build(VALUE self)
+{
+  jit_context_t context;
+  Data_Get_Struct(self, struct _jit_context, context);
+  jit_context_build_start(context);
+#ifdef HAVE_RB_ENSURE
+  return rb_ensure(
+      rb_yield,
+      self,
+      RUBY_METHOD_FUNC(jit_context_build_end),
+      (VALUE)context);
+#else
+  /* Rubinius does not yet have rb_ensure */
+  rb_yield(self);
+  jit_context_build_end(context);
+#endif
+}
+
+/*
+ * call-seq:
+ *   Context.build { |context| ... }
+ *
+ * Create a context and acquire a lock on it, then yield the context to
+ * the block.
+ */
+static VALUE context_s_build(VALUE klass)
+{
+  return context_build(context_s_new(klass));
+}
+
+/* ---------------------------------------------------------------------------
+ * Closure
+ * ---------------------------------------------------------------------------
+ */
+
+static void mark_closure(struct Closure * closure)
+{
+  rb_gc_mark(closure->function);
+}
+
+VALUE closure_to_int(VALUE self)
+{
+  struct Closure * closure;
+  Data_Get_Struct(self, struct Closure, closure);
+  VALUE v = ULONG2NUM((unsigned long)closure->function_ptr);
+  return v;
+}
+
+VALUE closure_to_s(VALUE self)
+{
+  struct Closure * closure;
+  VALUE args[4];
+  Data_Get_Struct(self, struct Closure, closure);
+  args[0] = rb_str_new2("#<JIT::Closure:0x%x function=%s function_ptr=0x%x>");
+  args[1] = ULONG2NUM((unsigned long)self);
+  args[2] = rb_any_to_s(closure->function);
+  args[3] = ULONG2NUM((unsigned long)closure->function_ptr);
+  return rb_f_sprintf(sizeof(args)/sizeof(args[0]), args);
+}
+
+VALUE closure_inspect(VALUE self)
+{
+  return closure_to_s(self);
+}
+
+/* ---------------------------------------------------------------------------
+ * Function
+ * ---------------------------------------------------------------------------
+ */
+
+static void mark_function(jit_function_t function)
+{
+  rb_gc_mark((VALUE)jit_function_get_meta(function, RJT_VALUE_OBJECTS));
+  rb_gc_mark((VALUE)jit_function_get_meta(function, RJT_CONTEXT));
+}
+
+static VALUE create_function(int argc, VALUE * argv, VALUE klass)
+{
+  VALUE context_v;
+  VALUE signature_v;
+  VALUE parent_function_v;
+
+  jit_function_t function;
+  jit_function_t parent_function;
+  jit_context_t context;
+  jit_type_t signature;
+  jit_type_t untagged_signature;
+
+  VALUE function_v;
+  VALUE functions;
+
+  int signature_tag;
+
+  rb_scan_args(argc, argv, "21", &context_v, &signature_v, &parent_function_v);
+
+  Data_Get_Struct(context_v, struct _jit_context, context);
+  Data_Get_Struct(signature_v, struct _jit_type, signature);
+
+  signature_tag = jit_type_get_kind(signature);
+
+  /* If this signature was tagged, get the untagged type */
+  if((untagged_signature = jit_type_get_tagged_type(signature)))
+  {
+    signature = untagged_signature;
+  }
+
+  if(RTEST(parent_function_v))
+  {
+    /* If this function has a parent, then it is a nested function */
+    Data_Get_Struct(parent_function_v, struct _jit_function, parent_function);
+    function = jit_function_create_nested(context, signature, parent_function);
+  }
+  else
+  {
+    /* Otherwise, it's a standalone function */
+    function = jit_function_create(context, signature);
+  }
+
+  /* Make sure the function is around as long as the context is */
+  if(!jit_function_set_meta(function, RJT_VALUE_OBJECTS, (void *)rb_ary_new(), 
0, 0))
+  {
+    rb_raise(rb_eNoMemError, "Out of memory");
+  }
+
+  /* Remember the signature's tag for later */
+  if(!jit_function_set_meta(function, RJT_TAG_FOR_SIGNATURE, (void 
*)signature_tag, 0, 0))
+  {
+    rb_raise(rb_eNoMemError, "Out of memory");
+  }
+
+  /* And remember the function's context for later */
+  if(!jit_function_set_meta(function, RJT_CONTEXT, (void *)context_v, 0, 0))
+  {
+    rb_raise(rb_eNoMemError, "Out of memory");
+  }
+
+  function_v = Data_Wrap_Struct(rb_cFunction, mark_function, 0, function);
+
+  /* Add this function to the context's list of functions */
+  functions = (VALUE)jit_context_get_meta(context, RJT_FUNCTIONS);
+  rb_ary_push(functions, function_v);
+
+  return function_v;
+}
+
+/*
+ * call-seq:
+ *   function.compile()
+ *
+ * Begin compiling a function.
+ */
+static VALUE function_compile(VALUE self)
+{
+  jit_function_t function;
+  Data_Get_Struct(self, struct _jit_function, function);
+  if(!jit_function_compile(function))
+  {
+    rb_raise(rb_eRuntimeError, "Unable to compile function");
+  }
+  return self;
+}
+
+/*
+ * call-seq:
+ *   function = Function.new(context, signature, [parent])
+ *
+ * Create a new function.
+ */
+static VALUE function_s_new(int argc, VALUE * argv, VALUE klass)
+{
+  if(rb_block_given_p())
+  {
+    rb_raise(rb_eArgError, "Function.new does not take a block");
+  }
+
+  return create_function(argc, argv, klass);
+}
+
+static VALUE function_abandon_if_exception(VALUE function_v)
+{
+  if(ruby_errinfo)
+  {
+    jit_function_t function;
+    Data_Get_Struct(function_v, struct _jit_function, function);
+    jit_function_abandon(function);
+  }
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *   function = Function.new(context, signature, [parent]) { |function| ... }
+ *
+ * Create a new function, begin compiling it, and pass the function to
+ * the block.
+ */
+static VALUE function_s_compile(int argc, VALUE * argv, VALUE klass)
+{
+  VALUE function = create_function(argc, argv, klass);
+  rb_yield(function);
+  function_compile(function);
+#ifdef HAVE_RB_ENSURE
+  rb_ensure(
+      function_compile,
+      function,
+      function_abandon_if_exception,
+      function);
+#else
+  /* Rubinius does not yet have rb_ensure */
+  function_compile(function);
+  function_abandon_if_exception(function);
+#endif
+  return function;
+}
+
+/*
+ * Get the value that corresponds to a specified function parameter.
+ *
+ * call-seq:
+ *   value = function.get_param(index)
+ */
+static VALUE function_get_param(VALUE self, VALUE idx)
+{
+  jit_function_t function;
+  jit_value_t value;
+  Data_Get_Struct(self, struct _jit_function, function);
+  value = jit_value_get_param(function, NUM2INT(idx));
+  raise_memory_error_if_zero(value);
+  return Data_Wrap_Struct(rb_cValue, 0, 0, value);
+}
+
+#include "insns.inc"
+
+static VALUE function_value_klass(VALUE self, VALUE type_v, VALUE klass)
+{
+  jit_function_t function;
+  jit_type_t type;
+  jit_value_t value;
+
+  Data_Get_Struct(self, struct _jit_function, function);
+
+  type_v = lookup_const(rb_cType, type_v);
+  check_type("type", rb_cType, type_v);
+  Data_Get_Struct(type_v, struct _jit_type, type);
+
+  /* TODO: When we wrap a value, we should inject a reference to the
+   * function in the object, so the function stays around as long as the
+   * value does */
+  value = jit_value_create(function, type);
+  return Data_Wrap_Struct(klass, 0, 0, value);
+}
+
+static VALUE coerce_to_jit(VALUE function, VALUE type_v, VALUE value_v);
+
+/*
+ * call-seq:
+ *   value = function.value(type)
+ *   value = function.value(type, initial_value)
+ *
+ * Create a value (placeholder/variable) with the given type.
+ */
+static VALUE function_value(int argc, VALUE * argv, VALUE self)
+{
+  VALUE type_v = Qnil;
+  VALUE initial_value_v = Qnil;
+
+  VALUE new_value = Qnil;
+
+  rb_scan_args(argc, argv, "11", &type_v, &initial_value_v);
+
+  new_value = function_value_klass(self, type_v, rb_cValue);
+
+  if(argc > 1)
+  {
+    function_insn_store(
+        self,
+        new_value,
+        coerce_to_jit(self, type_v, initial_value_v));
+  }
+
+  return new_value;
+}
+
+static jit_value_t create_const(jit_function_t function, jit_type_t type, 
VALUE constant)
+{
+  jit_constant_t c;
+  int kind = jit_type_get_kind(type);
+
+  switch(kind)
+  {
+    case JIT_TYPE_INT:
+    {
+      c.type = type;
+      c.un.int_value = NUM2INT(constant);
+      break;
+    }
+
+    case JIT_TYPE_UINT:
+    {
+      c.type = type;
+      c.un.int_value = NUM2UINT(constant);
+      break;
+    }
+
+    case JIT_TYPE_FLOAT32:
+    {
+      c.type = type;
+      c.un.float32_value = NUM2DBL(constant);
+      break;
+    }
+
+    case JIT_TYPE_FLOAT64:
+    {
+      c.type = type;
+      c.un.float64_value = NUM2DBL(constant);
+      break;
+    }
+
+    case JIT_TYPE_PTR:
+    {
+      c.type = type;
+      c.un.ptr_value = (void *)NUM2ULONG(constant);
+      break;
+    }
+
+    case JIT_TYPE_FIRST_TAGGED + RJT_OBJECT:
+    {
+      VALUE value_objects = (VALUE)jit_function_get_meta(function, 
RJT_VALUE_OBJECTS);
+
+      c.type = type;
+      SET_CONSTANT_VALUE(c, constant);
+
+      /* Make sure the object gets marked as long as the function is
+       * around */
+      rb_ary_push(value_objects, constant);
+      break;
+    }
+
+    case JIT_TYPE_FIRST_TAGGED + RJT_ID:
+    {
+      c.type = type;
+      SET_CONSTANT_ID(c, SYM2ID(constant));
+      break;
+    }
+
+    case JIT_TYPE_FIRST_TAGGED + RJT_FUNCTION_PTR:
+    {
+      c.type = type;
+      SET_FUNCTION_POINTER_VALUE(
+          c,
+          (Void_Function_Ptr)NUM2ULONG(rb_to_int(constant)));
+      break;
+    }
+
+    default:
+      rb_raise(rb_eTypeError, "Unsupported type");
+  }
+
+  return jit_value_create_constant(function, &c);
+}
+
+/*
+ * call-seq:
+ *   value = function.const(type, constant_value)
+ *
+ * Create a constant value with the given type.
+ */
+static VALUE function_const(VALUE self, VALUE type_v, VALUE constant)
+{
+  jit_function_t function;
+  jit_type_t type;
+  jit_value_t value;
+
+  Data_Get_Struct(self, struct _jit_function, function);
+
+  type_v = lookup_const(rb_cType, type_v);
+  check_type("type", rb_cType, type_v);
+  Data_Get_Struct(type_v, struct _jit_type, type);
+
+  value = create_const(function, type, constant);
+  return Data_Wrap_Struct(rb_cValue, 0, 0, value);
+}
+
+static VALUE coerce_to_jit(VALUE function, VALUE type_v, VALUE value_v)
+{
+  if(rb_obj_is_kind_of(value_v, rb_cValue))
+  {
+    return value_v;
+  }
+  else
+  {
+    return function_const(function, type_v, value_v);
+  }
+}
+
+static void convert_call_args(jit_function_t function, jit_value_t * args, 
VALUE args_v, jit_type_t signature)
+{
+  int j;
+
+  for(j = 0; j < RARRAY_LEN(args_v); ++j)
+  {
+    VALUE value = RARRAY_PTR(args_v)[j];
+    jit_value_t arg;
+
+    jit_type_t type = jit_type_get_param(signature, j);
+    if(!type)
+    {
+      rb_raise(rb_eArgError, "Type missing for param %d", j);
+    }
+
+    if(rb_obj_is_kind_of(value, rb_cValue))
+    {
+      Data_Get_Struct(value, struct _jit_value, arg);
+      if(!arg)
+      {
+        rb_raise(rb_eArgError, "Argument %d is invalid", j);
+      }
+      args[j] = arg;
+    }
+    else
+    {
+      args[j] = create_const(function, type, value);
+    }
+  }
+}
+
+/* 
+ * call-seq:
+ *   value = function.call(name, called_function, flags, [arg1 [, ... ]])
+ *
+ * Generate an instruction to call the specified function.
+ */
+static VALUE function_insn_call(int argc, VALUE * argv, VALUE self)
+{
+  jit_function_t function;
+
+  VALUE name_v;
+  VALUE called_function_v;
+  VALUE args_v;
+  VALUE flags_v = Qnil;
+
+  char const * name;
+  jit_function_t called_function;
+  jit_type_t signature;
+  jit_value_t * args;
+  jit_value_t retval;
+  int flags;
+  size_t num_args;
+
+  rb_scan_args(argc, argv, "3*", &name_v, &called_function_v, &flags_v, 
&args_v);
+
+  Data_Get_Struct(self, struct _jit_function, function);
+
+  name = STR2CSTR(name_v);
+
+  check_type("called function", rb_cFunction, called_function_v);
+  Data_Get_Struct(called_function_v, struct _jit_function, called_function);
+
+  num_args = RARRAY_LEN(args_v);
+  args = ALLOCA_N(jit_value_t, num_args);
+
+  signature = jit_function_get_signature(function);
+  convert_call_args(function, args, args_v, signature);
+
+  flags = NUM2INT(flags_v);
+
+  retval = jit_insn_call(
+      function, name, called_function, 0, args, num_args, flags);
+  return Data_Wrap_Struct(rb_cValue, 0, 0, retval);
+}
+
+/*
+ * call-seq:
+ *   value = function.call(name, flags, [arg1 [, ... ]])
+ *
+ * Generate an instruction to call a native function.
+ */
+static VALUE function_insn_call_native(int argc, VALUE * argv, VALUE self)
+{
+  jit_function_t function;
+
+  VALUE name_v;
+  VALUE args_v;
+  VALUE function_ptr_v;
+  VALUE signature_v;
+  VALUE flags_v;
+
+  char const * name;
+  jit_value_t * args;
+  jit_value_t retval;
+  void * function_ptr;
+  jit_type_t signature;
+  int flags;
+  size_t num_args;
+
+  rb_scan_args(argc, argv, "4*", &name_v, &function_ptr_v, &signature_v, 
&flags_v, &args_v);
+
+  Data_Get_Struct(self, struct _jit_function, function);
+  
+  if(SYMBOL_P(name_v))
+  {
+    name = rb_id2name(SYM2ID(name_v));
+  }
+  else
+  {
+    name = StringValuePtr(name_v);
+  }
+
+  function_ptr = (void *)NUM2ULONG(function_ptr_v);
+
+  Data_Get_Struct(signature_v, struct _jit_type, signature);
+
+  num_args = RARRAY_LEN(args_v);
+  args = ALLOCA_N(jit_value_t, num_args);
+
+  if(num_args != jit_type_num_params(signature))
+  {
+    rb_raise(
+        rb_eArgError,
+        "Wrong number of arguments passed for %s (expecting %d but got %d)", 
+        name,
+        jit_type_num_params(signature),
+        num_args);
+  }
+
+  convert_call_args(function, args, args_v, signature);
+
+  flags = NUM2INT(flags_v);
+
+  retval = jit_insn_call_native(
+      function, name, function_ptr, signature, args, num_args, flags);
+  return Data_Wrap_Struct(rb_cValue, 0, 0, retval);
+}
+
+/*
+ * call-seq:
+ *   function.insn_return()
+ *   function.insn_return(value)
+ *
+ * Emit an instruction to return from the function.  If value is
+ * specified, return the given value, otherwise return void.
+ */
+static VALUE function_insn_return(int argc, VALUE * argv, VALUE self)
+{
+  jit_function_t function;
+  jit_value_t value = 0;
+  VALUE value_v = Qnil;
+
+  rb_scan_args(argc, argv, "01", &value_v);
+
+  if(value_v != Qnil)
+  {
+    Data_Get_Struct(value_v, struct _jit_value, value);
+  }
+
+  Data_Get_Struct(self, struct _jit_function, function);
+  jit_insn_return(function, value);
+
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *   function.apply(arg1 [, arg2 [, ... ]])
+ *
+ * Call a compiled function.  Each argument passed in will be converted
+ * to the type specified by the function's signature.
+ *
+ * If the function's signature is Type::RUBY_VARARG_SIGNATURE, then the
+ * arguments will be passed in with the first parameter the count of the
+ * number of arguments, the second parameter a pointer to an array
+ * containing the second through the last argument, and the third
+ * parameter the explicit self (that is, the first argument passed to
+ * apply).
+ */
+static VALUE function_apply(int argc, VALUE * argv, VALUE self)
+{
+  jit_function_t function;
+  jit_type_t signature;
+  int j, n;
+  void * * args;
+  char * arg_data;
+  int signature_tag;
+
+  Data_Get_Struct(self, struct _jit_function, function);
+  signature = jit_function_get_signature(function);
+  n = jit_type_num_params(signature);
+
+  /* void pointers to each of the arguments */
+  args = ALLOCA_N(void *, n);
+
+  /* the actual data */
+  /* TODO: we need to allocate the proper size (but 8 bytes per arg
+   * should be sufficient for now) */
+  arg_data = (char *)ALLOCA_N(char, 8 * n);
+
+  signature_tag = (int)jit_function_get_meta(function, RJT_TAG_FOR_SIGNATURE);
+  if(signature_tag == JIT_TYPE_FIRST_TAGGED + RJT_RUBY_VARARG_SIGNATURE)
+  {
+    jit_VALUE result;
+    int f_argc = argc - 1;
+    VALUE f_self = *(VALUE *)argv;
+    VALUE * f_argv = ((VALUE *)argv) + 1;
+    void * f_args[3];
+    f_args[0] = &f_argc;
+    f_args[1] = &f_argv;
+    f_args[2] = &f_self;
+    jit_function_apply(function, f_args, &result);
+    return result;
+  }
+
+  if(argc != n)
+  {
+    rb_raise(
+        rb_eArgError,
+        "Wrong number of arguments (expected %d but got %d)",
+        n,
+        argc);
+  }
+
+  for(j = 0; j < n; ++j)
+  {
+    jit_type_t arg_type = jit_type_get_param(signature, j);
+    int kind = jit_type_get_kind(arg_type);
+    switch(kind)
+    {
+      case JIT_TYPE_INT:
+      {
+        *(int *)arg_data = NUM2INT(argv[j]);
+        args[j] = (int *)arg_data;
+        arg_data += sizeof(int);
+        break;
+      }
+
+      case JIT_TYPE_UINT:
+      {
+        *(int *)arg_data = NUM2UINT(argv[j]);
+        args[j] = (int *)arg_data;
+        arg_data += sizeof(int);
+        break;
+      }
+
+      case JIT_TYPE_FIRST_TAGGED + RJT_OBJECT:
+      {
+        *(VALUE *)arg_data = argv[j];
+        args[j] = (VALUE *)arg_data;
+        arg_data += sizeof(VALUE);
+        break;
+      }
+
+      case JIT_TYPE_FIRST_TAGGED + RJT_ID:
+      {
+        *(ID *)arg_data = SYM2ID(argv[j]);
+        args[j] = (ID *)arg_data;
+        arg_data += sizeof(ID);
+        break;
+      }
+
+      case JIT_TYPE_FIRST_TAGGED + RJT_FUNCTION_PTR:
+      {
+        *(Void_Function_Ptr *)arg_data =
+          (Void_Function_Ptr)NUM2ULONG(rb_to_int(argv[j]));
+        args[j] = (Void_Function_Ptr *)(arg_data);
+        arg_data += sizeof(Void_Function_Ptr);
+        break;
+      }
+
+      default:
+        rb_raise(rb_eTypeError, "Unsupported type %d", kind);
+    }
+  }
+
+  {
+    jit_type_t return_type = jit_type_get_return(signature);
+    int return_kind = jit_type_get_kind(return_type);
+    switch(return_kind)
+    {
+      case JIT_TYPE_INT:
+      {
+        jit_int result;
+        jit_function_apply(function, args, &result);
+        return INT2NUM(result);
+      }
+
+      case JIT_TYPE_FLOAT32:
+      {
+        jit_float32 result;
+        jit_function_apply(function, args, &result);
+        return rb_float_new(result);
+      }
+
+      case JIT_TYPE_FLOAT64:
+      {
+        jit_float64 result;
+        jit_function_apply(function, args, &result);
+        return rb_float_new(result);
+      }
+
+      case JIT_TYPE_FIRST_TAGGED + RJT_OBJECT:
+      {
+        jit_VALUE result;
+        jit_function_apply(function, args, &result);
+        return result;
+      }
+
+      case JIT_TYPE_FIRST_TAGGED + RJT_ID:
+      {
+        jit_ID result;
+        jit_function_apply(function, args, &result);
+        return ID2SYM(result);
+      }
+
+      default:
+        rb_raise(rb_eTypeError, "Unsupported return type %d", return_kind);
+    }
+  }
+}
+
+/*
+ * call-seq:
+ *   level = function.optimization_level()
+ *
+ * Get the optimization level for a function.
+ */
+static VALUE function_optimization_level(VALUE self)
+{
+  jit_function_t function;
+  Data_Get_Struct(self, struct _jit_function, function);
+  return INT2NUM(jit_function_get_optimization_level(function));
+}
+
+/*
+ * call-seq:
+ *   function.optimization_level = level
+ *
+ * Set the optimization level for a function.
+ */
+static VALUE function_set_optimization_level(VALUE self, VALUE level)
+{
+  jit_function_t function;
+  Data_Get_Struct(self, struct _jit_function, function);
+  jit_function_set_optimization_level(function, NUM2INT(level));
+  return level;
+}
+
+/*
+ * call-seq:
+ *   level = function.max_optimization_level()
+ *
+ * Get the maximum optimization level (which should be the same for any
+ * function).
+ */
+static VALUE function_max_optimization_level(VALUE klass)
+{
+  return INT2NUM(jit_function_get_max_optimization_level());
+}
+
+/*
+ * call-seq:
+ *   str = function.dump()
+ *
+ * Dump the instructions in a function to a string.
+ */
+static VALUE function_dump(VALUE self)
+{
+#ifdef HAVE_FMEMOPEN
+  jit_function_t function;
+  char buf[16*1024]; /* TODO: big enough? */
+  FILE * fp = fmemopen(buf, sizeof(buf), "w");
+  Data_Get_Struct(self, struct _jit_function, function);
+  jit_dump_function(fp, function, 0);
+  fclose(fp);
+  return rb_str_new2(buf);
+#else
+  rb_raise(rb_eNotImpError, "Not implemented: missing fmemopen");
+#endif
+}
+
+/*
+ * call-seq:
+ *   ptr = function.to_closure()
+ *
+ * Return a pointer to a closure for a function.  This pointer can be
+ * passed into other functions as a function pointer.
+ */
+static VALUE function_to_closure(VALUE self)
+{
+  jit_function_t function;
+  struct Closure * closure;
+  VALUE closure_v = Data_Make_Struct(
+      rb_cClosure, struct Closure, mark_closure, free, closure);
+  Data_Get_Struct(self, struct _jit_function, function);
+  closure->function = self;
+  closure->function_ptr =
+    (Void_Function_Ptr)jit_function_to_closure(function);
+  return closure_v;
+}
+
+/*
+ * call-seq:
+ *   context = function.context()
+ *
+ * Get a function's context.
+ */
+static VALUE function_get_context(VALUE self)
+{
+  jit_function_t function;
+  Data_Get_Struct(self, struct _jit_function, function);
+  return (VALUE)jit_function_get_meta(function, RJT_CONTEXT);
+}
+
+/*
+ * call-seq:
+ *   is_compiled = function.compiled?
+ *
+ * Determine whether a function is compiled.
+ */
+static VALUE function_is_compiled(VALUE self)
+{
+  jit_function_t function;
+  Data_Get_Struct(self, struct _jit_function, function);
+  return jit_function_is_compiled(function) ? Qtrue : Qfalse;
+}
+
+/* ---------------------------------------------------------------------------
+ * Type
+ * ---------------------------------------------------------------------------
+ */
+
+/* This function does not increment the reference count.  It is assumed
+ * that the caller will increment the reference count and that the newly
+ * wrapped object will take ownership. */
+static VALUE wrap_type_with_klass(jit_type_t type, VALUE klass)
+{
+  return Data_Wrap_Struct(klass, 0, jit_type_free, type);
+}
+
+static VALUE wrap_type(jit_type_t type)
+{
+  return wrap_type_with_klass(type, rb_cType);
+}
+
+/*
+ * call-seq:
+ *   type = Type.create_signature(abi, return_type, array_of_param_types)
+ *
+ * Create a new signature.
+ */
+static VALUE type_s_create_signature(
+    VALUE klass, VALUE abi_v, VALUE return_type_v, VALUE params_v)
+{
+  jit_abi_t abi;
+  jit_type_t return_type;
+  jit_type_t * params;
+  jit_type_t signature;
+  int j;
+  int len;
+
+  return_type_v = lookup_const(rb_cType, return_type_v);
+  check_type("return type", rb_cType, return_type_v);
+  Data_Get_Struct(return_type_v, struct _jit_type, return_type);
+
+  Check_Type(params_v, T_ARRAY);
+  len = RARRAY_LEN(params_v);
+  params = ALLOCA_N(jit_type_t, len);
+  for(j = 0; j < len; ++j)
+  {
+    VALUE param = RARRAY_PTR(params_v)[j];
+    param = lookup_const(rb_cType, param);
+    check_type("param", rb_cType, param);
+    Data_Get_Struct(param, struct _jit_type, params[j]);
+  }
+
+  abi_v = lookup_const(rb_mABI, abi_v);
+  abi = NUM2INT(abi_v);
+
+  signature = jit_type_create_signature(abi, return_type, params, len, 1);
+  return wrap_type(signature);
+}
+
+/*
+ * call-seq:
+ *   type = Type.create_struct(array_of_field_types)
+ *
+ * Create a new struct type.
+ */
+static VALUE type_s_create_struct(
+    VALUE klass, VALUE fields_v)
+{
+  jit_type_t * fields;
+  jit_type_t struct_type;
+  int len;
+  int j;
+
+  Check_Type(fields_v, T_ARRAY);
+  len = RARRAY_LEN(fields_v);
+  fields = ALLOCA_N(jit_type_t, len);
+  for(j = 0; j < len; ++j)
+  {
+    VALUE field = RARRAY_PTR(fields_v)[j];
+    check_type("field", rb_cType, field);
+    Data_Get_Struct(field, struct _jit_type, fields[j]);
+  }
+
+  struct_type = jit_type_create_struct(fields, RARRAY_LEN(fields_v), 1);
+  return wrap_type_with_klass(struct_type, klass);
+}
+
+/*
+ * call-seq:
+ *   type = Type.create_pointer(pointed_to_type)
+ *
+ * Create a new pointer type, pointing to the given type.
+ */
+static VALUE type_s_create_pointer(
+    VALUE klass, VALUE type_v)
+{
+  jit_type_t type;
+  jit_type_t pointer_type;
+  Data_Get_Struct(type_v, struct _jit_type, type);
+  pointer_type = jit_type_create_pointer(type, 1);
+  return wrap_type_with_klass(pointer_type, klass);
+}
+
+/*
+ * call-seq:
+ *   offset = struct_type.get_offset(index)
+ *
+ * Get the offset of the nth field in a struct.
+ */
+static VALUE type_get_offset(VALUE self, VALUE field_index_v)
+{
+  int field_index = NUM2INT(field_index_v);
+  jit_type_t type;
+  Data_Get_Struct(self, struct _jit_type, type);
+  return INT2NUM(jit_type_get_offset(type, field_index));
+}
+
+/*
+ * call-seq:
+ *   offset = struct_type.set_offset(index, offset)
+ *
+ * Set the offset of the nth field in a struct.
+ */
+static VALUE type_set_offset(VALUE self, VALUE field_index_v, VALUE offset_v)
+{
+  int field_index = NUM2INT(field_index_v);
+  int offset = NUM2UINT(offset_v);
+  jit_type_t type;
+  Data_Get_Struct(self, struct _jit_type, type);
+  jit_type_set_offset(type, field_index, offset);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *   offset = struct_type.size
+ *
+ * Get the size of a struct or union type.
+ */
+static VALUE type_size(VALUE self)
+{
+  jit_type_t type;
+  Data_Get_Struct(self, struct _jit_type, type);
+  return INT2NUM(jit_type_get_size(type));
+}
+
+/* ---------------------------------------------------------------------------
+ * Value
+ * ---------------------------------------------------------------------------
+ */
+
+static VALUE value_s_new_value(VALUE klass, VALUE function, VALUE type)
+{
+  return function_value_klass(function, type, klass);
+}
+
+/*
+ * call-seq:
+ *   str = value.to_s
+ *
+ * Return a string representation of the value.
+ */
+static VALUE value_to_s(VALUE self)
+{
+#ifdef HAVE_FMEMOPEN
+  char buf[1024];
+  FILE * fp = fmemopen(buf, sizeof(buf), "w");
+  jit_value_t value;
+  jit_function_t function;
+  Data_Get_Struct(self, struct _jit_value, value);
+  function = jit_value_get_function(value);
+  jit_dump_value(fp, function, value, 0);
+  fclose(fp);
+  return rb_str_new2(buf);
+#else
+  rb_raise(rb_eNotImpError, "Not implemented: missing fmemopen");
+#endif
+}
+
+/*
+ * call-seq:
+ *   str = value.inspect
+ *
+ * Return a string representation of a value with additional
+ * information about the value.
+ */
+static VALUE value_inspect(VALUE self)
+{
+  jit_value_t value;
+  jit_type_t type;
+  char const * cname = rb_obj_classname(self);
+  VALUE args[6];
+  Data_Get_Struct(self, struct _jit_value, value);
+  type = jit_value_get_type(value);
+  args[0] = rb_str_new2("#<%s:0x%x %s ptr=0x%x type=0x%x>");
+  args[1] = rb_str_new2(cname);
+  args[2] = ULONG2NUM((unsigned long)self);
+  args[3] = value_to_s(self);
+  args[4] = ULONG2NUM((unsigned long)value);
+  args[5] = ULONG2NUM((unsigned long)type);
+  return rb_f_sprintf(sizeof(args)/sizeof(args[0]), args);
+}
+
+/*
+ * call-seq:
+ *   is_valid = value.valid?
+ *
+ * Determine if a value is valid (non-zero).
+ */
+static VALUE value_is_valid(VALUE self)
+{
+  jit_value_t value;
+  Data_Get_Struct(self, struct _jit_value, value);
+  return (value != 0) ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   is_temporary = value.temporary?
+ *
+ * Determine if a value represents a temporary.
+ */
+static VALUE value_is_temporary(VALUE self)
+{
+  jit_value_t value;
+  Data_Get_Struct(self, struct _jit_value, value);
+  return jit_value_is_temporary(value) ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   is_local = value.local?
+ *
+ * Determine if a value represents a local.
+ */
+static VALUE value_is_local(VALUE self)
+{
+  jit_value_t value;
+  Data_Get_Struct(self, struct _jit_value, value);
+  return jit_value_is_local(value) ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   is_local = value.constant?
+ *
+ * Determine if a value represents a constant.
+ */
+static VALUE value_is_constant(VALUE self)
+{
+  jit_value_t value;
+  Data_Get_Struct(self, struct _jit_value, value);
+  return jit_value_is_constant(value) ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   is_volatile = value.volatile?
+ *
+ * Determine if a value is volatile (that is, the contents must be
+ * reloaded from memory each time it is used).
+ */
+static VALUE value_is_volatile(VALUE self)
+{
+  jit_value_t value;
+  Data_Get_Struct(self, struct _jit_value, value);
+  return jit_value_is_volatile(value) ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   value.volatile = is_volatile
+ *
+ * Make a value volatile (that is, ensure that its contents are reloaded
+ * from memory each time it is used).
+ */
+static VALUE value_set_volatile(VALUE self)
+{
+  jit_value_t value;
+  Data_Get_Struct(self, struct _jit_value, value);
+  jit_value_set_volatile(value);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *   is_addressable = value.addressable?
+ *
+ * Determine if a value is addressable.
+ */
+static VALUE value_is_addressable(VALUE self)
+{
+  jit_value_t value;
+  Data_Get_Struct(self, struct _jit_value, value);
+  return jit_value_is_addressable(value) ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   value.addressable = is_addressable
+ *
+ * Make a value addressable.
+ */
+static VALUE value_set_addressable(VALUE self)
+{
+  jit_value_t value;
+  Data_Get_Struct(self, struct _jit_value, value);
+  jit_value_set_addressable(value);
+  return Qnil;
+}
+
+/*
+ * call-seq:
+ *   function = value.function()
+ *
+ * Get a value's function.
+ */
+static VALUE value_function(VALUE self)
+{
+  jit_value_t value;
+  jit_function_t function;
+  Data_Get_Struct(self, struct _jit_value, value);
+  function = jit_value_get_function(value);
+  return Data_Wrap_Struct(rb_cFunction, mark_function, 0, function);
+}
+
+/*
+ * call-seq:
+ *   function = value.type()
+ *
+ * Get a value's type.
+ */
+static VALUE value_type(VALUE self)
+{
+  jit_value_t value;
+  jit_type_t type;
+  Data_Get_Struct(self, struct _jit_value, value);
+  type = jit_value_get_type(value);
+  type = jit_type_copy(type);
+  return wrap_type(type);
+}
+
+/*
+ * call-seq:
+ *   value1, value2 = value1.coerce(value2)
+ *
+ * If the given value is a JIT::Value, return an +[ self, value ]+,
+ * otherwise coerce the value to the same type as self and return
+ * +[ self, coerced_value ]+.
+ */
+static VALUE value_coerce(VALUE self, VALUE value)
+{
+  return rb_assoc_new(
+      self,
+      coerce_to_jit(
+          value_function(self),
+          value_type(self),
+          value));
+}
+
+/* ---------------------------------------------------------------------------
+ * Label
+ * ---------------------------------------------------------------------------
+ */
+
+/*
+ * call-seq:
+ *   label = Label.new
+ *
+ * Create a new label.
+ */
+static VALUE label_s_new(VALUE klass)
+{
+  jit_label_t * label;
+  VALUE labelval = Data_Make_Struct(rb_cLabel, jit_label_t, 0, xfree, label);
+  *label = jit_label_undefined;
+  return labelval;
+}
+
+/* ---------------------------------------------------------------------------
+ * Module
+ * ---------------------------------------------------------------------------
+ */
+
+/*
+ * call-seq:
+ *   module.define_jit_method(name, function)
+ *
+ * Use a Function to define an instance method on a module.  The
+ * function should have one of two signatures:
+ *
+ * * The first parameter to the function should be an OBJECT that
+ *   represents the self parameter and the rest of the parameters, or
+ *
+ * * The function's signature should be Type::RUBY_VARARG_SIGNATURE.
+ */
+static VALUE module_define_jit_method(VALUE klass, VALUE name_v, VALUE 
function_v)
+{
+  char const * name;
+  jit_function_t function;
+  jit_type_t signature;
+  int signature_tag;
+  int arity;
+  VALUE closure_v;
+  struct Closure * closure;
+
+  if(SYMBOL_P(name_v))
+  {
+    name = rb_id2name(SYM2ID(name_v));
+  }
+  else
+  {
+    name = STR2CSTR(name_v);
+  }
+
+  Data_Get_Struct(function_v, struct _jit_function, function);
+
+  signature = jit_function_get_signature(function);
+  signature_tag = (int)jit_function_get_meta(function, RJT_TAG_FOR_SIGNATURE);
+  if(signature_tag == JIT_TYPE_FIRST_TAGGED + RJT_RUBY_VARARG_SIGNATURE)
+  {
+    arity = -1;
+  }
+  else
+  {
+    /* TODO: check the types to make sure they are OBJECT */
+    arity = jit_type_num_params(signature) - 1;
+  }
+
+  closure_v = function_to_closure(function_v);
+  Data_Get_Struct(closure_v, struct Closure, closure);
+  define_method_with_data(
+      klass, rb_intern(name), RUBY_METHOD_FUNC(closure->function_ptr),
+      arity, closure_v);
+  return Qnil;
+}
+
+/* ---------------------------------------------------------------------------
+ * Init
+ * ---------------------------------------------------------------------------
+ */
+
+void Init_jit()
+{
+  jit_init();
+
+  rb_mJIT = rb_define_module("JIT");
+
+  rb_cContext = rb_define_class_under(rb_mJIT, "Context", rb_cObject);
+  rb_define_singleton_method(rb_cContext, "new", context_s_new, 0);
+  rb_define_method(rb_cContext, "build", context_build, 0);
+  rb_define_singleton_method(rb_cContext, "build", context_s_build, 0);
+
+  rb_cClosure = rb_define_class_under(rb_mJIT, "Closure", rb_cObject);
+  rb_define_method(rb_cClosure, "to_int", closure_to_int, 0);
+  rb_define_method(rb_cClosure, "to_s", closure_to_s, 0);
+  rb_define_method(rb_cClosure, "inspect", closure_inspect, 0);
+
+  rb_cFunction = rb_define_class_under(rb_mJIT, "Function", rb_cObject);
+  rb_define_singleton_method(rb_cFunction, "new", function_s_new, -1);
+  rb_define_method(rb_cFunction, "compile", function_compile, 0);
+  rb_define_singleton_method(rb_cFunction, "compile", function_s_compile, -1);
+  rb_define_method(rb_cFunction, "get_param", function_get_param, 1);
+  init_insns();
+  rb_define_method(rb_cFunction, "insn_call", function_insn_call, -1);
+  rb_define_method(rb_cFunction, "insn_call_native", 
function_insn_call_native, -1);
+  rb_define_method(rb_cFunction, "insn_return", function_insn_return, -1);
+  rb_define_method(rb_cFunction, "apply", function_apply, -1);
+  rb_define_alias(rb_cFunction, "call", "apply");
+  rb_define_method(rb_cFunction, "value", function_value, -1);
+  rb_define_method(rb_cFunction, "const", function_const, 2);
+  rb_define_method(rb_cFunction, "optimization_level", 
function_optimization_level, 0);
+  rb_define_method(rb_cFunction, "optimization_level=", 
function_set_optimization_level, 1);
+  rb_define_singleton_method(rb_cFunction, "max_optimization_level", 
function_max_optimization_level, 0);
+  rb_define_method(rb_cFunction, "dump", function_dump, 0);
+  rb_define_method(rb_cFunction, "to_closure", function_to_closure, 0);
+  rb_define_method(rb_cFunction, "context", function_get_context, 0);
+  rb_define_method(rb_cFunction, "compiled?", function_is_compiled, 0);
+
+  rb_cType = rb_define_class_under(rb_mJIT, "Type", rb_cObject);
+  rb_define_singleton_method(rb_cType, "create_signature", 
type_s_create_signature, 3);
+  rb_define_singleton_method(rb_cType, "create_struct", type_s_create_struct, 
1);
+  rb_define_singleton_method(rb_cType, "create_pointer", 
type_s_create_pointer, 1);
+  rb_define_method(rb_cType, "get_offset", type_get_offset, 1);
+  rb_define_method(rb_cType, "set_offset", type_set_offset, 2);
+  rb_define_method(rb_cType, "size", type_size, 0);
+  rb_define_const(rb_cType, "VOID", wrap_type(jit_type_void));
+  rb_define_const(rb_cType, "SBYTE", wrap_type(jit_type_sbyte));
+  rb_define_const(rb_cType, "UBYTE", wrap_type(jit_type_ubyte));
+  rb_define_const(rb_cType, "SHORT", wrap_type(jit_type_short));
+  rb_define_const(rb_cType, "USHORT", wrap_type(jit_type_ushort));
+  rb_define_const(rb_cType, "INT", wrap_type(jit_type_int));
+  rb_define_const(rb_cType, "UINT", wrap_type(jit_type_uint));
+  rb_define_const(rb_cType, "NINT", wrap_type(jit_type_nint));
+  rb_define_const(rb_cType, "NUINT", wrap_type(jit_type_nuint));
+  rb_define_const(rb_cType, "LONG", wrap_type(jit_type_long));
+  rb_define_const(rb_cType, "ULONG", wrap_type(jit_type_ulong));
+  rb_define_const(rb_cType, "FLOAT32", wrap_type(jit_type_float32));
+  rb_define_const(rb_cType, "FLOAT64", wrap_type(jit_type_float64));
+  rb_define_const(rb_cType, "NFLOAT", wrap_type(jit_type_nfloat));
+  rb_define_const(rb_cType, "VOID_PTR", wrap_type(jit_type_void_ptr));
+
+  jit_type_VALUE = jit_type_create_tagged(jit_underlying_type_VALUE, 
RJT_OBJECT, 0, 0, 1);
+  rb_define_const(rb_cType, "OBJECT", wrap_type(jit_type_VALUE));
+
+  jit_type_ID = jit_type_create_tagged(jit_underlying_type_ID, RJT_ID, 0, 0, 
1);
+  rb_define_const(rb_cType, "ID", wrap_type(jit_type_ID));
+
+  jit_type_Function_Ptr = jit_type_create_tagged(jit_underlying_type_ID, 
RJT_FUNCTION_PTR, 0, 0, 1);
+  rb_define_const(rb_cType, "FUNCTION_PTR", wrap_type(jit_type_Function_Ptr));
+
+  {
+    jit_type_t ruby_vararg_param_types[3];
+    jit_type_t ruby_vararg_signature_untagged;
+    ruby_vararg_param_types[0] = jit_type_int;
+    ruby_vararg_param_types[1] = jit_type_void_ptr;
+    ruby_vararg_param_types[2] = jit_type_VALUE;
+    ruby_vararg_signature_untagged = jit_type_create_signature(
+          jit_abi_cdecl,
+          jit_type_VALUE,
+          ruby_vararg_param_types,
+          3,
+          1);
+    ruby_vararg_signature = 
jit_type_create_tagged(ruby_vararg_signature_untagged, 
RJT_RUBY_VARARG_SIGNATURE, 0, 0, 1);
+  }
+  rb_define_const(rb_cType, "RUBY_VARARG_SIGNATURE", 
wrap_type(ruby_vararg_signature));
+
+  rb_mABI = rb_define_module_under(rb_mJIT, "ABI");
+  rb_define_const(rb_mABI, "CDECL", INT2NUM(jit_abi_cdecl));
+  rb_define_const(rb_mABI, "VARARG", INT2NUM(jit_abi_vararg));
+  rb_define_const(rb_mABI, "STDCALL", INT2NUM(jit_abi_stdcall));
+  rb_define_const(rb_mABI, "FASTCALL", INT2NUM(jit_abi_fastcall));
+
+  rb_cValue = rb_define_class_under(rb_mJIT, "Value", rb_cObject);
+  rb_define_singleton_method(rb_cValue, "new_value", value_s_new_value, 2);
+  rb_define_method(rb_cValue, "to_s", value_to_s, 0);
+  rb_define_method(rb_cValue, "inspect", value_inspect, 0);
+  rb_define_method(rb_cValue, "valid?", value_is_valid, 0);
+  rb_define_method(rb_cValue, "temporary?", value_is_temporary, 0);
+  rb_define_method(rb_cValue, "local?", value_is_local, 0);
+  rb_define_method(rb_cValue, "constant?", value_is_constant, 0);
+  rb_define_method(rb_cValue, "volatile?", value_is_volatile, 0);
+  rb_define_method(rb_cValue, "set_volatile", value_set_volatile, 0);
+  rb_define_method(rb_cValue, "addressable?", value_is_addressable, 0);
+  rb_define_method(rb_cValue, "addressable=", value_set_addressable, 0);
+  rb_define_method(rb_cValue, "function", value_function, 0);
+  rb_define_method(rb_cValue, "type", value_type, 0);
+  rb_define_method(rb_cValue, "coerce", value_coerce, 1);
+
+  rb_cLabel = rb_define_class_under(rb_mJIT, "Label", rb_cObject);
+  rb_define_singleton_method(rb_cLabel, "new", label_s_new, 0);
+
+  rb_mCall = rb_define_module_under(rb_mJIT, "Call");
+  rb_define_const(rb_mCall, "NOTHROW", INT2NUM(JIT_CALL_NOTHROW));
+  rb_define_const(rb_mCall, "NORETURN", INT2NUM(JIT_CALL_NORETURN));
+  rb_define_const(rb_mCall, "TAIL", INT2NUM(JIT_CALL_TAIL));
+
+  /* VALUE rb_cModule = rb_define_module(); */
+  rb_define_method(rb_cModule, "define_jit_method", module_define_jit_method, 
2);
+
+#ifdef NEED_MINIMAL_NODE
+  Init_minimal_node();
+#endif
+}
+

Index: jitruby/ext/method_data.c.rpp
===================================================================
RCS file: jitruby/ext/method_data.c.rpp
diff -N jitruby/ext/method_data.c.rpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/ext/method_data.c.rpp       12 Dec 2008 11:31:03 -0000      1.1
@@ -0,0 +1,294 @@
+#include "method_data.h"
+
+#include <ruby.h>
+
+#ifndef HAVE_RUBINIUS
+
+#ruby <<END
+MAX_ARGS = 15
+nil
+END
+
+#if defined(HAVE_NODE_H)
+/* pre-YARV */
+#include <node.h>
+#elif defined(REALLY_HAVE_RUBY_NODE_H)
+/* YARV */
+#include <ruby/node.h>
+#elif defined(RUBY_VM)
+/* YARV without node.h */
+#include "minimal_node.h"
+#else
+/* something else */
+#error "Need node.h"
+#endif
+
+#ifdef HAVE_ENV_H
+/* pre-YARV */
+#include <env.h>
+#endif
+
+#ifdef RUBY_VM
+
+/* YARV */
+
+struct rb_thread_struct
+{   
+    VALUE self;
+    void *vm;
+    VALUE *stack;
+    unsigned long stack_size;
+    VALUE *cfp;
+    /* ... */
+};
+
+typedef struct rb_thread_struct rb_thread_t;
+
+#define CFP_DATA_MEMO_NODE_AND_PC cfp[0]
+#define CFP_METHOD_CLASS cfp[11]
+
+/* On YARV, we store the method data on the stack.  We don't have to pop
+ * it off the stack, because the stack pointer will be reset to the
+ * previous frame's stack pointer when the function returns.
+ */
+static void fix_frame()
+{
+  do {
+    extern rb_thread_t * ruby_current_thread;
+    VALUE * cfp = ruby_current_thread->cfp;
+    CFP_DATA_MEMO_NODE_AND_PC = RBASIC(CFP_METHOD_CLASS)->klass;
+
+    if(rb_type(CFP_DATA_MEMO_NODE_AND_PC) != T_NODE)
+    {
+      /* This can happen for module functions that are created after
+       * the stub function */
+      rb_raise(
+          rb_eRuntimeError,
+          "Cannot find method data for module function");
+    }
+    else
+    {
+      CFP_METHOD_CLASS = RCLASS_SUPER(CFP_METHOD_CLASS);
+    }
+  } while(0);
+}
+
+#define FIX_FRAME() \
+  fix_frame()
+
+static NODE * data_memo_node()
+{
+  extern rb_thread_t * ruby_current_thread;
+  VALUE * cfp = ruby_current_thread->cfp;
+  return (NODE *)CFP_DATA_MEMO_NODE_AND_PC;
+}
+
+#else
+
+/* pre-YARV */
+
+/* Okay to not pop this temporary frame, since it will be popped by the
+ * caller
+ */
+#define FIX_FRAME() \
+  struct FRAME _frame = *ruby_frame; \
+  _frame.last_class = RCLASS(ruby_frame->last_class)->super; \
+  _frame.prev = ruby_frame; \
+  ruby_frame = &_frame; \
+
+static NODE * data_memo_node()
+{
+  return (NODE *)(RBASIC(ruby_frame->prev->last_class)->klass);
+}
+
+#endif
+
+typedef VALUE (*Method_Func)(ANYARGS);
+
+static Method_Func actual_cfunc()
+{
+  return data_memo_node()->nd_cfnc;
+}
+
+static VALUE data_wrapper_m1(int argc, VALUE * argv, VALUE self)
+{
+  VALUE result;
+  FIX_FRAME();
+  result = (*actual_cfunc())(argc, argv, self);
+  return result;
+}
+
+static VALUE data_wrapper_0(VALUE self)
+{
+  VALUE result;
+  FIX_FRAME();
+  result = (*actual_cfunc())(self);
+  return result;
+}
+
+#ruby <<END
+  (1..MAX_ARGS).each do |i|
+    params = (1..i).map { |j| "VALUE arg#{j}" }.join(', ')
+    args = (1..i).map { |j| "arg#{j}" }.join(', ')
+
+    puts <<-END
+static VALUE data_wrapper_#{i}(VALUE self, #{params})
+{
+  VALUE result;
+  FIX_FRAME();
+  result = (*actual_cfunc())(self, #{args});
+  return result;
+}
+    END
+  end
+
+  nil
+END
+
+/* Define a method and attach data to it.
+ *
+ * The method looks to ruby like a normal aliased CFUNC, with a modified
+ * origin class:
+ *
+ * NODE_FBODY
+ *   |- (u1) orig - origin class
+ *   |  |- basic
+ *   |  |  |- flags - origin class flags + FL_SINGLETON
+ *   |  |  +- klass - NODE_MEMO
+ *   |  |     |- (u1) cfnc - actual C function to call
+ *   |  |     |- (u2) rval - stored data
+ *   |  |     +- (u3) 0
+ *   |  |- iv_tbl - 0
+ *   |  |- m_tbl - 0
+ *   |  +- super - actual origin class
+ *   |- (u2) mid - name of the method
+ *   +- (u3) head - NODE_CFUNC
+ *      |- (u1) cfnc - wrapper function to call
+ *      +- (u2) argc - function arity
+ *
+ * Or, on YARV:
+ *
+ * NODE_FBODY
+ *   |- (u1) oid - name of the method
+ *   +- (u2) body - NODE_METHOD
+ *      |- (u1) clss - origin class
+ *      |  |- basic
+ *      |  |  |- flags - origin class flags + FL_SINGLETON
+ *      |  |  +- klass - NODE_MEMO
+ *      |  |     |- (u1) cfnc - actual C function to call
+ *      |  |     |- (u2) rval - stored data
+ *      |  |     +- (u3) 0
+ *      |  |- ptr - rb_classext_t
+ *      |  |  |- super - actual origin class
+ *      |  |  +- iv_tbl - 0
+ *      |  |- m_tbl - 0
+ *      |  +- iv_index_tbl - 0?
+ *      |- (u2) body - NODE_CFUNC
+ *      |  |- (u1) cfnc - wrapper function to call
+ *      |  |- (u2) argc - function arity
+ *      +- (u3) noex - NOEX_PUBLIC
+ *
+ * When the wrapper function is called, last_class is set to the origin
+ * class found in the FBODY node.  So that the method data will be
+ * accessible, and so last_class will point to klass and not to our MEMO
+ * node, it is necessary to "fix" the current frame.
+ *
+ * Pre-YARV, this means we duplicate the current frame and set last_class:
+ *
+ * ruby_frame
+ *   |- last_class - klass
+ *   |- prev
+ *   |  |- last_class - NODE_MEMO
+ *   |  |  |- (u1) cfnc - actual C function to call
+ *   |  |  |- (u2) rval - stored data
+ *   |  |  +- (u3) 0
+ *   |  |- prev - the real previous frame
+ *   |  +- ...
+ *   +- ...
+ *
+ * The method data is then accessible via
+ * ruby_frame->prev->last_class->rval.
+ *
+ * On YARV, the current frame is not duplicated; rather, the method data
+ * is placed on the stack and is referenced by one of the unused members
+ * of the control frame (the program counter):
+ *
+ * ruby_current_thread->cfp
+ *   |- pc - NODE_MEMO
+ *   |  |- (u1) cfnc - actual C function to call
+ *   |  |- (u2) rval - stored data
+ *   |  +- (u3) 0
+ *   |- method_class - klass
+ *   +- ...
+ *
+ */
+void define_method_with_data(
+    VALUE klass, ID id, VALUE (*cfunc)(ANYARGS), int arity, VALUE data)
+{
+  /* TODO: origin should have #to_s and #inspect methods defined */
+#ifdef HAVE_RB_CLASS_BOOT
+  VALUE origin = rb_class_boot(klass);
+#else
+  VALUE origin = rb_class_new(klass);
+#endif
+  NODE * node;
+
+  VALUE (*data_wrapper)(ANYARGS);
+  switch(arity)
+  {
+#ruby <<END
+  (0..MAX_ARGS).each do |i|
+    puts <<-END
+    case #{i}: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_#{i}); break;
+    END
+  end
+  nil
+END
+    case -1: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_m1); break;
+    default: rb_raise(rb_eArgError, "unsupported arity %d", arity);
+  }
+
+  FL_SET(origin, FL_SINGLETON);
+  rb_singleton_class_attached(origin, klass);
+  rb_name_class(origin, SYM2ID(rb_class_name(klass)));
+
+  RBASIC(origin)->klass = (VALUE)NEW_NODE(NODE_MEMO, cfunc, data, 0);
+
+#ifdef RUBY_VM
+  /* YARV */
+  node = NEW_FBODY(
+      NEW_METHOD(
+          NEW_CFUNC(data_wrapper, arity),
+          origin,
+          NOEX_PUBLIC),
+      id);
+  st_insert(RCLASS_M_TBL(klass), id, (st_data_t)node);
+#else
+  /* pre-YARV */
+  node = NEW_FBODY(
+      NEW_CFUNC(data_wrapper, arity),
+      id,
+      origin);
+  rb_add_method(klass, id, node, NOEX_PUBLIC);
+#endif
+}
+
+VALUE get_method_data()
+{
+  return data_memo_node()->nd_rval;
+}
+
+#else /* HAVE_RUBINIUS */
+
+void define_method_with_data(
+    VALUE klass, ID id, VALUE (*cfunc)(ANYARGS), int arity, VALUE data)
+{
+  rb_raise(rb_eNotImpError, "Not implemented: define_method_with_data");
+}
+
+VALUE get_method_data()
+{
+  rb_raise(rb_eNotImpError, "Not implemented: get_method_data");
+}
+
+#endif

Index: jitruby/ext/method_data.h
===================================================================
RCS file: jitruby/ext/method_data.h
diff -N jitruby/ext/method_data.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/ext/method_data.h   12 Dec 2008 11:31:03 -0000      1.1
@@ -0,0 +1,11 @@
+#ifndef METHOD_DATA_H
+#define METHOD_DATA_H
+
+#include <ruby.h>
+
+void define_method_with_data(
+    VALUE klass, ID id, VALUE (*cfunc)(ANYARGS), int arity, VALUE data);
+
+VALUE get_method_data();
+
+#endif // METHOD_DATA_H

Index: jitruby/ext/minimal_node.c
===================================================================
RCS file: jitruby/ext/minimal_node.c
diff -N jitruby/ext/minimal_node.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/ext/minimal_node.c  12 Dec 2008 11:31:03 -0000      1.1
@@ -0,0 +1,35 @@
+#ifdef NEED_MINIMAL_NODE
+
+#include "minimal_node.h"
+#include <string.h>
+
+int NODE_MEMO = 0;
+int NODE_METHOD = 0;
+int NODE_FBODY = 0;
+int NODE_CFUNC = 0;
+
+char const * ruby_node_name(int node);
+
+static int node_value(char const * name)
+{
+  /* TODO: any way to end the block? */
+  int j;
+  for(j = 0; ; ++j)
+  {
+    if(!strcmp(name, ruby_node_name(j)))
+    {
+      return j;
+    }
+  }
+}
+
+void Init_minimal_node()
+{
+  NODE_MEMO = node_value("NODE_MEMO");
+  NODE_METHOD = node_value("NODE_METHOD");
+  NODE_FBODY = node_value("NODE_FBODY");
+  NODE_CFUNC = node_value("NODE_CFUNC");
+}
+
+#endif
+

Index: jitruby/ext/minimal_node.h
===================================================================
RCS file: jitruby/ext/minimal_node.h
diff -N jitruby/ext/minimal_node.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/ext/minimal_node.h  12 Dec 2008 11:31:03 -0000      1.1
@@ -0,0 +1,52 @@
+#ifndef minimal_node_h
+#define minimal_node_h
+
+#ifdef NEED_MINIMAL_NODE
+
+#include "ruby.h"
+
+typedef struct RNode {
+  unsigned long flags;
+  void * reserved;
+  union {
+    struct RNode * node;
+    VALUE (*cfunc)(ANYARGS);
+  } u1;
+  union {
+    struct RNode * node;
+    VALUE value;
+  } u2;
+  union {
+    struct RNode * node;
+  } u3;
+} NODE;
+
+#define nd_cfnc u1.cfunc
+#define nd_rval u2.value
+
+#define NEW_NODE(t,a0,a1,a2) 
rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2))
+
+/* TODO: No way to know the correct size of node_type */
+enum node_type {
+  NODE_FOO,
+};
+
+void rb_add_method(VALUE, ID, NODE *, int);
+NODE *rb_node_newnode(enum node_type, VALUE, VALUE, VALUE);
+
+extern int NODE_MEMO;
+extern int NODE_METHOD;
+extern int NODE_FBODY;
+extern int NODE_CFUNC;
+
+void Init_minimal_node();
+
+#define NOEX_PUBLIC 0x0
+
+#define NEW_METHOD(n,x,v) NEW_NODE(NODE_METHOD,x,n,v)
+#define NEW_FBODY(n,i) NEW_NODE(NODE_FBODY,i,n,0)
+#define NEW_CFUNC(f,c) NEW_NODE(NODE_CFUNC,f,c,0)
+
+#endif
+
+#endif

Index: jitruby/ext/rubyjit.h
===================================================================
RCS file: jitruby/ext/rubyjit.h
diff -N jitruby/ext/rubyjit.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/ext/rubyjit.h       12 Dec 2008 11:31:03 -0000      1.1
@@ -0,0 +1,20 @@
+#ifndef RUBYJIT_H
+#define RUBYJIT_H
+
+enum Ruby_Libjit_Tag
+{
+  RJT_OBJECT,
+  RJT_ID,
+  RJT_FUNCTION_PTR,
+  RJT_RUBY_VARARG_SIGNATURE,
+  RJT_VALUE_OBJECTS,
+  RJT_FUNCTIONS,
+  RJT_CONTEXT,
+  RJT_TAG_FOR_SIGNATURE
+};
+
+extern jit_type_t jit_type_VALUE;
+extern jit_type_t jit_type_ID;
+extern jit_type_t jit_type_Function_Ptr;
+
+#endif

Index: jitruby/ext/rubypp.rb
===================================================================
RCS file: jitruby/ext/rubypp.rb
diff -N jitruby/ext/rubypp.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/ext/rubypp.rb       12 Dec 2008 11:31:03 -0000      1.1
@@ -0,0 +1,97 @@
+class Preprocessor
+  def initialize(input, output, filename)
+    @input = input
+    @output = output
+    @filename = filename
+    @linenum = 1
+  end
+
+  def getline
+    line = @input.gets
+    @linenum += 1 if not line.nil?
+    return line
+  end
+
+  def preprocess
+    success = false
+    begin
+      loop do
+        line = getline
+        break if line.nil?
+        case line
+        when /(.*[^\\]|^)\#\{(.*?)\}(.*)/
+          puts "#{$1}#{evaluate($2, @linenum)}#{$3}"
+        when /^\#ruby\s+<<(.*)/
+          marker = $1
+          str = ''
+          evalstart = @linenum
+          loop do
+            line = getline
+            if line.nil? then
+              raise "End of input without #{marker}"
+            end
+            break if line.chomp == marker
+            str << line
+          end
+          result = evaluate(str, evalstart)
+          puts result if not result.nil?
+        when /^\#ruby\s+(.*)/
+          str = line = $1
+          while line[-1] == ?\\
+            str.chop!
+            line = getline
+            break if line.nil?
+            line.chomp!
+            str << line
+          end
+          result = evaluate(str, @linenum)
+          puts result if not result.nil?
+        else
+          puts line
+        end
+      end
+      success = true
+    ensure
+      if not success then
+        $stderr.puts "Error on line address@hidden:"
+      end
+    end
+  end
+
+  def evaluate(str, linenum)
+    result = eval(str, TOPLEVEL_BINDING, @filename, linenum)
+    success = true
+    return result
+  end
+
+  def puts(line='')
+    @output.puts(line)
+  end
+end
+
+def puts(line='')
+  $preprocessor.puts(line)
+end
+
+def rubypp(input_file, output_file)
+  input = input_file ? File.open(input_file) : $stdin
+  output = output_file ? File.open(output_file, 'w') : $stdout
+
+  success = false
+  begin
+    $preprocessor = Preprocessor.new(input, output, input_file || "(stdin)")
+    $preprocessor.preprocess()
+    success = true
+  ensure
+    if not success then
+      File.unlink(output_file) rescue Errno::ENOENT
+    end
+  end
+end
+
+if __FILE__ == $0 then
+  input_file = ARGV[0]
+  output_file = ARGV[1]
+  rubypp(input_file, output_file)
+end
+

Index: jitruby/lib/jit.rb
===================================================================
RCS file: jitruby/lib/jit.rb
diff -N jitruby/lib/jit.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/lib/jit.rb  12 Dec 2008 11:31:03 -0000      1.1
@@ -0,0 +1,5 @@
+require 'jit.so'
+require 'jit/array'
+require 'jit/function'
+require 'jit/struct'
+require 'jit/value'

Index: jitruby/lib/jit/array.rb
===================================================================
RCS file: jitruby/lib/jit/array.rb
diff -N jitruby/lib/jit/array.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/lib/jit/array.rb    12 Dec 2008 11:31:04 -0000      1.1
@@ -0,0 +1,135 @@
+require 'jit'
+require 'jit/value'
+
+module JIT
+
+  # An abstraction for a fixed-length array type.
+  #
+  # Example usage:
+  #
+  #   array_type = JIT::Array.new(JIT::Type::INT, 4)
+  #
+  #   JIT::Context.build do |context|
+  #     signature = JIT::Type.create_signature(
+  #         JIT::ABI::CDECL, JIT::Type::INT, [ ])
+  #
+  #     function = JIT::Function.compile(context, signature) do |f|
+  #       array_instance = array_type.create(f)
+  #       array_instance[0] = f.const(JIT::Type::INT, 42)
+  #       f.insn_return(array_instance[0])
+  #     end
+  #
+  #   end
+  #
+  class Array < JIT::Type
+    attr_reader :type
+    attr_reader :length
+
+    # Create a new JIT array type.
+    #
+    # +type+::   The type of the elements in the array.
+    # +length+:: The number of elements in the array.
+    #
+    def self.new(type, length)
+      array = self.create_struct([ type ] * length)
+      array.instance_eval do
+        @type = type
+        @length = length
+      end
+      return array
+    end
+
+    # Wrap an existing array.
+    #
+    # +ptr+:: A pointer to the first element in the array.
+    #
+    def wrap(ptr)
+      return Instance.wrap(self, ptr)
+    end
+
+    # Create a new array.
+    #
+    # +function+:: The JIT::Function this array will be used in.
+    #
+    def create(function)
+      instance = function.value(self)
+      ptr = function.insn_address_of(instance)
+      return wrap(ptr)
+    end
+
+    # Return the offset (in bytes) of the element at the given +index+.
+    #
+    # +index+:: The index of the desired element.
+    #
+    def offset_of(index)
+      return self.get_offset(index)
+    end
+
+    # Return the type of the element at the given +index+.
+    #
+    # +index+:: The index of the desired element.
+    #
+    def type_of(index)
+      return @type
+    end
+
+    # An abstraction for an instance of a fixed-length array.
+    #
+    class Instance < JIT::Value
+      attr_reader :array_type
+      attr_reader :type
+
+      # A pointer to the first element of the array.  Note that this
+      # differs from +address+, which returns the address of a pointer
+      # to the array.
+      attr_reader :ptr
+
+      # TODO: This breaks code below?
+      # attr_reader :function
+
+      # Wrap an existing array.
+      #
+      # +array_type+:: The JIT::Array type to wrap.
+      # +ptr+::        A pointer to the first element in the array.
+      #
+      def self.wrap(array_type, ptr)
+        pointer_type = JIT::Type.create_pointer(array_type)
+        value = self.new_value(ptr.function, pointer_type)
+        value.store(ptr)
+        value.instance_eval do
+          @array_type = array_type
+          @type = array_type.type
+          @function = ptr.function
+          @ptr = ptr
+        end
+        return value
+      end
+
+      # Generate JIT code to retrieve the element at the given +index+.
+      #
+      # +index+:: The index of the desired element.  The value of the
+      #           index must be known at compile-time.
+      #
+      def [](index)
+        @function.insn_load_relative(
+            @ptr,
+            @array_type.offset_of(index),
+            @array_type.type_of(index))
+      end
+
+      # Generate JIT code to assign to the element at the given +index+.
+      #
+      # +index+:: The index of the desired element.  The value of the
+      #           index must be known at compile-time.
+      # +value+:: The JIT::Value to assign to the element.
+      #
+      def []=(index, value)
+        @function.insn_store_relative(
+            @ptr,
+            @array_type.offset_of(index),
+            value)
+      end
+    end
+  end
+end
+

Index: jitruby/lib/jit/function.rb
===================================================================
RCS file: jitruby/lib/jit/function.rb
diff -N jitruby/lib/jit/function.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/lib/jit/function.rb 12 Dec 2008 11:31:04 -0000      1.1
@@ -0,0 +1,200 @@
+require 'jit'
+
+module JIT
+  class Function
+    # An abstraction for conditionals.
+    #
+    # Example usage:
+    #
+    #   function.if(condition) {
+    #     # condition is true
+    #   } .elsif(condition2) {
+    #     # condition2 is true
+    #   } .else {
+    #     # condition1 and condition2 are false
+    #   } .end
+    #
+    # Caution: if you omit end, then the generated code will have
+    # undefined behavior, but there will be no warning generated.
+    def if(cond, end_label = Label.new, &block)
+      false_label = Label.new
+      insn_branch_if_not(cond, false_label)
+      block.call
+      insn_branch(end_label)
+      insn_label(false_label)
+      return If.new(self, end_label)
+    end
+
+    # An abstraction for an inverted conditional.
+    #
+    # Example usage:
+    #
+    #   function.unless(condition) {
+    #     # condition is false
+    #   } .elsunless(condition2) {
+    #     # condition2 is false
+    #   } .else {
+    #     # condition1 and condition2 are true
+    #   } .end
+    #
+    # Caution: if you omit end, then the generated code will have
+    # undefined behavior, but there will be no warning generated.
+    def unless(cond, end_label = Label.new, &block)
+      true_label = Label.new
+      insn_branch_if(cond, true_label)
+      block.call
+      insn_branch(end_label)
+      insn_label(true_label)
+      return If.new(self, end_label)
+    end
+
+    class If # :nodoc:
+      def initialize(function, end_label)
+        @function = function
+        @end_label = end_label
+      end
+
+      def else(&block)
+        block.call
+        return self
+      end
+
+      def elsif(cond, &block)
+        return @function.if(cond, @end_label, &block)
+      end
+
+      def elsunless(cond, &block)
+        return @function.unless(cond, @end_label, &block)
+      end
+
+      def end
+        @function.insn_label(@end_label)
+      end
+    end
+
+    # An abstraction for a multi-way conditional.
+    #
+    # Example usage:
+    #
+    #   function.case(value1)
+    #   .when(value2) {
+    #     # value1 == value2
+    #   }.when(value3) {
+    #     # value1 == value3
+    #   } .else {
+    #     # all other cases fell through
+    #   } .end
+    #
+    # Caution: if you omit end, then the generated code will have
+    # undefined behavior, but there will be no warning generated.
+    def case(value)
+      return Case.new(self, value)
+    end
+
+    class Case # :nodoc:
+      def initialize(function, value)
+        @function = function
+        @value = value
+        @if = nil
+      end
+
+      def when(value, &block)
+        if not @if then
+          @if = @function.if(value == @value, &block)
+        else
+          @if.elsif(value == @value, &block)
+        end
+        return self
+      end
+
+      def else(&block)
+        @if.else(&block)
+      end
+
+      def end
+        @if.end if @if
+      end
+    end
+
+    # Usage:
+    #
+    #   until { <condition> }.do {
+    #     # loop body
+    #   } .end
+    #
+    def until(&block)
+      start_label = Label.new
+      done_label = Label.new
+      insn_label(start_label)
+      insn_branch_if(block.call, done_label)
+      loop = Loop.new(self, start_label, done_label)
+      return loop
+    end
+
+    # Usage:
+    #
+    #   while { <condition> }.do {
+    #     # loop body
+    #   } .end
+    #
+    def while(&block)
+      start_label = Label.new
+      done_label = Label.new
+      insn_label(start_label)
+      insn_branch_if_not(block.call, done_label)
+      loop = Loop.new(self, start_label, done_label)
+      return loop
+    end
+
+    class Loop # :nodoc:
+      def initialize(function, start_label, done_label)
+        @function = function
+        @start_label = start_label
+        @redo_label = start_label
+        @done_label = done_label
+      end
+
+      def do(&block)
+        block.call(self)
+        return self
+      end
+
+      def end
+        @function.insn_branch(@start_label)
+        @function.insn_label(@done_label)
+      end
+
+      def break
+        @function.insn_branch(@done_label)
+      end
+
+      def redo
+        @function.insn_branch(@redo_label)
+      end
+
+      def redo_from_here
+        @redo_label = JIT::Label.new
+        @function.insn_label(@redo_label)
+      end
+    end
+
+    # An alias for get_param
+    def param(n)
+      self.get_param(n)
+    end
+
+    # An alias for insn_return
+    def return(result)
+      self.insn_return(result)
+    end
+
+    # Create a JIT::Context and compile a new function within that
+    # context.
+    def self.build(*args, &block)
+      JIT::Context.build do |context|
+        JIT::Function.compile(context, *args, &block)
+      end
+    end
+  end
+end
+

Index: jitruby/lib/jit/pointer.rb
===================================================================
RCS file: jitruby/lib/jit/pointer.rb
diff -N jitruby/lib/jit/pointer.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/lib/jit/pointer.rb  12 Dec 2008 11:31:04 -0000      1.1
@@ -0,0 +1,98 @@
+require 'jit'
+require 'jit/value'
+
+module JIT
+
+  # An abstraction for a pointer to a non-void type.
+  #
+  # Example usage:
+  #
+  # TODO
+  #
+  class Pointer < JIT::Type
+    attr_reader :type
+
+    # Create a new JIT pointer type.
+    #
+    # +type+::   The pointed-to type.
+    #
+    def self.new(type)
+      pointer_type = self.create_pointer(type)
+      pointer_type.instance_eval do
+        @type = type
+      end
+      return pointer_type
+    end
+
+    # Wrap an existing void pointer.
+    #
+    # +ptr+:: The pointer to wrap.
+    #
+    def wrap(ptr)
+      return Instance.wrap(self, ptr)
+    end
+
+    # Return the offset (in bytes) of the element at the given +index+.
+    #
+    # +index+:: The index of the desired element.
+    #
+    def offset_of(index)
+      return index * @type.size
+    end
+
+    # Return the type of the element at the given +index+.
+    #
+    # +index+:: The index of the desired element.
+    #
+    def type_of(index)
+      return @type
+    end
+
+    # An abstraction for a pointer object.
+    #
+    class Instance < JIT::Value
+      # Wrap an existing void pointer.
+      #
+      # +array_type+:: The JIT::Array type to wrap.
+      # +ptr+::        A pointer to the first element in the array.
+      #
+      def self.wrap(pointer_type, ptr)
+        value = self.new_value(ptr.function, pointer_type)
+        value.store(ptr)
+        value.instance_eval do
+          @pointer_type = pointer_type
+          @pointed_type = pointer_type.type
+          @function = ptr.function
+          @ptr = ptr
+        end
+        return value
+      end
+
+      # Generate JIT code to retrieve the element at the given +index+.
+      #
+      # +index+:: The index of the desired element.  The value of the
+      #           index must be known at compile-time.
+      #
+      def [](index)
+        @function.insn_load_relative(
+            @ptr,
+            @pointer_type.offset_of(index),
+            @pointer_type.type_of(index))
+      end
+
+      # Generate JIT code to assign to the element at the given +index+.
+      #
+      # +index+:: The index of the desired element.  The value of the
+      #           index must be known at compile-time.
+      # +value+:: The JIT::Value to assign to the element.
+      #
+      def []=(index, value)
+        @function.insn_store_relative(
+            @ptr,
+            @pointer_type.offset_of(index),
+            value)
+      end
+    end
+  end
+end
+

Index: jitruby/lib/jit/struct.rb
===================================================================
RCS file: jitruby/lib/jit/struct.rb
diff -N jitruby/lib/jit/struct.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/lib/jit/struct.rb   12 Dec 2008 11:31:04 -0000      1.1
@@ -0,0 +1,158 @@
+require 'jit'
+
+module JIT
+
+  # An abstraction for a record composed of heterogenous fields.
+  #
+  # Example usage:
+  #
+  #   point_type = JIT::Struct.new(
+  #       [ :x, JIT::Type::INT ],
+  #       [ :y, JIT::Type::INT ],
+  #       [ :z, JIT::Type::INT ])
+  #
+  #   JIT::Context.build do |context|
+  #     signature = JIT::Type.create_signature(
+  #         JIT::ABI::CDECL, JIT::Type::INT, [ ])
+  #
+  #     function = JIT::Function.compile(context, signature) do |f|
+  #       point = point_type.create(f)
+  #       point.x = function.const(JIT::Type::INT, 1)
+  #       point.y = function.const(JIT::Type::INT, 2)
+  #       point.z = function.const(JIT::Type::INT, 3)
+  #       f.insn_return(point.x)
+  #     end
+  #
+  #   end
+  #
+  class Struct < JIT::Type
+
+    # Construct a new JIT structure type.
+    #
+    # +members+:: A list of members, where each element in the list is a
+    #             two-element array [ :name, type ]
+    #
+    def self.new(*members)
+      member_names = members.map { |m| m[0].to_s.intern }
+      member_types = members.map { |m| m[1] }
+      type = self.create_struct(member_types)
+      type.instance_eval do
+        @members = members
+        @member_names = member_names
+        @member_types = member_types
+        @index = address@hidden((address@hidden).to_a).flatten]
+      end
+      return type
+    end
+
+    # Return the names of the members in the structure.
+    def members
+      return @member_names
+    end
+
+    # Wrap an existing structure.
+    #
+    # +ptr+:: A pointer to the first element in the structure.
+    #
+    def wrap(ptr)
+      return Instance.new(self, ptr)
+    end
+
+    # Create a new structure.
+    #
+    # +function+:: The JIT::Function this structure will be used in.
+    #
+    def create(function)
+      instance = function.value(self)
+      ptr = function.insn_address_of(instance)
+      return wrap(ptr)
+    end
+
+    # Return the offset (in bytes) of the element with the given name.
+    #
+    # +name+:: The name of the desired element.
+    #
+    def offset_of(name)
+      name = (Symbol === name) ? name : name.to_s.intern
+      return self.get_offset(@index[name])
+    end
+
+    # Change the offset of the element with the given name.
+    #
+    # +name+::   The name of the desired element.
+    # +offset+:: The new offset.
+    #
+    def set_offset_of(name, offset)
+      name = (Symbol === name) ? name : name.to_s.intern
+      return self.set_offset(@index[name], offset)
+    end
+
+    # Return the type of the element with the given name.
+    #
+    # +name+:: The name of the desired element.
+    #
+    def type_of(name)
+      name = (Symbol === name) ? name : name.to_s.intern
+      return @address@hidden
+    end
+
+    # An abstraction for an instance of a JIT::Struct.
+    #
+    class Instance
+      attr_reader :ptr
+
+      # Wrap an existing structure.
+      #
+      # +struct+:: The JIT::Struct type to wrap.
+      # +ptr+      A pointer to the first element of the structure.
+      #
+      def initialize(struct, ptr)
+        @struct = struct
+        @function = ptr.function
+        @ptr = ptr
+
+        mod = Module.new do
+          struct.members.each do |name|
+            define_method("#{name}") do
+              self[name] # return
+            end
+
+            define_method("#{name}=") do |value|
+              self[name] = value # return
+            end
+          end
+        end
+
+        extend(mod)
+      end
+
+      # Generate JIT code to retrieve the element with the given name.
+      #
+      # +name+:: The name of the desired element.
+      #
+      def [](name)
+        @function.insn_load_relative(
+            @ptr,
+            @struct.offset_of(name),
+            @struct.type_of(name))
+      end
+
+      # Generate JIT code to assign to the element with the given name.
+      #
+      # +name+::  The name of the desired element.
+      # +value+:: The JIT::Value to assign to the element.
+      #
+      def []=(name, value)
+        @function.insn_store_relative(
+            @ptr,
+            @struct.offset_of(name),
+            value)
+      end
+
+      def members
+        return @struct.members
+      end
+    end
+  end
+end
+

Index: jitruby/lib/jit/value.rb
===================================================================
RCS file: jitruby/lib/jit/value.rb
diff -N jitruby/lib/jit/value.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/lib/jit/value.rb    12 Dec 2008 11:31:04 -0000      1.1
@@ -0,0 +1,199 @@
+require 'jit'
+
+module JIT
+  class Value
+    module UNINITIALIZED; end
+
+    # Create a new JIT::Value.  If value is specified, the value will be
+    # variable, otherwise it will be a constant with the given value.
+    #
+    # +function+:: The function to which this value will belong.
+    # +type+::     The type of the new value.
+    # +value+:     The value to use, if this is a constant.
+    #
+    def self.new(function, type, value=UNINITIALIZED)
+      # TODO: Not sure if I like this...
+      if value == UNINITIALIZED then
+        return function.value(type)
+      else
+        return function.const(type, value)
+      end
+    end
+
+    # Assign +value+ to this JIT::Value.
+    #
+    # +value+:: The value to assign.
+    #
+    def store(value)
+      lhs, rhs = coerce(value)
+      self.function.insn_store(lhs, rhs)
+    end
+
+    # Return the address of this value.
+    def address
+      return self.function.insn_address_of(self)
+    end
+
+    # Add this value to another and return the result.
+    #
+    # +rhs+:: The right hand side of the addition operator.
+    #
+    def +(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_add(lhs, rhs)
+    end
+
+    # Subtract another value from this one and return the result.
+    #
+    # +rhs+:: The right hand side of the subtraction operator.
+    #
+    def -(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_sub(lhs, rhs)
+    end
+
+    # Multiply this value by another and return the result.
+    #
+    # +rhs+:: The right hand side of the multiplication operator.
+    #
+    def *(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_mul(lhs, rhs)
+    end
+
+    # Divide this value by another and return the quotient.
+    #
+    # +rhs+:: The right hand side of the division operator.
+    #
+    def /(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_div(lhs, rhs)
+    end
+
+    # Return the additive inverse (negation) of this value.
+    def -@()
+      rhs, lhs = coerce(0) # inverted, since we are subtracting from 0
+      return lhs - rhs
+    end
+
+    # Divide this value by another and return the remainder.
+    #
+    # +rhs+:: The right hand side of the modulus operator.
+    #
+    def %(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_rem(lhs, rhs)
+    end
+
+    # Perform a bitwise and between this value and another.
+    #
+    # +rhs+:: The right hand side of the operator.
+    #
+    def &(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_and(lhs, rhs)
+    end
+
+    # Perform a bitwise or between this value and another.
+    #
+    # +rhs+:: The right hand side of the operator.
+    #
+    def |(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_or(lhs, rhs)
+    end
+
+    # Perform a bitwise xor between this value and another.
+    #
+    # +rhs+:: The right hand side of the operator.
+    #
+    def ^(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_xor(lhs, rhs)
+    end
+
+    # Compare this value to another, returning 1 if the left hand is
+    # less than the right hand side or 0 otherwise.
+    #
+    # +rhs+:: The right hand side of the comparison.
+    #
+    def <(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_lt(lhs, rhs)
+    end
+
+    # Compare this value to another, returning 1 if the left hand is
+    # greater than the right hand side or 0 otherwise.
+    #
+    # +rhs+:: The right hand side of the comparison.
+    #
+    def >(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_gt(lhs, rhs)
+    end
+
+    # Compare this value to another, returning 1 if the left hand is
+    # equal to the right hand side or 0 otherwise.
+    #
+    # +rhs+:: The right hand side of the comparison.
+    #
+    def ==(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_eq(lhs, rhs)
+    end
+
+    # Compare this value to another, returning 1 if the left hand is
+    # not equal to the right hand side or 0 otherwise.
+    #
+    # +rhs+:: The right hand side of the comparison.
+    #
+    def neq(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_ne(lhs, rhs)
+    end
+
+    # Compare this value to another, returning 1 if the left hand is
+    # less than or equal to the right hand side or 0 otherwise.
+    #
+    # +rhs+:: The right hand side of the comparison.
+    #
+    def <=(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_le(lhs, rhs)
+    end
+
+    # Compare this value to another, returning 1 if the left hand is
+    # greater than or equal to the right hand side or 0 otherwise.
+    #
+    # +rhs+:: The right hand side of the comparison.
+    #
+    def >=(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_ge(lhs, rhs)
+    end
+
+    # Shift this value left by the given number of bits.
+    #
+    # +rhs+:: The number of bits to shift by.
+    #
+    def <<(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_shl(lhs, rhs)
+    end
+
+    # Shift this value right by the given number of bits.
+    #
+    # +rhs+:: The number of bits to shift by.
+    #
+    def >>(rhs)
+      lhs, rhs = coerce(rhs)
+      return self.function.insn_shr(lhs, rhs)
+    end
+
+    # Return the logical inverse of this value.
+    def ~()
+      return self.function.insn_not(self)
+    end
+  end
+end
+

Index: jitruby/sample/fib.rb
===================================================================
RCS file: jitruby/sample/fib.rb
diff -N jitruby/sample/fib.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/sample/fib.rb       12 Dec 2008 11:31:04 -0000      1.1
@@ -0,0 +1,29 @@
+require 'jit'
+
+fib = nil
+signature = JIT::Type.create_signature(
+    :CDECL,
+    :INT,
+    [ :INT ])
+fib = JIT::Function.build(signature) do |f|
+  n = f.param(0)
+
+  a = f.value(:INT, 0)
+  b = f.value(:INT, 1)
+  c = f.value(:INT, 1)
+
+  i = f.value(:INT, 0)
+
+  f.while{ i < n }.do {
+    c.store(a + b)
+    a.store(b)
+    b.store(c)
+    i.store(i + 1)
+  }.end
+
+  f.return(c)
+end
+
+values = (0...10).collect { |x| fib.apply(x) }
+p values #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
+

Index: jitruby/sample/gcd_benchmark.rb
===================================================================
RCS file: jitruby/sample/gcd_benchmark.rb
diff -N jitruby/sample/gcd_benchmark.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/sample/gcd_benchmark.rb     12 Dec 2008 11:31:04 -0000      1.1
@@ -0,0 +1,117 @@
+require 'jit'
+require 'benchmark'
+
+# GCD, JIT-compiled
+
+jit_gcd = nil
+
+JIT::Context.build do |context|
+  signature = JIT::Type.create_signature(
+      JIT::ABI::CDECL,
+      JIT::Type::INT,
+      [ JIT::Type::INT, JIT::Type::INT ])
+  jit_gcd = JIT::Function.compile(context, signature) do |f|
+    x = f.get_param(0)
+    y = f.get_param(1)
+    temp1 = f.insn_eq(x, y)
+    label1 = JIT::Label.new
+    f.insn_branch_if_not(temp1, label1)
+    f.insn_return(x)
+    f.insn_label(label1)
+    temp2 = f.insn_lt(x, y)
+    label2 = JIT::Label.new
+    f.insn_branch_if_not(temp2, label2)
+    s1 = f.insn_sub(y, x)
+    temp3 = f.insn_call("gcd", f, 0, x, s1)
+    f.insn_return(temp3)
+    f.insn_label(label2)
+    s2 = f.insn_sub(x, y)
+    temp4 = f.insn_call("gcd", f, 0, s2, y)
+    f.insn_return(temp4)
+
+    f.optimization_level = 3
+  end
+end
+
+if jit_gcd.apply(28, 21) != 7 then
+  puts "jit_gcd is broken"
+  exit 1
+end
+
+
+# GCD with tail recursion optimization
+
+jit_gcd_tail = nil
+
+JIT::Context.build do |context|
+  signature = JIT::Type.create_signature(
+      JIT::ABI::CDECL,
+      JIT::Type::INT,
+      [ JIT::Type::INT, JIT::Type::INT ])
+  jit_gcd_tail = JIT::Function.compile(context, signature) do |f|
+    x = f.get_param(0)
+    y = f.get_param(1)
+    temp1 = f.insn_eq(x, y)
+    label1 = JIT::Label.new
+    f.insn_branch_if_not(temp1, label1)
+    f.insn_return(x)
+    f.insn_label(label1)
+    temp2 = f.insn_lt(x, y)
+    label2 = JIT::Label.new
+    f.insn_branch_if_not(temp2, label2)
+    s1 = f.insn_sub(y, x)
+    temp3 = f.insn_call("gcd", f, JIT::Call::TAIL, x, s1)
+    # f.insn_return(temp3)
+    f.insn_label(label2)
+    s2 = f.insn_sub(x, y)
+    temp4 = f.insn_call("gcd", f, JIT::Call::TAIL, s2, x)
+    # f.insn_return(temp4)
+
+    f.optimization_level = 3
+  end
+end
+
+if jit_gcd_tail.apply(28, 21) != 7 then
+  puts "jit_gcd_tail is broken"
+  exit 1
+end
+
+
+# GCD in ruby with recursion
+
+def gcd(x, y)
+  if x == y
+    return x
+  elsif x < y
+    return gcd(x, y - x)
+  else
+    return gcd(x - y, y)
+  end
+end
+
+
+# GCD in ruby without recursion
+
+def gcd2(x, y)
+  while x != y do
+    if x < y
+      y -= x
+    else
+      x -= y
+    end
+  end
+  return x
+end
+
+N = 1000
+
+X = 1000
+Y = 1005
+
+Benchmark.bm(16) do |x|
+  x.report("jit")            { N.times { jit_gcd.apply(X, Y) } }
+  x.report("jit tail:")      { N.times { jit_gcd_tail.apply(X, Y) } }
+  x.report("ruby recur:")    { N.times { gcd(X, Y) } }
+  x.report("ruby iter:")     { N.times { gcd2(X, Y) } }
+end
+

Index: jitruby/sample/simple.rb
===================================================================
RCS file: jitruby/sample/simple.rb
diff -N jitruby/sample/simple.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/sample/simple.rb    12 Dec 2008 11:31:04 -0000      1.1
@@ -0,0 +1,15 @@
+require 'jit'
+
+function = nil
+JIT::Context.build do |context|
+  signature = JIT::Type.create_signature(
+      JIT::ABI::CDECL,
+      JIT::Type::INT,       # returns an integer
+      [ JIT::Type::INT ])   # and tages an integer as a parameter
+  function = JIT::Function.compile(context, signature) do |f|
+    value = f.get_param(0)
+    f.insn_return(value)
+  end
+end
+
+p function.apply(42) #=> 42

Index: jitruby/test/assertions.rb
===================================================================
RCS file: jitruby/test/assertions.rb
diff -N jitruby/test/assertions.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/test/assertions.rb  12 Dec 2008 11:31:05 -0000      1.1
@@ -0,0 +1,34 @@
+module JitAssertions
+  def assert_function_result(args, &block)
+    result_type = nil
+    expected_result = nil
+    param_types = []
+    params = []
+
+    args.each do |k, v|
+      case k.to_s
+      when /^arg(\d+)$/
+        n = $1.to_i
+        param_types[n] = v[0]
+        params[n] = v[1]
+      when 'result'
+        result_type = v[0]
+        expected_result = v[1]
+      else
+        raise "Bad arg #{arg}"
+      end
+    end
+
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          result_type,
+          param_types)
+      function = JIT::Function.compile(context, signature, &block)
+    end
+
+    assert_equal(expected_result, function.apply(*params))
+  end
+end
+

Index: jitruby/test/test_jit_array.rb
===================================================================
RCS file: jitruby/test/test_jit_array.rb
diff -N jitruby/test/test_jit_array.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/test/test_jit_array.rb      12 Dec 2008 11:31:05 -0000      1.1
@@ -0,0 +1,70 @@
+require 'jit/array'
+require 'jit/function'
+require 'test/unit'
+require 'assertions'
+
+class TestJitArray < Test::Unit::TestCase
+  include JitAssertions
+
+  def test_new_array
+    a_type = JIT::Array.new(JIT::Type::INT, 12)
+    assert_equal JIT::Type::INT, a_type.type
+    assert_equal 12, a_type.length
+  end
+
+  # TODO: wrap
+
+  def test_create
+    p = proc { |f|
+      a_type = JIT::Array.new(JIT::Type::INT, 4)
+      a = a_type.create(f)
+      f.return f.const(JIT::Type::INT, 0)
+    }
+    assert_function_result(
+        :result => [ JIT::Type::INT, 0 ],
+        &p)
+  end
+
+  def test_offset_of
+    a_type = JIT::Array.new(JIT::Type::INT, 4)
+    assert_equal 0, a_type.offset_of(0)
+    assert_equal 4, a_type.offset_of(1)
+    assert_equal 8, a_type.offset_of(2)
+    assert_equal 12, a_type.offset_of(3)
+    # TODO: check out of bounds
+  end
+
+  def test_type_of
+    a_type = JIT::Array.new(JIT::Type::INT, 4)
+    assert_equal JIT::Type::INT, a_type.type_of(0)
+    assert_equal JIT::Type::INT, a_type.type_of(1)
+    assert_equal JIT::Type::INT, a_type.type_of(2)
+    assert_equal JIT::Type::INT, a_type.type_of(3)
+    # TODO: check out of bounds
+  end
+
+  def test_instance_bracket
+    p = proc { |f|
+      a_type = JIT::Array.new(JIT::Type::INT, 4)
+      a = a_type.create(f)
+      f.insn_store_relative(a.ptr, 4, f.const(JIT::Type::INT, 42))
+      f.return a[1]
+    }
+    assert_function_result(
+        :result => [ JIT::Type::INT, 42 ],
+        &p)
+  end
+
+  def test_instance_bracket_eq
+    p = proc { |f|
+      a_type = JIT::Array.new(JIT::Type::INT, 4)
+      a = a_type.create(f)
+      a[1] = f.const(JIT::Type::INT, 42)
+      f.return a[1]
+    }
+    assert_function_result(
+        :result => [ JIT::Type::INT, 42 ],
+        &p)
+  end
+end
+

Index: jitruby/test/test_jit_function.rb
===================================================================
RCS file: jitruby/test/test_jit_function.rb
diff -N jitruby/test/test_jit_function.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/test/test_jit_function.rb   12 Dec 2008 11:31:05 -0000      1.1
@@ -0,0 +1,329 @@
+require 'jit/function'
+require 'jit/value'
+require 'test/unit'
+
+class TestJitFunction < Test::Unit::TestCase
+  def test_if_false
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ JIT::Type::INT ])
+      function = JIT::Function.compile(context, signature) do |f|
+        result = f.value(JIT::Type::INT)
+        result.store f.const(JIT::Type::INT, 1)
+        f.if(f.get_param(0)) {
+          result.store f.const(JIT::Type::INT, 2)
+        } .end
+        f.insn_return result
+      end
+    end
+
+    assert_equal(1, function.apply(0))
+  end
+
+  def test_if_true
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ JIT::Type::INT ])
+      function = JIT::Function.compile(context, signature) do |f|
+        result = f.value(JIT::Type::INT)
+        result.store f.const(JIT::Type::INT, 1)
+        f.if(f.get_param(0)) {
+          result.store f.const(JIT::Type::INT, 2)
+        } .end
+        f.insn_return result
+      end
+    end
+
+    assert_equal(2, function.apply(1))
+  end
+
+  def test_if_false_else
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ JIT::Type::INT ])
+      function = JIT::Function.compile(context, signature) do |f|
+        result = f.value(JIT::Type::INT)
+        result.store f.const(JIT::Type::INT, 1)
+        f.if(f.get_param(0)) {
+          result.store f.const(JIT::Type::INT, 2)
+        } .else {
+          result.store f.const(JIT::Type::INT, 3)
+        } .end
+        f.insn_return result
+      end
+    end
+
+    assert_equal(3, function.apply(0))
+  end
+
+  def test_if_true_else
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ JIT::Type::INT ])
+      function = JIT::Function.compile(context, signature) do |f|
+        result = f.value(JIT::Type::INT)
+        result.store f.const(JIT::Type::INT, 1)
+        f.if(f.get_param(0)) {
+          result.store f.const(JIT::Type::INT, 2)
+        } .else {
+          result.store f.const(JIT::Type::INT, 3)
+        } .end
+        f.insn_return result
+      end
+    end
+
+    assert_equal(2, function.apply(1))
+  end
+
+  def test_if_false_else_if_true_else
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ JIT::Type::INT, JIT::Type::INT ])
+      function = JIT::Function.compile(context, signature) do |f|
+        result = f.value(JIT::Type::INT)
+        result.store f.const(JIT::Type::INT, 1)
+        f.if(f.get_param(0)) {
+          result.store f.const(JIT::Type::INT, 2)
+        } .elsif(f.get_param(1)) {
+          result.store f.const(JIT::Type::INT, 3)
+        } .else {
+          result.store f.const(JIT::Type::INT, 4)
+        } .end
+        f.insn_return result
+      end
+    end
+
+    assert_equal(3, function.apply(0, 1))
+  end
+
+  def test_if_true_else_if_false_else
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ JIT::Type::INT, JIT::Type::INT ])
+      function = JIT::Function.compile(context, signature) do |f|
+        result = f.value(JIT::Type::INT)
+        result.store f.const(JIT::Type::INT, 1)
+        f.if(f.get_param(0)) {
+          result.store f.const(JIT::Type::INT, 2)
+        } .elsif(f.get_param(1)) {
+          result.store f.const(JIT::Type::INT, 3)
+        } .else {
+          result.store f.const(JIT::Type::INT, 4)
+        } .end
+        f.insn_return result
+      end
+    end
+
+    assert_equal(2, function.apply(1, 0))
+  end
+
+  def test_if_false_else_if_false_else
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ JIT::Type::INT, JIT::Type::INT ])
+      function = JIT::Function.compile(context, signature) do |f|
+        result = f.value(JIT::Type::INT)
+        result.store f.const(JIT::Type::INT, 1)
+        f.if(f.get_param(0)) {
+          result.store f.const(JIT::Type::INT, 2)
+        } .elsif(f.get_param(1)) {
+          result.store f.const(JIT::Type::INT, 3)
+        } .else {
+          result.store f.const(JIT::Type::INT, 4)
+        } .end
+        f.insn_return result
+      end
+    end
+
+    assert_equal(4, function.apply(0, 0))
+  end
+
+  def test_while_true_enters_loop
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ ])
+      function = JIT::Function.compile(context, signature) do |f|
+        true_value = f.const(JIT::Type::INT, 1)
+        false_value = f.const(JIT::Type::INT, 0)
+        f.while{ true_value }.do {
+          f.insn_return true_value
+        }.end
+        f.insn_return false_value
+      end
+    end
+
+    assert_equal(1, function.apply)
+  end
+
+  def test_while_true_reenters_loop
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ ])
+      function = JIT::Function.compile(context, signature) do |f|
+        value = f.value(JIT::Type::INT)
+        value.store(f.const(JIT::Type::INT, 0))
+        f.while{ value < f.const(JIT::Type::INT, 2) }.do {
+          value.store(value + f.const(JIT::Type::INT, 1))
+        }.end
+        f.insn_return value
+      end
+    end
+
+    assert_equal(2, function.apply)
+  end
+
+  def test_while_false_does_not_enter_loop
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ ])
+      function = JIT::Function.compile(context, signature) do |f|
+        true_value = f.const(JIT::Type::INT, 1)
+        false_value = f.const(JIT::Type::INT, 0)
+        f.while{ false_value }.do {
+          f.insn_return true_value
+        }.end
+        f.insn_return false_value
+      end
+    end
+
+    assert_equal(0, function.apply)
+  end
+
+  def test_until_false_enters_loop
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ ])
+      function = JIT::Function.compile(context, signature) do |f|
+        true_value = f.const(JIT::Type::INT, 1)
+        false_value = f.const(JIT::Type::INT, 0)
+        f.until{ false_value }.do {
+          f.insn_return true_value
+        }.end
+        f.insn_return false_value
+      end
+    end
+
+    assert_equal(1, function.apply)
+  end
+
+  def test_until_false_reenters_loop
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ ])
+      function = JIT::Function.compile(context, signature) do |f|
+        value = f.value(JIT::Type::INT)
+        value.store(f.const(JIT::Type::INT, 0))
+        f.until{ value == f.const(JIT::Type::INT, 2) }.do {
+          value.store(value + f.const(JIT::Type::INT, 1))
+        }.end
+        f.insn_return value
+      end
+    end
+
+    assert_equal(2, function.apply)
+  end
+
+  def test_until_true_does_not_enter_loop
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::INT,
+          [ ])
+      function = JIT::Function.compile(context, signature) do |f|
+        true_value = f.const(JIT::Type::INT, 1)
+        false_value = f.const(JIT::Type::INT, 0)
+        f.until{ true_value }.do {
+          f.insn_return true_value
+        }.end
+        f.insn_return false_value
+      end
+    end
+
+      assert_equal(0, function.apply)
+  end
+
+  # TODO: while/break
+  # TODO: while/redo
+  # TODO: until/break
+  # TODO: until/redo
+  # TODO: unless
+  # TODO: elsunless
+
+  def test_define_jit_method
+    function = nil
+    JIT::Context.build do |context|
+      signature = JIT::Type.create_signature(
+          JIT::ABI::CDECL,
+          JIT::Type::OBJECT,
+          [ JIT::Type::OBJECT ])
+      function = JIT::Function.compile(context, signature) do |f|
+        f.insn_return(f.const(JIT::Type::OBJECT, 42))
+      end
+    end
+
+    c = Class.new
+    c.instance_eval do
+      define_jit_method('foo', function)
+    end
+
+    o = c.new
+    assert_equal 42, o.foo
+  end
+
+  def test_define_jit_method_non_object_param
+    # TODO: should raise an exception
+  end
+
+  # TODO: get_param
+  # TODO: insn_call
+  # TODO: insn_call_native
+  # TODO: insn_return
+  # TODO: apply
+  # TODO: value
+  # TODO: const
+  # TODO: optimization_level
+  # TODO: optimization_level=
+  # TODO: max_optimization_level
+  # TODO: dump
+  # TODO: to_closure
+  # TODO: context
+  # TODO: compiled?
+end
+

Index: jitruby/test/test_jit_pointer.rb
===================================================================
RCS file: jitruby/test/test_jit_pointer.rb
diff -N jitruby/test/test_jit_pointer.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/test/test_jit_pointer.rb    12 Dec 2008 11:31:05 -0000      1.1
@@ -0,0 +1,63 @@
+require 'jit/pointer'
+require 'jit/array'
+require 'jit/function'
+require 'test/unit'
+require 'assertions'
+
+class TestJitArray < Test::Unit::TestCase
+  include JitAssertions
+
+  def test_new_pointer
+    p_type = JIT::Pointer.new(JIT::Type::INT)
+    assert_equal JIT::Type::INT, p_type.type
+  end
+
+  # TODO: wrap
+
+  def test_offset_of
+    p_type = JIT::Pointer.new(JIT::Type::INT)
+    assert_equal 0, p_type.offset_of(0)
+    assert_equal 4, p_type.offset_of(1)
+    assert_equal 8, p_type.offset_of(2)
+    assert_equal 12, p_type.offset_of(3)
+    # TODO: check out of bounds
+  end
+
+  def test_type_of
+    p_type = JIT::Pointer.new(JIT::Type::INT)
+    assert_equal JIT::Type::INT, p_type.type_of(0)
+    assert_equal JIT::Type::INT, p_type.type_of(1)
+    assert_equal JIT::Type::INT, p_type.type_of(2)
+    assert_equal JIT::Type::INT, p_type.type_of(3)
+    # TODO: check out of bounds
+  end
+
+  def test_instance_bracket
+    p = proc { |f|
+      a_type = JIT::Array.new(JIT::Type::INT, 4)
+      p_type = JIT::Pointer.new(JIT::Type::INT)
+      a = a_type.create(f)
+      ptr = p_type.wrap(a.ptr)
+      f.insn_store_relative(a.ptr, 4, f.const(JIT::Type::INT, 42))
+      f.return ptr[1]
+    }
+    assert_function_result(
+        :result => [ JIT::Type::INT, 42 ],
+        &p)
+  end
+
+  def test_instance_bracket_eq
+    p = proc { |f|
+      a_type = JIT::Array.new(JIT::Type::INT, 4)
+      p_type = JIT::Pointer.new(JIT::Type::INT)
+      a = a_type.create(f)
+      ptr = p_type.wrap(a.ptr)
+      ptr[1] = f.const(JIT::Type::INT, 42)
+      f.return a[1]
+    }
+    assert_function_result(
+        :result => [ JIT::Type::INT, 42 ],
+        &p)
+  end
+end
+

Index: jitruby/test/test_jit_struct.rb
===================================================================
RCS file: jitruby/test/test_jit_struct.rb
diff -N jitruby/test/test_jit_struct.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/test/test_jit_struct.rb     12 Dec 2008 11:31:05 -0000      1.1
@@ -0,0 +1,111 @@
+require 'jit/array'
+require 'jit/function'
+require 'test/unit'
+require 'assertions'
+
+class TestJitStruct < Test::Unit::TestCase
+  include JitAssertions
+
+  def test_new_struct
+    s_type = JIT::Struct.new(
+        [ :foo, JIT::Type::INT ],
+        [ :bar, JIT::Type::VOID_PTR ],
+        [ :baz, JIT::Type::FLOAT32 ])
+    assert_equal [ :foo, :bar, :baz ], s_type.members
+  end
+
+  def test_create
+    p = proc { |f|
+      s_type = JIT::Struct.new(
+          [ :foo, JIT::Type::INT ],
+          [ :bar, JIT::Type::VOID_PTR ],
+          [ :baz, JIT::Type::FLOAT32 ])
+      s = s_type.create(f)
+      f.return f.const(JIT::Type::INT, 0)
+    }
+    assert_function_result(
+        :result => [ JIT::Type::INT, 0 ],
+        &p)
+  end
+
+  def test_offset_of
+    s_type = JIT::Struct.new(
+        [ :foo, JIT::Type::INT ],
+        [ :bar, JIT::Type::FLOAT64 ],
+        [ :baz, JIT::Type::VOID_PTR ])
+    assert_equal 0, s_type.offset_of(:foo)
+    assert_equal 4, s_type.offset_of(:bar)
+    assert_equal 12, s_type.offset_of(:baz)
+  end
+
+  def test_type_of
+    s_type = JIT::Struct.new(
+        [ :foo, JIT::Type::INT ],
+        [ :bar, JIT::Type::FLOAT64 ],
+        [ :baz, JIT::Type::VOID_PTR ])
+    assert_equal JIT::Type::INT, s_type.type_of(:foo)
+    assert_equal JIT::Type::FLOAT64, s_type.type_of(:bar)
+    assert_equal JIT::Type::VOID_PTR, s_type.type_of(:baz)
+  end
+
+  def test_instance_bracket
+    p = proc { |f|
+      s_type = JIT::Struct.new(
+          [ :foo, JIT::Type::INT ],
+          [ :bar, JIT::Type::FLOAT64 ],
+          [ :baz, JIT::Type::VOID_PTR ])
+      s = s_type.create(f)
+      f.insn_store_relative(s.ptr, 4, f.const(JIT::Type::FLOAT64, 42.0))
+      f.return s[:bar]
+    }
+    assert_function_result(
+        :result => [ JIT::Type::FLOAT64, 42.0 ],
+        &p)
+  end
+
+  def test_instance_attrget
+    p = proc { |f|
+      s_type = JIT::Struct.new(
+          [ :foo, JIT::Type::INT ],
+          [ :bar, JIT::Type::FLOAT64 ],
+          [ :baz, JIT::Type::VOID_PTR ])
+      s = s_type.create(f)
+      f.insn_store_relative(s.ptr, 4, f.const(JIT::Type::FLOAT64, 42.0))
+      f.return s.bar
+    }
+    assert_function_result(
+        :result => [ JIT::Type::FLOAT64, 42.0 ],
+        &p)
+  end
+
+  def test_instance_bracket_eq
+    p = proc { |f|
+      s_type = JIT::Struct.new(
+          [ :foo, JIT::Type::INT ],
+          [ :bar, JIT::Type::FLOAT64 ],
+          [ :baz, JIT::Type::VOID_PTR ])
+      s = s_type.create(f)
+      s[:bar] = f.const(JIT::Type::FLOAT64, 42.0)
+      f.return s[:bar]
+    }
+    assert_function_result(
+        :result => [ JIT::Type::FLOAT64, 42.0 ],
+        &p)
+  end
+
+  def test_instance_attrset
+    p = proc { |f|
+      s_type = JIT::Struct.new(
+          [ :foo, JIT::Type::INT ],
+          [ :bar, JIT::Type::FLOAT64 ],
+          [ :baz, JIT::Type::VOID_PTR ])
+      s = s_type.create(f)
+      s.bar = f.const(JIT::Type::FLOAT64, 42.0)
+      f.return s.bar
+    }
+    assert_function_result(
+        :result => [ JIT::Type::FLOAT64, 42.0 ],
+        &p)
+  end
+end
+

Index: jitruby/test/test_jit_value.rb
===================================================================
RCS file: jitruby/test/test_jit_value.rb
diff -N jitruby/test/test_jit_value.rb
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ jitruby/test/test_jit_value.rb      12 Dec 2008 11:31:05 -0000      1.1
@@ -0,0 +1,258 @@
+require 'jit/value'
+require 'jit/function'
+require 'test/unit'
+require 'assertions'
+
+class TestJitValue < Test::Unit::TestCase
+  include JitAssertions
+
+  def test_store
+    p = proc { |f|
+      v = f.value(JIT::Type::INT)
+      v.store(f.const(JIT::Type::INT, 42))
+      f.return v
+    }
+    assert_function_result(
+        :result => [ JIT::Type::INT, 42 ],
+        &p)
+  end
+
+  # TODO: address
+
+  def test_int_plus
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 + v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 1 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 3 ],
+        &p)
+  end
+
+  def test_int_minus
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 - v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 3 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 1 ],
+        &p)
+  end
+
+  def test_int_mult
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 * v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 3 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 6 ],
+        &p)
+  end
+
+  def test_int_div
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 / v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 6 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 3 ],
+        &p)
+  end
+
+  def test_int_mod
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 % v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 20 ],
+        :arg1 => [ JIT::Type::INT, 6 ],
+        :result => [ JIT::Type::INT, 2 ],
+        &p)
+  end
+
+  def test_int_and
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 & v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 11 ],
+        :arg1 => [ JIT::Type::INT, 3 ],
+        :result => [ JIT::Type::INT, 3 ],
+        &p)
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 8 ],
+        :arg1 => [ JIT::Type::INT, 3 ],
+        :result => [ JIT::Type::INT, 0 ],
+        &p)
+  end
+
+  def test_int_or
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 | v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 10 ],
+        :arg1 => [ JIT::Type::INT, 3 ],
+        :result => [ JIT::Type::INT, 11 ],
+        &p)
+  end
+
+  def test_int_xor
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 ^ v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 10 ],
+        :arg1 => [ JIT::Type::INT, 3 ],
+        :result => [ JIT::Type::INT, 9 ],
+        &p)
+  end
+
+  def test_int_lt
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 < v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 1 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 1 ],
+        &p)
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 2 ],
+        :arg1 => [ JIT::Type::INT, 1 ],
+        :result => [ JIT::Type::INT, 0 ],
+        &p)
+  end
+
+  def test_int_gt
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 > v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 1 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 0 ],
+        &p)
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 2 ],
+        :arg1 => [ JIT::Type::INT, 1 ],
+        :result => [ JIT::Type::INT, 1 ],
+        &p)
+  end
+
+  def test_int_eq
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 == v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 1 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 0 ],
+        &p)
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 1 ],
+        :arg1 => [ JIT::Type::INT, 1 ],
+        :result => [ JIT::Type::INT, 1 ],
+        &p)
+  end
+
+  def test_int_le
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 <= v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 1 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 1 ],
+        &p)
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 2 ],
+        :arg1 => [ JIT::Type::INT, 1 ],
+        :result => [ JIT::Type::INT, 0 ],
+        &p)
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 1 ],
+        :arg1 => [ JIT::Type::INT, 1 ],
+        :result => [ JIT::Type::INT, 1 ],
+        &p)
+  end
+
+  def test_int_ge
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 >= v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 1 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 0 ],
+        &p)
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 2 ],
+        :arg1 => [ JIT::Type::INT, 1 ],
+        :result => [ JIT::Type::INT, 1 ],
+        &p)
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 1 ],
+        :arg1 => [ JIT::Type::INT, 1 ],
+        :result => [ JIT::Type::INT, 1 ],
+        &p)
+  end
+
+  def test_int_lshift
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 << v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 31 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 124 ],
+        &p)
+  end
+
+  def test_int_rshift
+    p = proc { |f|
+      v1 = f.get_param(0)
+      v2 = f.get_param(1)
+      f.return v1 >> v2
+    }
+    assert_function_result(
+        :arg0 => [ JIT::Type::INT, 31 ],
+        :arg1 => [ JIT::Type::INT, 2 ],
+        :result => [ JIT::Type::INT, 7 ],
+        &p)
+  end
+end
+
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]