I've started to play with a proof-of-concept branch that uses Rubinius's kernel (core class implementations) in replacement for our own. Initially I've started playing with Hash, which is one of the few Rubinius core classes that does not have any "primitives".

The challenge to make it work was mostly in adding a few utilities it needed (using Array for "Tuple", setting the top "self" to "MAIN", loading a Type module for coercions, etc) and getting the intialization paths to use the pure-Ruby Hash impl instead of our concrete Java impl. I was able to overcome all these and get Rubinius's hash to function in both compiled and interpreted modes, and run a few simple tests and benchmarks.

It is, as you would expect, dozens of times slower than our Java impl, but the performance is better than I expected once the various JIT layers kick in. I doubt it will be possible to get its performance to the same level as hand-written Java code. However, I don't think it would be hard to improve performance substantially by enabling some normally unsafe optimizations only for these pure-Ruby kernel classes.

At any rate, it can probably become a side project, since the goal of running the same pure Ruby kernel across many implementations is certainly attractive...even if our kernel is pretty much done already.

I will probably create an SVN branch later today and push my changes to it. For now I've attached the patch for the initial POC work.

Comments, suggestions are welcome :)

- Charlie
>From 281650894d8b8e04b651f61c072a2e1a2ec8e0ff Mon Sep 17 00:00:00 2001
From: Charles Nutter <[EMAIL PROTECTED]>
Date: Wed, 29 Oct 2008 03:08:14 -0500
Subject: [PATCH] Initial support for Rubinius kernel; Hash from Rubinius now 
loads and functions. Not 100% but looking good.

---
 lib/ruby/1.8/rubinius/kernel/bootstrap/hash.rb     |  211 +++++++++++
 lib/ruby/1.8/rubinius/kernel/common/hash.rb        |  366 ++++++++++++++++++++
 lib/ruby/1.8/rubinius/kernel/common/misc.rb        |   83 +++++
 src/org/jruby/Ruby.java                            |   26 ++
 src/org/jruby/RubyClass.java                       |    6 +-
 src/org/jruby/RubyHash.java                        |    3 +-
 src/org/jruby/RubyInstanceConfig.java              |   10 +-
 src/org/jruby/ast/HashNode.java                    |   39 ++-
 src/org/jruby/compiler/impl/BaseBodyCompiler.java  |   19 +-
 src/org/jruby/javasupport/util/RuntimeHelpers.java |    4 +
 src/org/jruby/runtime/ObjectAllocator.java         |    6 +
 11 files changed, 760 insertions(+), 13 deletions(-)
 create mode 100644 lib/ruby/1.8/rubinius/kernel/bootstrap/hash.rb
 create mode 100644 lib/ruby/1.8/rubinius/kernel/common/hash.rb
 create mode 100644 lib/ruby/1.8/rubinius/kernel/common/misc.rb

diff --git a/lib/ruby/1.8/rubinius/kernel/bootstrap/hash.rb 
b/lib/ruby/1.8/rubinius/kernel/bootstrap/hash.rb
new file mode 100644
index 0000000..a2358e8
--- /dev/null
+++ b/lib/ruby/1.8/rubinius/kernel/bootstrap/hash.rb
@@ -0,0 +1,211 @@
+# depends on: module.rb symbol.rb string.rb lookuptable.rb
+
+class Hash
+
+  # Bucket abstracts storage and search of entries in Hash.
+  # Each bin in a Hash is either +nil+, a single +Bucket+
+  # instance, or the head of a chain of +Bucket+ instances.
+  class Bucket
+    attr_accessor :key
+    attr_accessor :value
+    attr_accessor :key_hash
+    attr_accessor :next
+
+    def initialize(key=nil, value=nil, key_hash=nil, nxt=nil)
+      @key      = key
+      @value    = value
+      @key_hash = key_hash
+      @next     = nxt
+    end
+
+    # Searches this chain of buckets for one matching both +key+
+    # and +key_hash+. Returns +nil+ if there is no match. Calls
+    # <code>#eql?</code> on +key+.
+    def find(key, key_hash)
+      return self if self.key_hash == key_hash and key.eql? self.key
+      return unless nxt = self.next
+      nxt.find key, key_hash
+    end
+
+    # Either updates an existing bucket matching +key+ and +key_hash+
+    # or appends a new bucket containing +key+, +value+, +key_hash+
+    # to the chain. Returns +true+ if a new bucket was added, otherwise
+    # returns +false+.
+    def set(key, value, key_hash)
+      if self.key_hash == key_hash and key.eql? self.key
+        self.value = value
+        return false
+      elsif nxt = self.next
+        return nxt.set(key, value, key_hash)
+      else
+        bucket = Bucket.new key, value, key_hash
+        self.next = bucket
+        return true
+      end
+    end
+
+    # Returns +false+ if the bucket was found and deleted and the head
+    # of the chain is unchanged. Returns +nil+ if the head of the
+    # chain should be replaced with <code>head.next</code>. Returns
+    # +true+ if the bucket was not found.
+    def delete(key, key_hash, parent = nil)
+      if self.key_hash == key_hash and key.eql? self.key
+        return nil unless parent
+        parent.next = self.next
+        return false
+      elsif nxt = self.next
+        return nxt.delete(key, key_hash, self)
+      else
+        return true
+      end
+    end
+  end
+
+  # An external iterator that returns only bucket chains from the
+  # Hash storage, never nil bins. While somewhat following the API
+  # of Enumerator, it is named Iterator because it does not provide
+  # <code>#each</code> and should not conflict with +Enumerator+ in
+  # MRI 1.8.7+. Returned by <code>Hash#to_iter</code>.
+  class Iterator
+    def initialize(bins, records)
+      @bins = bins
+      @records = records
+      @index = -1
+    end
+
+    # Returns the next object or +nil+.
+    def next
+      while (@index += 1) < @records
+        bucket = @[EMAIL PROTECTED]
+        return bucket if bucket
+      end
+    end
+
+    # Returns the index of the last object returned by <code>#next</code>.
+    def index
+      @index
+    end
+
+    # Resets the index of the next object to be returned by
+    # <code>#next</code> to the beginning of the storage vector.
+    def reset
+      @index = -1
+    end
+  end
+
+  # MUST be a power of 2
+  MIN_SIZE = 16
+
+  # Ensure that key_hash is a Fixnum
+  MAX_HASH_VALUE = 0x1fffffff
+
+  # Allocate more storage when this full
+  MAX_DENSITY = 0.75
+
+  # Creates a fully-formed instance of Hash.
+  #--
+  # @size is the number of pairs, equivalent to <code>hsh.size</code>.
+  # @records is the number of entries in [EMAIL PROTECTED]
+  # @bins is the vector of storage for the bucket chains.
+  #++
+  def self.allocate
+    h = super()
+
+    h.__initialize__
+    h
+  end
+
+  # Sets the underlying data structures.
+  def __initialize__
+    # We don't need the nanny checking our symbols
+    set_instance_variable :@records, MIN_SIZE
+    set_instance_variable :@bins, Tuple.new(MIN_SIZE)
+    set_instance_variable :@size, 0
+  end
+
+  # Returns the storage vector for Hash. The object should provide
+  # an <code>#[]</code> for accessing and <code>#[]=</code> for setting.
+  def bins
+    @bins
+  end
+
+  # Returns the size of the storage vector ([EMAIL PROTECTED]).
+  def records
+    @records
+  end
+
+  def size
+    @size
+  end
+
+  def size=(size)
+    @size = size
+    redistribute false
+  end
+
+  # Returns an external iterator for the bins. See +Iterator+
+  def to_iter
+    Iterator.new @bins, @records
+  end
+
+  # Returns a hash for key constrained to always be a Fixnum.
+  def key_hash(key)
+    hash = key.hash
+    hash = hash % MAX_HASH_VALUE unless hash.kind_of? Fixnum
+    hash
+  end
+
+  # Returns a bucket for +key_hash+ from a bin. Creates a new
+  # bucket if there was no bucket at that bin. The bucket may be
+  # the head of a chain. Call <code>#find</code> to locate a value
+  # or <code>#set</code> to add or update a value. Those methods
+  # handle manipulating the bucket chain.
+  def entry(key, key_hash)
+    bin = entry_bin key_hash
+    entry = @bins[bin]
+    return entry if entry
+
+    self.size += 1
+
+    # recalc the bin since #size may have invoked redistribute
+    @bins[entry_bin(key_hash)] = Bucket.new key, nil, key_hash
+  end
+
+  # Returns the index into the storage for +key_hash+.
+  def entry_bin(key_hash)
+    key_hash & (@records - 1)
+  end
+
+  # Grows the hash storage and redistributes the entries among
+  # the new bins if the entry density is above a threshold. Any
+  # Iterator instance will be invalid after a call to redistribute.
+  # If +rehash+ is true, recalculate the key_hash for each key.
+  def redistribute(rehash = true)
+    resize = @size >= MAX_DENSITY * @records
+    return unless rehash or resize
+
+    i = to_iter
+    @records *= 2 if resize
+    @bins = Tuple.new @records
+
+    while entry = i.next
+      while entry
+        nxt = entry.next
+
+        entry.key_hash = key_hash entry.key if rehash
+
+        bin = entry_bin entry.key_hash
+        if head = @bins[bin]
+          entry.next = head
+        else
+          entry.next = nil
+        end
+        @bins[bin] = entry
+
+        entry = nxt
+      end
+    end
+
+    self
+  end
+end
diff --git a/lib/ruby/1.8/rubinius/kernel/common/hash.rb 
b/lib/ruby/1.8/rubinius/kernel/common/hash.rb
new file mode 100644
index 0000000..ce5b0ca
--- /dev/null
+++ b/lib/ruby/1.8/rubinius/kernel/common/hash.rb
@@ -0,0 +1,366 @@
+# depends on: enumerable.rb misc.rb class.rb
+
+class Hash
+
+  include Enumerable
+
+  def self.[](*args)
+    if args.size == 1
+      obj = args.first
+      if obj.kind_of? Hash
+        return new.replace(obj)
+      elsif obj.respond_to? :to_hash
+        return new.replace(Type.coerce_to(obj, Hash, :to_hash))
+      end
+    end
+
+    if args.size & 1 == 1
+      raise ArgumentError, "Expected an even number, got #{args.length}"
+    end
+
+    hsh = new
+    i = 0
+    while i < args.size
+      hsh[args[i]] = args[i+1]
+      i += 2
+    end
+    hsh
+  end
+
+  def initialize(default = Undefined, &block)
+    if !default.equal?(Undefined) and block
+      raise ArgumentError, "Specify a default or a block, not both"
+    end
+
+    if block
+      @default = block
+      @default_proc = true
+    elsif !default.equal?(Undefined)
+      @default = default
+      @default_proc = false
+    end
+  end
+  private :initialize
+
+  def initialize_copy(other)
+    replace other
+  end
+  private :initialize_copy
+
+  def ==(other)
+    return true if self.equal? other
+    return false unless other.is_a? Hash or other.respond_to? :to_hash
+
+    other = Type.coerce_to other, Hash, :to_hash
+    return false unless other.size == size
+
+    # Pickaxe claims that defaults are compared, but MRI 1.8.[46] doesn't 
actually do that
+    # return false unless other.default == default
+    each { |k, v| return false unless other[k] == v }
+    true
+  end
+
+  def fetch(key, default = Undefined)
+    hsh = key_hash key
+    bin = entry_bin hsh
+
+    if entry = bins[bin]
+      result = entry.find key, hsh
+      return result.value if result
+    end
+
+    return yield(key) if block_given?
+    return default unless default.equal?(Undefined)
+    raise IndexError, 'key not found'
+  end
+
+  def [](key)
+    hsh = key_hash key
+    bin = entry_bin hsh
+
+    if entry = bins[bin]
+      result = entry.find key, hsh
+      return result.value if result
+    end
+
+    default key
+  end
+
+  def []=(key, value)
+    key = key.dup if key.kind_of? String
+
+    hsh = key_hash key
+    entry = self.entry key, hsh
+    self.size += 1 if entry.set(key, value, hsh)
+
+    value
+  end
+
+  alias_method :store, :[]=
+
+  def clear
+    __initialize__
+    self
+  end
+
+  def clone
+    hash = dup
+    hash.freeze if frozen?
+    hash
+  end
+
+  def default(key = Undefined)
+    # current MRI documentation comment is wrong.  Actual behavior is:
+    # Hash.new { 1 }.default # => nil
+    if @default_proc
+      key.equal?(Undefined) ? nil : @default.call(self, key)
+    else
+      @default
+    end
+  end
+
+  def default=(value)
+    @default_proc = false
+    @default = value
+  end
+
+  def default_proc
+    @default if @default_proc
+  end
+
+  def delete(key)
+    hsh = key_hash key
+    bin = entry_bin hsh
+
+    if entry = bins[bin]
+      result = entry.delete key, hsh
+      bins[bin] = entry.next if result.nil?
+      unless result
+        self.size -= 1
+        return entry.value
+      end
+    end
+
+    return yield(key) if block_given?
+  end
+
+  def delete_if(&block)
+    raise LocalJumpError, "no block given" unless block_given? or empty?
+
+    select(&block).each { |k, v| delete k }
+
+    self
+  end
+
+  def dup
+    hash = self.class.new
+    hash.send :initialize_copy, self
+    hash.taint if self.tainted?
+    hash
+  end
+
+  def each_key
+    raise LocalJumpError, "no block given" unless block_given? or empty?
+
+    each { |k, v| yield k }
+
+    self
+  end
+
+  def each
+    raise LocalJumpError, "no block given" unless block_given? or empty?
+
+    i = to_iter
+    while entry = i.next
+      begin
+        yield [entry.key, entry.value]
+      end while entry = entry.next
+    end
+
+    self
+  end
+
+  def each_pair
+    raise LocalJumpError, "no block given" unless block_given? or empty?
+
+    i = to_iter
+    while entry = i.next
+      begin
+        yield entry.key, entry.value
+      end while entry = entry.next
+    end
+
+    self
+  end
+
+  def each_value
+    raise LocalJumpError, "no block given" unless block_given? or empty?
+
+    each { |k, v| yield v }
+
+    self
+  end
+
+  def empty?
+    size == 0
+  end
+
+  def index(value)
+    each { |k, v| return k if v == value }
+    nil
+  end
+
+  def inspect
+    # recursively_inspect
+    return '{...}' if RecursionGuard.inspecting?(self)
+
+    out = []
+    RecursionGuard.inspect(self) do
+      each do |key, value|
+        str =  key.inspect
+        str << '=>'
+        str << value.inspect
+        out << str
+      end
+    end
+
+    "{#{out.join ', '}}"
+  end
+
+  def invert
+    inverted = {}
+    each { |key, value| inverted[value] = key }
+    inverted
+  end
+
+  def key?(key)
+    i = to_iter
+    while entry = i.next
+      begin
+        return true if entry.key_hash == key.hash and entry.key.eql? key
+      end while entry = entry.next
+    end
+    false
+  end
+
+  alias_method :has_key?, :key?
+  alias_method :include?, :key?
+  alias_method :member?, :key?
+
+  def keys
+    map { |key, value| key }
+  end
+
+  def merge(other, &block)
+    dup.merge!(other, &block)
+  end
+
+  def merge!(other)
+    other = Type.coerce_to other, Hash, :to_hash
+    other.each do |k, v|
+      if block_given? and key? k
+        self[k] = yield k, self[k], v
+      else
+        self[k] = v
+      end
+    end
+    self
+  end
+  alias_method :update, :merge!
+
+  alias_method :rehash, :redistribute
+
+  def reject(&block)
+    hsh = dup
+    hsh.reject! &block
+    hsh
+  end
+
+  def reject!
+    raise LocalJumpError, "no block given" unless block_given? or empty?
+
+    rejected = select { |k, v| yield k, v }
+    return if rejected.empty?
+
+    rejected.each { |k, v| delete k }
+    self
+  end
+
+  def replace(other)
+    other = Type.coerce_to other, Hash, :to_hash
+    return self if self.equal? other
+
+    clear
+    other.each { |k, v| self[k] = v }
+
+    if other.default_proc
+      @default = other.default_proc
+      @default_proc = true
+    else
+      @default = other.default
+      @default_proc = false
+    end
+
+    self
+  end
+
+  def select
+    raise LocalJumpError, "no block given" unless block_given? or empty?
+
+    selected = []
+    i = to_iter
+    while e = i.next
+      begin
+        selected << [e.key, e.value] if yield(e.key, e.value)
+      end while e = e.next
+    end
+
+    selected
+  end
+
+  def shift
+    return default(nil) if empty?
+
+    i = to_iter
+    if entry = i.next
+      bins[i.index] = entry.next
+      self.size -= 1
+      return entry.key, entry.value
+    end
+  end
+
+  alias_method :length, :size
+
+  def sort(&block)
+    to_a.sort(&block)
+  end
+
+  def to_a
+    select { true }
+  end
+
+  def to_hash
+    self
+  end
+
+  def to_s
+    to_a.join
+  end
+
+  def value?(value)
+    each { |k, v| return true if v == value }
+    false
+  end
+  alias_method :has_value?, :value?
+
+  def values
+    map { |key, value| value }
+  end
+
+  def values_at(*args)
+    args.collect { |key| self[key] }
+  end
+  alias_method :indexes, :values_at
+  alias_method :indices, :values_at
+
+end
diff --git a/lib/ruby/1.8/rubinius/kernel/common/misc.rb 
b/lib/ruby/1.8/rubinius/kernel/common/misc.rb
new file mode 100644
index 0000000..e736855
--- /dev/null
+++ b/lib/ruby/1.8/rubinius/kernel/common/misc.rb
@@ -0,0 +1,83 @@
+# depends on: module.rb class.rb
+
+class << MAIN
+  def include(*mods)
+    Object.include(*mods)
+  end
+
+  def public(*methods)
+    Object.public(*methods)
+  end
+
+  def private(*methods)
+    Object.private(*methods)
+  end
+
+  def protected(*methods)
+    Object.protected(*methods)
+  end
+
+  def add_method(name, obj)
+    Object.add_method(name, obj)
+  end
+
+  def alias_method(new_name, current_name)
+    Object.__send__ :alias_method, new_name, current_name
+  end
+
+  def __const_set__(name, obj)
+    Object.__const_set__(name, obj)
+  end
+end
+
+def self.to_s
+  "main"
+end
+
+class NilClass
+  alias_method :|, :^
+
+  def call(*a)
+    raise LocalJumpError, "not callable"
+  end
+end
+
+NIL = nil
+
+class TrueClass
+  alias_method :inspect, :to_s
+end
+
+TRUE = true
+
+class FalseClass
+  alias_method :|, :^
+  alias_method :inspect, :to_s
+end
+
+FALSE = false
+
+Undefined = Object.new
+
+
+##
+# This is used to prevent recursively traversing an object graph.
+
+module RecursionGuard
+  def self.inspecting?(obj)
+    stack.include?(obj.object_id)
+  end
+
+  def self.inspect(obj, &block)
+    stack.push(obj.object_id)
+    begin
+      yield
+    ensure
+      stack.pop
+    end
+  end
+
+  def self.stack
+    stack = Thread.current[:inspecting] ||= []
+  end
+end
diff --git a/src/org/jruby/Ruby.java b/src/org/jruby/Ruby.java
index 2291dc3..205121a 100644
--- a/src/org/jruby/Ruby.java
+++ b/src/org/jruby/Ruby.java
@@ -939,6 +939,32 @@ public final class Ruby {
 
         // initialize builtin libraries
         initBuiltins();
+
+        // If loading Rubinius kernel, load it now
+        if (config.isRubiniusKernelEnabled()) {
+            // pull in the Type module
+            loadService.require("jruby/type");
+
+            // preparations for bootstrapping
+            objectClass.defineAlias("set_instance_variable", 
"instance_variable_set");
+            objectClass.defineConstant("Tuple", arrayClass);
+            objectClass.deleteConstant("Hash");
+            objectClass.deleteConstant("NIL");
+            objectClass.deleteConstant("TRUE");
+            objectClass.deleteConstant("FALSE");
+
+            // bootstrap
+            objectClass.defineConstant("MAIN", topSelf);
+            loadService.require("rubinius/kernel/bootstrap/hash.rb");
+
+            // common
+            loadService.require("rubinius/kernel/common/misc.rb");
+            loadService.require("rubinius/kernel/common/hash.rb");
+
+            // re-init class references and set up Rubinius allocators
+            hashClass = getClass("Hash");
+            hashClass.setAllocator(ObjectAllocator.RUBINIUS_ALLOCATOR);
+        }
         
         // Require in all libraries specified on command line
         for (String scriptName : config.requiredLibraries()) {
diff --git a/src/org/jruby/RubyClass.java b/src/org/jruby/RubyClass.java
index e10842e..567bb09 100644
--- a/src/org/jruby/RubyClass.java
+++ b/src/org/jruby/RubyClass.java
@@ -114,7 +114,6 @@ public class RubyClass extends RubyModule {
         this.allocator = allocator;
     }
 
-    @JRubyMethod(name = "allocate")
     public IRubyObject allocate() {
         if (superClass == null) throw runtime.newTypeError("can't instantiate 
uninitialized class");
         IRubyObject obj = allocator.allocate(runtime, this);
@@ -122,6 +121,11 @@ public class RubyClass extends RubyModule {
         return obj;
     }
 
+    @JRubyMethod(name = "allocate")
+    public IRubyObject rbAllocate() {
+        return new RubyObject(runtime, this);
+    }
+
     public CallSite[] getBaseCallSites() {
         return baseCallSites;
     }
diff --git a/src/org/jruby/RubyHash.java b/src/org/jruby/RubyHash.java
index 8cc04c5..1add4ba 100644
--- a/src/org/jruby/RubyHash.java
+++ b/src/org/jruby/RubyHash.java
@@ -43,6 +43,7 @@ import static org.jruby.RubyEnumerator.enumeratorize;
 import java.io.IOException;
 import java.util.AbstractCollection;
 import java.util.AbstractSet;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.Map;
@@ -173,7 +174,7 @@ public class RubyHash extends RubyObject implements Map {
      */
     public static final RubyHash newHash(Ruby runtime, Map valueMap, 
IRubyObject defaultValue) {
         assert defaultValue != null;
-
+        
         return new RubyHash(runtime, valueMap, defaultValue);
     }
 
diff --git a/src/org/jruby/RubyInstanceConfig.java 
b/src/org/jruby/RubyInstanceConfig.java
index 710d2de..410fcf0 100644
--- a/src/org/jruby/RubyInstanceConfig.java
+++ b/src/org/jruby/RubyInstanceConfig.java
@@ -168,6 +168,7 @@ public class RubyInstanceConfig {
     private boolean shouldCheckSyntax = false;
     private String inputFieldSeparator = null;
     private boolean managementEnabled = true;
+    public static boolean rubiniusKernelEnabled = false;
 
     private int safeLevel = 0;
 
@@ -399,7 +400,8 @@ public class RubyInstanceConfig {
                 .append("  +C              force compilation of all scripts 
before they are run (except eval)\n")
                 .append("  -y              read a YARV-compiled Ruby script 
and run that (EXPERIMENTAL)\n")
                 .append("  -Y              compile a Ruby script into YARV 
bytecodes and run this (EXPERIMENTAL)\n")
-                .append("  -R              read a Rubinius-compiled Ruby 
script and run that (EXPERIMENTAL)\n");
+                .append("  -R              read a Rubinius-compiled Ruby 
script and run that (EXPERIMENTAL)\n")
+                .append("  -Rk             use the Rubinius implementations of 
core classes (Rubinius kernel)");
 
         return sb.toString();
     }
@@ -910,6 +912,8 @@ public class RubyInstanceConfig {
                         yarvCompile = true;
                     } else if (extendedOption.equals("-R")) {
                         rubinius = true;
+                    } else if (extendedOption.equals("-Rk")) {
+                        rubiniusKernelEnabled = true;
                     } else {
                         MainExitException mee =
                                 new MainExitException(1, "jruby: invalid 
extended option " + extendedOption + " (-X will list valid options)\n");
@@ -1179,6 +1183,10 @@ public class RubyInstanceConfig {
         return rubinius;
     }
 
+    public boolean isRubiniusKernelEnabled() {
+        return rubiniusKernelEnabled;
+    }
+
     public boolean isYARVCompileEnabled() {
         return yarvCompile;
     }
diff --git a/src/org/jruby/ast/HashNode.java b/src/org/jruby/ast/HashNode.java
index f15a6d3..eb2a2a4 100644
--- a/src/org/jruby/ast/HashNode.java
+++ b/src/org/jruby/ast/HashNode.java
@@ -76,22 +76,45 @@ public class HashNode extends Node {
     
     @Override
     public IRubyObject interpret(Ruby runtime, ThreadContext context, 
IRubyObject self, Block aBlock) {
-        RubyHash hash = RubyHash.newHash(runtime);
-        
+        if (runtime.getInstanceConfig().isRubiniusKernelEnabled()) {
+            return rbxInterpret(runtime, context, self, aBlock);
+        } else {
+            RubyHash hash = RubyHash.newHash(runtime);
+
+            ListNode listNode = this.listNode;
+            if (listNode != null) {
+                int size = listNode.size();
+
+                for (int i = 0; i < size;) {
+                    // insert all nodes in sequence, hash them in the final 
instruction
+                    // KEY
+                    IRubyObject key = listNode.get(i++).interpret(runtime, 
context, self, aBlock);
+                    IRubyObject value = listNode.get(i++).interpret(runtime, 
context, self, aBlock);
+
+                    hash.fastASet(key, value);
+                }
+            }
+
+            return hash;
+        }
+    }
+
+    public IRubyObject rbxInterpret(Ruby runtime, ThreadContext context, 
IRubyObject self, Block aBlock) {
         ListNode listNode = this.listNode;
+        IRubyObject hash = runtime.getHash().newInstance(context, 
IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
+        
         if (listNode != null) {
             int size = listNode.size();
-   
+
             for (int i = 0; i < size;) {
                 // insert all nodes in sequence, hash them in the final 
instruction
                 // KEY
-                IRubyObject key = listNode.get(i++).interpret(runtime, 
context, self, aBlock);
-                IRubyObject value = listNode.get(i++).interpret(runtime, 
context, self, aBlock);
-   
-                hash.fastASet(key, value);
+                hash.getMetaClass().finvoke(context, hash, "[]=",
+                    listNode.get(i++).interpret(runtime, context, self, 
aBlock),
+                    listNode.get(i++).interpret(runtime, context, self, 
aBlock));
             }
         }
-      
+        
         return hash;
     }
 }
diff --git a/src/org/jruby/compiler/impl/BaseBodyCompiler.java 
b/src/org/jruby/compiler/impl/BaseBodyCompiler.java
index 3ac2d83..24ff91f 100644
--- a/src/org/jruby/compiler/impl/BaseBodyCompiler.java
+++ b/src/org/jruby/compiler/impl/BaseBodyCompiler.java
@@ -481,9 +481,22 @@ public abstract class BaseBodyCompiler implements 
BodyCompiler {
     }
 
     public void createNewHash(Object elements, ArrayCallback callback, int 
keyCount) {
-        loadRuntime();
+        if (RubyInstanceConfig.rubiniusKernelEnabled) {
+            loadThreadContext();
+            invokeUtilityMethod("constructRubiniusHash", 
sig(IRubyObject.class, ThreadContext.class));
 
-        if (keyCount <= RuntimeHelpers.MAX_SPECIFIC_ARITY_HASH) {
+            for (int i = 0; i < keyCount; i++) {
+                method.dup();
+                loadThreadContext();
+                method.swap();
+                method.ldc("[]=");
+                callback.nextValue(this, elements, i);
+                invokeUtilityMethod("invoke", sig(IRubyObject.class, 
ThreadContext.class, IRubyObject.class, String.class, IRubyObject.class, 
IRubyObject.class));
+                method.pop();
+            }
+        } else if (keyCount <= RuntimeHelpers.MAX_SPECIFIC_ARITY_HASH) {
+            loadRuntime();
+            
             // we have a specific-arity method we can use to construct, so use 
that
             for (int i = 0; i < keyCount; i++) {
                 callback.nextValue(this, elements, i);
@@ -491,6 +504,8 @@ public abstract class BaseBodyCompiler implements 
BodyCompiler {
 
             invokeUtilityMethod("constructHash", sig(RubyHash.class, 
params(Ruby.class, IRubyObject.class, keyCount * 2)));
         } else {
+            loadRuntime();
+            
             method.invokestatic(p(RubyHash.class), "newHash", 
sig(RubyHash.class, params(Ruby.class)));
 
             for (int i = 0; i < keyCount; i++) {
diff --git a/src/org/jruby/javasupport/util/RuntimeHelpers.java 
b/src/org/jruby/javasupport/util/RuntimeHelpers.java
index 8039e75..20ccf32 100644
--- a/src/org/jruby/javasupport/util/RuntimeHelpers.java
+++ b/src/org/jruby/javasupport/util/RuntimeHelpers.java
@@ -908,6 +908,10 @@ public class RuntimeHelpers {
     public static String[] constructStringArray(String one, String two, String 
three, String four, String five, String six, String seven, String eight, String 
nine, String ten) {
         return new String[] {one, two, three, four, five, six, seven, eight, 
nine, ten};
     }
+
+    public static IRubyObject constructRubiniusHash(ThreadContext context) {
+        return context.getRuntime().getHash().newInstance(context, 
IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
+    }
     
     public static final int MAX_SPECIFIC_ARITY_HASH = 3;
     
diff --git a/src/org/jruby/runtime/ObjectAllocator.java 
b/src/org/jruby/runtime/ObjectAllocator.java
index 5f42532..8ff4c3a 100644
--- a/src/org/jruby/runtime/ObjectAllocator.java
+++ b/src/org/jruby/runtime/ObjectAllocator.java
@@ -25,4 +25,10 @@ public interface ObjectAllocator {
             throw runtime.newTypeError("allocator undefined for " + 
klass.getName());
         }
     };
+
+    public static final ObjectAllocator RUBINIUS_ALLOCATOR = new 
ObjectAllocator() {
+        public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
+            return klazz.getMetaClass().finvoke(runtime.getCurrentContext(), 
klazz, "allocate");
+        }
+    };
 }
-- 
1.6.0.2


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email

Reply via email to