[macruby-changes] [3315] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Jan 20 15:49:12 PST 2010


Revision: 3315
          http://trac.macosforge.org/projects/ruby/changeset/3315
Author:   lsansonetti at apple.com
Date:     2010-01-20 15:49:09 -0800 (Wed, 20 Jan 2010)
Log Message:
-----------
introduce RubyHash, fix a lot of minor bugs, start cleaning process

Modified Paths:
--------------
    MacRuby/trunk/array.c
    MacRuby/trunk/bin/rubyd
    MacRuby/trunk/class.c
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/dispatcher.cpp
    MacRuby/trunk/error.c
    MacRuby/trunk/hash.c
    MacRuby/trunk/include/ruby/intern.h
    MacRuby/trunk/include/ruby/ruby.h
    MacRuby/trunk/objc.m
    MacRuby/trunk/object.c
    MacRuby/trunk/re.c
    MacRuby/trunk/spec/frozen/tags/macruby/core/marshal/load_tags.txt
    MacRuby/trunk/st.c
    MacRuby/trunk/string.c
    MacRuby/trunk/struct.c
    MacRuby/trunk/time.c
    MacRuby/trunk/vm.cpp

Modified: MacRuby/trunk/array.c
===================================================================
--- MacRuby/trunk/array.c	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/array.c	2010-01-20 23:49:09 UTC (rev 3315)
@@ -234,9 +234,32 @@
     return NOT_FOUND;
 }
 
-#define IS_RARY(x) (*(VALUE *)x == rb_cRubyArray)
+//#define IS_RARY(x) (*(VALUE *)x == rb_cRubyArray)
+// XXX temporary
+#define IS_RARY(x) __is_rary(*(VALUE *)x)
 #define RARY(x) ((rb_ary_t *)x)
 
+static force_inline bool
+__is_rary(VALUE k)
+{
+    while (k != 0) {
+	if (k == rb_cRubyArray) {
+	    return true;
+	}
+	if (k == rb_cCFArray) {
+	    return false;
+	}
+	k = RCLASS_SUPER(k);
+    }
+    return false;
+}
+
+bool
+rb_klass_is_rary(VALUE klass)
+{
+    return __is_rary(klass);
+}
+
 void
 rb_mem_clear(register VALUE *mem, register long size)
 {
@@ -253,11 +276,7 @@
 	mask = RBASIC(ary)->flags;
     }
     else {
-#ifdef __LP64__
-	mask = RCLASS_RC_FLAGS(ary);
-#else
 	mask = rb_objc_flag_get_mask((void *)ary);
-#endif
 	if (RARRAY_IMMUTABLE(ary)) {
 	    mask |= FL_FREEZE;
 	}

Modified: MacRuby/trunk/bin/rubyd
===================================================================
--- MacRuby/trunk/bin/rubyd	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/bin/rubyd	2010-01-20 23:49:09 UTC (rev 3315)
@@ -15,7 +15,8 @@
     raise "need at least one argument" if args.empty?
     path = internal ? './miniruby' : File.join(RbConfig::CONFIG['bindir'],
       RbConfig::CONFIG['RUBY_INSTALL_NAME'])
-    @connector = ::MacRubyDebuggerConnector.alloc.initWithInterpreterPath(path,       arguments: args)
+    @connector = ::MacRubyDebuggerConnector.alloc.initWithInterpreterPath(path,
+      arguments: args)
   end
 
   def run

Modified: MacRuby/trunk/class.c
===================================================================
--- MacRuby/trunk/class.c	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/class.c	2010-01-20 23:49:09 UTC (rev 3315)
@@ -28,7 +28,7 @@
 bool
 rb_objc_install_primitives(Class ocklass, Class ocsuper)
 {
-    if (rb_cArray != 0 && rb_cHash != 0 && rb_cString != 0) {
+    if (rb_cRubyArray != 0 && rb_cRubyHash != 0 && rb_cString != 0) {
 	do {
 	    if (ocsuper == (Class)rb_cRubyArray) {
 		RCLASS_SET_VERSION_FLAG(ocklass, RCLASS_IS_ARRAY_SUBCLASS);
@@ -39,6 +39,10 @@
 		RCLASS_SET_VERSION_FLAG(ocklass, RCLASS_IS_ARRAY_SUBCLASS);
 		return true;
 	    }
+	    if (ocsuper == (Class)rb_cRubyHash) {
+		RCLASS_SET_VERSION_FLAG(ocklass, RCLASS_IS_HASH_SUBCLASS);
+		return false;
+	    }
 	    if (ocsuper == (Class)rb_cHash) {
 		rb_objc_install_hash_primitives(ocklass);
 		RCLASS_SET_VERSION_FLAG(ocklass, RCLASS_IS_HASH_SUBCLASS);
@@ -113,8 +117,6 @@
     return rcv;
 }
 
-VALUE rb_class_new_instance_imp(VALUE klass, SEL sel, int argc, VALUE *argv);
-
 void
 rb_define_object_special_methods(VALUE klass)
 {

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/compiler.cpp	2010-01-20 23:49:09 UTC (rev 3315)
@@ -2846,6 +2846,7 @@
 Value *
 RoxorCompiler::compile_immutable_literal(VALUE val)
 {
+    GC_RETAIN(val);
     return ConstantInt::get(RubyObjTy, (long)val); 
 }
 
@@ -5230,7 +5231,7 @@
 		Value *val = compile_protected_call(yieldFunc, params);
 
 		if (getBrokenFunc == NULL) {
-		    // VALUE rb_vm_pop_broken_value(void)
+		    // VALUE rb_vm_get_broken_value(void)
 		    getBrokenFunc = cast<Function>(module->getOrInsertFunction(
 				"rb_vm_get_broken_value",
 				RubyObjTy, NULL));

Modified: MacRuby/trunk/dispatcher.cpp
===================================================================
--- MacRuby/trunk/dispatcher.cpp	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/dispatcher.cpp	2010-01-20 23:49:09 UTC (rev 3315)
@@ -812,6 +812,9 @@
 	    if (self == rb_cNSMutableArray) {
 		self = rb_cRubyArray;
 	    }
+	    if (self == rb_cNSMutableHash) {
+		self = rb_cRubyHash;
+	    }
 	}
 	else if (sel == selClass) {
 	    // Because +[NSObject class] returns self.
@@ -840,7 +843,7 @@
 		return RARRAY_IMMUTABLE(self)
 		    ? rb_cNSArray : rb_cNSMutableArray;
 	    }
-	    else if (klass == (Class)rb_cRubyArray) {
+	    if (klass == (Class)rb_cRubyArray) {
 		return rb_cNSMutableArray;
 	    }
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
@@ -851,6 +854,9 @@
 		return RHASH_IMMUTABLE(self)
 		    ? rb_cNSHash : rb_cNSMutableHash;
 	    }
+	    if (klass == (Class)rb_cRubyHash) {
+		return rb_cNSMutableHash;
+	    } 
 	}
 
 #if ROXOR_VM_DEBUG
@@ -1257,6 +1263,9 @@
 	    if (self_type == T_ARRAY) {
 		return rb_ary_equal(self, other);
 	    }
+	    if (self_type == T_HASH) {
+		return rb_hash_equal(self, other);
+	    }
 	    return CFEqual((CFTypeRef)self, (CFTypeRef)other)
 		? Qtrue : Qfalse;
 

Modified: MacRuby/trunk/error.c
===================================================================
--- MacRuby/trunk/error.c	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/error.c	2010-01-20 23:49:09 UTC (rev 3315)
@@ -1040,8 +1040,6 @@
  *  <code>Exception</code> to add additional information.
  */
 
-VALUE rb_class_new_instance_imp(VALUE, SEL, int, VALUE *);
-
 void
 Init_Exception(void)
 {

Modified: MacRuby/trunk/hash.c
===================================================================
--- MacRuby/trunk/hash.c	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/hash.c	2010-01-20 23:49:09 UTC (rev 3315)
@@ -35,23 +35,63 @@
 #endif
 VALUE rb_cNSHash;
 VALUE rb_cNSMutableHash;
+VALUE rb_cRubyHash;
 
+typedef struct {
+    struct RBasic basic;
+    st_table *tbl;
+    VALUE ifnone;
+    bool has_proc_default; 
+} rb_hash_t;
+
+//#define IS_RHASH(x) (*(VALUE *)x == rb_cRubyHash)
+// XXX temporary
+#define IS_RHASH(x) __is_rhash(*(VALUE *)x)
+#define RHASH(x) ((rb_hash_t *)x)
+
+static force_inline bool
+__is_rhash(VALUE k)
+{
+    while (k != 0) {
+	if (k == rb_cRubyHash) {
+	    return true;
+	}
+	if (k == rb_cCFHash) {
+	    return false;
+	}
+	k = RCLASS_SUPER(k);
+    }
+    return false;
+}
+
+bool
+rb_klass_is_rhash(VALUE klass)
+{
+    return __is_rhash(klass);
+}
+
 static VALUE envtbl;
-static ID id_hash, id_yield;
+static ID id_yield;
 
 static void *defaultCache = NULL;
+static void *hashCache = NULL;
 static SEL selDefault = 0;
+static SEL selHash = 0;
 
 VALUE
 rb_hash(VALUE obj)
 {
-    VALUE v = rb_funcall(obj, id_hash, 0);
-    if (TYPE(v) == T_BIGNUM) {
-	unsigned long l = NUM2ULONG(v);
-	l /= 2.0;
-	v = ULONG2NUM(l);
+    VALUE v = rb_vm_call_with_cache(hashCache, obj, selHash, 0, NULL);
+retry:
+    switch (TYPE(v)) {
+	case T_FIXNUM:
+	    return v;
+	case T_BIGNUM:
+	    return LONG2FIX(((long *)(RBIGNUM_DIGITS(v)))[0]);
+	default:
+	    v = rb_to_int(v);
+	    goto retry;
     }
-    return v;
 }
 
 typedef int st_foreach_func(st_data_t, st_data_t, st_data_t);
@@ -65,10 +105,10 @@
 static int
 foreach_safe_i(st_data_t key, st_data_t value, struct foreach_safe_arg *arg)
 {
-    int status;
-
-    if (key == Qundef) return ST_CONTINUE;
-    status = (*arg->func)(key, value, arg->arg);
+    if (key == Qundef) {
+	return ST_CONTINUE;
+    }
+    const int status = (*arg->func)(key, value, arg->arg);
     if (status == ST_CONTINUE) {
 	return ST_CHECK;
     }
@@ -83,40 +123,41 @@
     arg.tbl = table;
     arg.func = (st_foreach_func *)func;
     arg.arg = a;
-    if (st_foreach(table, foreach_safe_i, (st_data_t)&arg)) {
-	rb_raise(rb_eRuntimeError, "hash modified during iteration");
-    }
+    st_foreach(table, foreach_safe_i, (st_data_t)&arg);
 }
 
 void
 rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
 {
-    CFIndex count = CFDictionaryGetCount((CFDictionaryRef)hash);
-    if (count == 0)
-	return;
-
-    const void **keys = (const void **)alloca(sizeof(void *) * count);
-    const void **values = (const void **)alloca(sizeof(void *) * count);
-
-    CFDictionaryGetKeysAndValues((CFDictionaryRef)hash, keys, values);
-
-    for (CFIndex i = 0; i < count; i++) {
-	if ((*func)(OC2RB(keys[i]), OC2RB(values[i]), farg) != ST_CONTINUE) {
-	    break;
+    if (IS_RHASH(hash)) {
+	st_foreach_safe(RHASH(hash)->tbl, func, (st_data_t)farg);
+    }
+    else {
+	CFIndex count = CFDictionaryGetCount((CFDictionaryRef)hash);
+	if (count != 0) {
+	    const void **keys = (const void **)alloca(sizeof(void *) * count);
+	    const void **vals = (const void **)alloca(sizeof(void *) * count);
+	    CFDictionaryGetKeysAndValues((CFDictionaryRef)hash, keys, vals);
+	    for (CFIndex i = 0; i < count; i++) {
+		if ((*func)(OC2RB(keys[i]), OC2RB(vals[i]), farg)
+			!= ST_CONTINUE) {
+		    break;
+		}
+	    }
 	}
     }
 }
 
-struct rb_hash_iterate_context {
+struct rb_cfhash_iterate_context {
     int (*func)(ANYARGS);
     VALUE farg;
 };
 
 static void
-rb_hash_iterate_i(const void *key, const void *value, void *context)
+rb_cfhash_iterate_i(const void *key, const void *value, void *context)
 {
-    struct rb_hash_iterate_context *ctx =
-	(struct rb_hash_iterate_context *)context;
+    struct rb_cfhash_iterate_context *ctx =
+	(struct rb_cfhash_iterate_context *)context;
 
     (*ctx->func)(OC2RB(key), OC2RB(value), ctx->farg); 
 }
@@ -124,84 +165,110 @@
 void
 rb_hash_iterate(VALUE hash, int (*func)(ANYARGS), VALUE farg)
 {
-    struct rb_hash_iterate_context ctx;
-    ctx.func = func;
-    ctx.farg = farg;
-    CFDictionaryApplyFunction((CFDictionaryRef)hash, rb_hash_iterate_i,
-	    &ctx); 
+    if (IS_RHASH(hash)) {
+	st_foreach_safe(RHASH(hash)->tbl, func, (st_data_t)farg);
+    }
+    else {
+	struct rb_cfhash_iterate_context ctx = {func, farg};
+	CFDictionaryApplyFunction((CFDictionaryRef)hash, rb_cfhash_iterate_i,
+		&ctx);
+    }
 }
 
-# define HASH_KEY_CALLBACKS(h) \
-  ((CFDictionaryKeyCallBacks *)((uint8_t *)h + 52))
+static int
+rb_any_cmp(VALUE a, VALUE b)
+{
+    if (a == b) {
+	return 0;
+    }
+    const int type = TYPE(a);
+    switch (type) {
+	case T_FIXNUM:
+	case T_FLOAT:
+	case T_SYMBOL:
+	    if (type == TYPE(b)) {
+		return a != b;
+	    }
+	    break;
+    }
 
-/* TODO optimize me */
-struct rb_objc_hash_struct {
-    VALUE ifnone;
-    bool has_proc_default; 
-};
+    // XXX optimize for string
 
-/* This variable will always stay NULL, we only use its address. */
-static void *rb_objc_hash_assoc_key = NULL;
-
-static struct rb_objc_hash_struct *
-rb_objc_hash_get_struct(VALUE hash)
-{
-    return rb_objc_get_associative_ref((void *)hash, &rb_objc_hash_assoc_key);
+    return !rb_eql(a, b);
 }
 
-static struct rb_objc_hash_struct *
-rb_objc_hash_get_struct2(VALUE hash)
+static int
+rb_any_hash(VALUE a)
 {
-    struct rb_objc_hash_struct *s;
+    switch (TYPE(a)) {
+	case T_FIXNUM:
+	case T_FLOAT:
+	case T_SYMBOL:
+	case T_NIL:
+	case T_FALSE:
+	case T_TRUE:
+	    return (int)a;
 
-    s = rb_objc_hash_get_struct(hash);
-    if (s == NULL) {
-	s = xmalloc(sizeof(struct rb_objc_hash_struct));
-	rb_objc_set_associative_ref((void *)hash, &rb_objc_hash_assoc_key, s);
-	s->ifnone = Qnil;
-	s->has_proc_default = false;
+	case T_STRING:
+	    return CFHash((CFTypeRef)a);
     }
-    return s;
-}
 
-static void
-rb_objc_hash_set_struct(VALUE hash, VALUE ifnone, bool has_proc_default)
-{
-    struct rb_objc_hash_struct *s;
+    // XXX optimize for string
 
-    s = rb_objc_hash_get_struct2(hash);
-
-    GC_WB(&s->ifnone, ifnone);
-    s->has_proc_default = has_proc_default;
+    return (int)FIX2LONG(rb_hash(a));
 }
 
+static const struct st_hash_type objhash = {
+    rb_any_cmp,
+    rb_any_hash,
+};
+
 static VALUE
 hash_alloc(VALUE klass)
 {
-    CFMutableDictionaryRef hash;
-
-    hash = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    if (klass != 0 && klass != rb_cNSHash && klass != rb_cNSMutableHash)
-	*(Class *)hash = (Class)klass;
-
-    CFMakeCollectable(hash);
-
-    return (VALUE)hash;
+    if ((klass == 0 || klass == rb_cRubyHash || klass == rb_cNSMutableHash)
+	    && rb_cRubyHash != 0) {
+	NEWOBJ(hash, rb_hash_t);
+	hash->basic.flags = 0;
+	hash->basic.klass = rb_cRubyHash;
+	GC_WB(&hash->tbl, st_init_table(&objhash));
+	hash->ifnone = Qnil;
+	hash->has_proc_default = false;
+	return (VALUE)hash;
+    }
+    else {
+	CFMutableDictionaryRef hash = CFDictionaryCreateMutable(NULL, 0,
+		&kCFTypeDictionaryKeyCallBacks,
+		&kCFTypeDictionaryValueCallBacks);
+	if (klass != 0 && klass != rb_cNSHash && klass != rb_cNSMutableHash) {
+	    *(Class *)hash = (Class)klass;
+	}
+	CFMakeCollectable(hash);
+	return (VALUE)hash;
+    }
 }
 
 VALUE
 rb_hash_dup(VALUE rcv)
 {
-    VALUE dup = (VALUE)CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)rcv);
-    if (OBJ_TAINTED(rcv))
-	OBJ_TAINT(dup);
-    CFMakeCollectable((CFTypeRef)dup);
-
-	struct rb_objc_hash_struct *s = rb_objc_hash_get_struct(rcv);
-	if (s != NULL)
-	    rb_objc_hash_set_struct(dup, s->ifnone, s->has_proc_default);
-
-    return dup;
+    if (IS_RHASH(rcv)) {
+	NEWOBJ(dup, rb_hash_t);
+	dup->basic.flags = 0;
+	dup->basic.klass = rb_cRubyHash;
+	GC_WB(&dup->tbl, st_copy(RHASH(rcv)->tbl));
+	GC_WB(&dup->ifnone, RHASH(rcv)->ifnone);
+	dup->has_proc_default = RHASH(rcv)->has_proc_default;
+	return (VALUE)dup;
+    }
+    else {
+	VALUE dup = (VALUE)CFDictionaryCreateMutableCopy(NULL, 0,
+		(CFDictionaryRef)rcv);
+	CFMakeCollectable((CFTypeRef)dup);
+	if (OBJ_TAINTED(rcv)) {
+	    OBJ_TAINT(dup);
+	}
+	return dup;
+    }
 }
 
 static VALUE
@@ -214,8 +281,9 @@
 rb_hash_clone(VALUE rcv, SEL sel)
 {
     VALUE clone = rb_hash_dup(rcv);
-    if (OBJ_FROZEN(rcv))
+    if (OBJ_FROZEN(rcv)) {
 	OBJ_FREEZE(clone);
+    }
     return clone;
 }
 
@@ -228,20 +296,16 @@
 VALUE
 rb_hash_new_fast(int argc, ...)
 {
-    va_list ar;
-    VALUE hash;
-    int i;
+    assert(argc % 2 == 0);
 
-    hash = hash_alloc(0);
+    VALUE hash = hash_alloc(0);
 
-    assert(argc % 2 == 0);
-
+    va_list ar;
     va_start(ar, argc);
-    for (i = 0; i < argc; i += 2) {
+    for (int i = 0; i < argc; i += 2) {
 	VALUE key = va_arg(ar, VALUE);
 	VALUE val = va_arg(ar, VALUE);
-	CFDictionarySetValue((CFMutableDictionaryRef)hash, (const void *)RB2OC(key),
-		(const void *)RB2OC(val));
+	rb_hash_aset(hash, key, val);
     }
     va_end(ar);
 
@@ -252,14 +316,15 @@
 rb_hash_modify_check(VALUE hash)
 {
     long mask;
-#ifdef __LP64__
-    mask = RCLASS_RC_FLAGS(hash);
-#else
-    mask = rb_objc_flag_get_mask((const void *)hash);
-#endif
-    if (RHASH_IMMUTABLE(hash)) {
-	mask |= FL_FREEZE;
+    if (IS_RHASH(hash)) {
+	mask = RBASIC(hash)->flags;
     }
+    else {
+	mask = rb_objc_flag_get_mask((const void *)hash);
+	if (RHASH_IMMUTABLE(hash)) {
+	    mask |= FL_FREEZE;
+	}
+    }
     if ((mask & FL_FREEZE) == FL_FREEZE) {
 	rb_raise(rb_eRuntimeError, "can't modify frozen/immutable hash");
     }
@@ -310,20 +375,24 @@
 {
     rb_hash_modify(hash);
 
-    hash = (VALUE)objc_msgSend((id)hash, selInit);
+    //hash = (VALUE)objc_msgSend((id)hash, selInit);
 
-    if (rb_block_given_p()) {
-	if (argc > 0) {
-	    rb_raise(rb_eArgError, "wrong number of arguments");
+    if (IS_RHASH(hash)) {
+	if (rb_block_given_p()) {
+	    if (argc > 0) {
+		rb_raise(rb_eArgError, "wrong number of arguments");
+	    }
+	    GC_WB(&RHASH(hash)->ifnone, rb_block_proc());
+	    RHASH(hash)->has_proc_default = true;
 	}
-	rb_objc_hash_set_struct(hash, rb_block_proc(), true);
+	else {
+	    VALUE ifnone;
+	    rb_scan_args(argc, argv, "01", &ifnone);
+	    if (ifnone != Qnil) {
+		GC_WB(&RHASH(hash)->ifnone, ifnone);
+	    }
+	}
     }
-    else {
-	VALUE ifnone;
-	rb_scan_args(argc, argv, "01", &ifnone);
-	if (ifnone != Qnil)
-	    rb_objc_hash_set_struct(hash, ifnone, false);
-    }
 
     return hash;
 }
@@ -352,43 +421,47 @@
 static VALUE
 rb_hash_s_create(VALUE klass, SEL sel, int argc, VALUE *argv)
 {
-    VALUE hash, tmp;
-    int i;
-
     if (argc == 1) {
-	tmp = rb_hash_s_try_convert(Qnil, 0, argv[0]);
+	VALUE tmp = rb_hash_s_try_convert(Qnil, 0, argv[0]);
 	if (!NIL_P(tmp)) {
-	    CFIndex i, count;
-	    const void **keys;
-	    const void **values;
+	    VALUE hash = hash_alloc(klass);
+	    if (IS_RHASH(hash) && IS_RHASH(tmp)) {
+		GC_WB(&RHASH(hash)->tbl, st_copy(RHASH(tmp)->tbl));
+	    }
+	    else {
+		CFIndex count = CFDictionaryGetCount((CFDictionaryRef)tmp);
+		if (count == 0) {
+		    return hash;
+		}
 
-	    hash = hash_alloc(klass);
-	    count = CFDictionaryGetCount((CFDictionaryRef)tmp);
-	    if (count == 0)
-		return hash;
+		const void **keys = (const void **)alloca(sizeof(void *)
+			* count);
+		const void **values = (const void **)alloca(sizeof(void *)
+			* count);
 
-	    keys = (const void **)alloca(sizeof(void *) * count);
-	    values = (const void **)alloca(sizeof(void *) * count);
+		CFDictionaryGetKeysAndValues((CFDictionaryRef)tmp, keys,
+			values);
 
-	    CFDictionaryGetKeysAndValues((CFDictionaryRef)tmp, keys, values);
+		for (int i = 0; i < count; i++) {
+		    CFDictionarySetValue((CFMutableDictionaryRef)hash,
+			    RB2OC(keys[i]), RB2OC(values[i]));
+		}
+	    }
 
-	    for (i = 0; i < count; i++)
-		CFDictionarySetValue((CFMutableDictionaryRef)hash,
-			RB2OC(keys[i]), RB2OC(values[i]));
-
 	    return hash;
 	}
 
 	tmp = rb_check_array_type(argv[0]);
 	if (!NIL_P(tmp)) {
-	    long i;
-
-	    hash = hash_alloc(klass);
-	    for (i = 0; i < RARRAY_LEN(tmp); ++i) {
+	    VALUE hash = hash_alloc(klass);
+	    for (int i = 0; i < RARRAY_LEN(tmp); ++i) {
 		VALUE v = rb_check_array_type(RARRAY_AT(tmp, i));
-
-		if (NIL_P(v)) continue;
-		if (RARRAY_LEN(v) < 1 || 2 < RARRAY_LEN(v)) continue;
+		if (NIL_P(v)) {
+		    continue;
+		}
+		if (RARRAY_LEN(v) < 1 || 2 < RARRAY_LEN(v)) {
+		    continue;
+		}
 		rb_hash_aset(hash, RARRAY_AT(v, 0), RARRAY_AT(v, 1));
 	    }
 	    return hash;
@@ -398,8 +471,8 @@
 	rb_raise(rb_eArgError, "odd number of arguments for Hash");
     }
 
-    hash = hash_alloc(klass);
-    for (i=0; i<argc; i+=2) {
+    VALUE hash = hash_alloc(klass);
+    for (int i = 0; i < argc; i += 2) {
         rb_hash_aset(hash, argv[i], argv[i + 1]);
     }
 
@@ -449,29 +522,44 @@
  *     h[a]       #=> 100
  */
 
+static int
+rb_hash_rehash_i(VALUE key, VALUE value, VALUE arg)
+{
+    st_table *tbl = (st_table *)arg;
+    if (key != Qundef) {
+	st_insert(tbl, key, value);
+    }
+    return ST_CONTINUE;
+}
+
 static VALUE
 rb_hash_rehash(VALUE hash, SEL sel)
 {
-    CFIndex i, count;
-    const void **keys;
-    const void **values;
-
     rb_hash_modify_check(hash);
+    if (IS_RHASH(hash)) {
+	st_table *tbl = st_init_table_with_size(RHASH(hash)->tbl->type,
+		RHASH(hash)->tbl->num_entries);
+	rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tbl);
+	//st_free_table(RHASH(hash)->tbl);
+	GC_WB(&RHASH(hash)->tbl, tbl);
+    }
+    else {
+	CFIndex count = CFDictionaryGetCount((CFDictionaryRef)hash);
+	if (count == 0) {
+	    return hash;
+	}
 
-    count = CFDictionaryGetCount((CFDictionaryRef)hash);
-    if (count == 0)
-	return hash;
+	const void **keys = (const void **)alloca(sizeof(void *) * count);
+	const void **values = (const void **)alloca(sizeof(void *) * count);
 
-    keys = (const void **)alloca(sizeof(void *) * count);
-    values = (const void **)alloca(sizeof(void *) * count);
+	CFDictionaryGetKeysAndValues((CFDictionaryRef)hash, keys, values);
+	CFDictionaryRemoveAllValues((CFMutableDictionaryRef)hash);
 
-    CFDictionaryGetKeysAndValues((CFDictionaryRef)hash, keys, values);
-    CFDictionaryRemoveAllValues((CFMutableDictionaryRef)hash);
-
-    for (i = 0; i < count; i++)
-	CFDictionarySetValue((CFMutableDictionaryRef)hash,
-	    (const void *)keys[i], (const void *)values[i]);
-
+	for (CFIndex i = 0; i < count; i++) {
+	    CFDictionarySetValue((CFMutableDictionaryRef)hash,
+		    (const void *)keys[i], (const void *)values[i]);
+	}
+    }
     return hash;
 }
 
@@ -492,20 +580,26 @@
 VALUE
 rb_hash_aref(VALUE hash, VALUE key)
 {
-    VALUE val;
-
-    if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
-		(const void *)RB2OC(key), (const void **)&val)) {
-	if (*(VALUE *)hash == rb_cCFHash) {
-	    struct rb_objc_hash_struct *s = rb_objc_hash_get_struct(hash);
-	    if (s == NULL || s->ifnone == Qnil) {
+    if (IS_RHASH(hash)) {
+	VALUE val;
+	if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
+	    if (*(VALUE *)hash == rb_cRubyHash
+		    && RHASH(hash)->ifnone == Qnil) {
 		return Qnil;
 	    }
+	    return rb_vm_call_with_cache(defaultCache, hash, selDefault,
+		    1, &key);
 	}
-	return rb_vm_call_with_cache(defaultCache, hash, selDefault, 1, &key);
+	return val;
     }
-    val = OC2RB(val);
-    return val;
+    else {
+	VALUE val;
+	if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
+		    (const void *)RB2OC(key), (const void **)&val)) {
+	    return Qnil;
+	}
+	return OC2RB(val);
+    }
 }
 
 static VALUE
@@ -514,17 +608,30 @@
     return rb_hash_aref(hash, key);
 }
 
+static VALUE
+rb_hash_lookup0(VALUE hash, VALUE key)
+{
+    if (IS_RHASH(hash)) {
+	VALUE val;
+	if (st_lookup(RHASH(hash)->tbl, key, &val)) {
+	    return val;
+	}
+    }
+    else {
+	VALUE val;
+	if (CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
+		    (const void *)RB2OC(key), (const void **)&val)) {
+	    return OC2RB(val);
+	}
+    }
+    return Qundef;
+}
+
 VALUE
 rb_hash_lookup(VALUE hash, VALUE key)
 {
-    VALUE val;
-
-    if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)hash, (const void *)RB2OC(key),
-	(const void **)&val)) {
-	return Qnil;
-    }
-    val = OC2RB(val);
-    return val;
+    VALUE v = rb_hash_lookup0(hash, key);
+    return v == Qundef ? Qnil : v;
 }
 
 /*
@@ -560,24 +667,24 @@
 rb_hash_fetch(VALUE hash, SEL sel, int argc, VALUE *argv)
 {
     VALUE key, if_none;
-    VALUE val;
-    long block_given;
-
     rb_scan_args(argc, argv, "11", &key, &if_none);
 
-    block_given = rb_block_given_p();
+    const bool block_given = rb_block_given_p();
     if (block_given && argc == 2) {
 	rb_warn("block supersedes default value argument");
     }
-    if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)hash, (const void *)RB2OC(key),
-	(const void **)&val)) {
-	if (block_given) return rb_yield(key);
-	if (argc == 1) {
-	    rb_raise(rb_eKeyError, "key not found");
-	}
-	return if_none;
+
+    VALUE v = rb_hash_lookup0(hash, key);
+    if (v != Qundef) {
+	return v;
     }
-    return OC2RB(val);
+    if (block_given) {
+	return rb_yield(key);
+    }
+    if (argc == 1) {
+	rb_raise(rb_eKeyError, "key not found");
+    }
+    return if_none;
 }
 
 /*
@@ -604,18 +711,19 @@
 static VALUE
 rb_hash_default(VALUE hash, SEL sel, int argc, VALUE *argv)
 {
-    struct rb_objc_hash_struct *s = rb_objc_hash_get_struct(hash);
     VALUE key;
+    rb_scan_args(argc, argv, "01", &key);
 
-    if (s == NULL || s->ifnone == Qnil)
-	return Qnil;
-
-    rb_scan_args(argc, argv, "01", &key);
-    if (s->has_proc_default) {
-	if (argc == 0) return Qnil;
-	return rb_funcall(s->ifnone, id_yield, 2, hash, key);
+    if (IS_RHASH(hash)) {
+	if (RHASH(hash)->has_proc_default) {
+	    if (argc == 0) {
+		return Qnil;
+	    }
+	    return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash, key);
+	}
+	return RHASH(hash)->ifnone;
     }
-    return s->ifnone;
+    return Qnil;
 }
 
 /*
@@ -642,7 +750,10 @@
 rb_hash_set_default(VALUE hash, SEL sel, VALUE ifnone)
 {
     rb_hash_modify(hash);
-    rb_objc_hash_set_struct(hash, ifnone, false);
+    if (IS_RHASH(hash)) {
+	GC_WB(&RHASH(hash)->ifnone, ifnone);
+	RHASH(hash)->has_proc_default = false;
+    }
     return ifnone;
 }
 
@@ -670,9 +781,9 @@
 static VALUE
 rb_hash_default_proc(VALUE hash, SEL sel)
 {
-    struct rb_objc_hash_struct *s = rb_objc_hash_get_struct(hash);
-    if (s != NULL && s->has_proc_default)
-	return s->ifnone;
+    if (IS_RHASH(hash)) {
+	return RHASH(hash)->has_proc_default ? RHASH(hash)->ifnone : Qnil;
+    }
     return Qnil;
 }
 
@@ -701,13 +812,8 @@
 static VALUE
 rb_hash_key(VALUE hash, SEL sel, VALUE value)
 {
-    VALUE args[2];
-
-    args[0] = value;
-    args[1] = Qnil;
-
+    VALUE args[2] = {value, Qnil};
     rb_hash_iterate(hash, key_i, (st_data_t)args);
-
     return args[1];
 }
 
@@ -722,14 +828,22 @@
 VALUE
 rb_hash_delete_key(VALUE hash, VALUE key)
 {
-    VALUE val;
-    id ockey = RB2OC(key);
-    if (CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
-	(const void *)ockey, (const void **)&val)) {
-	CFDictionaryRemoveValue((CFMutableDictionaryRef)hash, 
-	    (const void *)ockey);
-	return OC2RB(val);
+    if (IS_RHASH(hash)) {
+	VALUE val;
+	if (st_delete(RHASH(hash)->tbl, &key, &val)) {
+	    return val;
+	}
     }
+    else {
+	VALUE val;
+	id ockey = RB2OC(key);
+	if (CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
+		    (const void *)ockey, (const void **)&val)) {
+	    CFDictionaryRemoveValue((CFMutableDictionaryRef)hash, 
+		    (const void *)ockey);
+	    return OC2RB(val);
+	}
+    }
     return Qundef;
 }
 
@@ -754,11 +868,11 @@
 VALUE
 rb_hash_delete(VALUE hash, VALUE key)
 {
-    VALUE val;
-
     rb_hash_modify(hash);
-    val = rb_hash_delete_key(hash, key);
-    if (val != Qundef) return val;
+    VALUE val = rb_hash_delete_key(hash, key);
+    if (val != Qundef) {
+	return val;
+    }
     if (rb_block_given_p()) {
 	return rb_yield(key);
     }
@@ -789,33 +903,35 @@
 static VALUE
 rb_hash_shift(VALUE hash, SEL sel)
 {
-    VALUE keys, key, val;
-
-    keys = rb_hash_keys_imp(hash, 0);
+    VALUE keys = rb_hash_keys_imp(hash, 0);
     if (RARRAY_LEN(keys) == 0) {
-	struct rb_objc_hash_struct *s = rb_objc_hash_get_struct(hash);
-
-	if (s == NULL || s->ifnone == Qnil)
-	    return Qnil;
-
-	if (s->has_proc_default)
-	    return rb_funcall(s->ifnone, id_yield, 2, hash, Qnil);
-	return s->ifnone;
+	if (IS_RHASH(hash)) {
+	    if (RHASH(hash)->ifnone != Qnil) {
+		if (RHASH(hash)->has_proc_default) {
+		    return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash,
+			    Qnil);
+		}
+		return RHASH(hash)->ifnone;
+	    }
+	}
+	return Qnil;
     }
 
-    key = RARRAY_AT(keys, 0);
-    val = rb_hash_aref(hash, key);
+    VALUE key = RARRAY_AT(keys, 0);
+    VALUE val = rb_hash_aref(hash, key);
     rb_hash_delete(hash, key);
 
     return rb_assoc_new(key, val);
 }
 
 static int
-delete_if_i(VALUE key, VALUE value, VALUE hash)
+delete_if_i(VALUE key, VALUE value, VALUE ary)
 {
-    if (key == Qundef) return ST_CONTINUE;
+    if (key == Qundef) {
+	return ST_CONTINUE;
+    }
     if (RTEST(rb_yield_values(2, key, value))) {
-	rb_hash_delete_key(hash, key);
+	rb_ary_push(ary, key);
     }
     return ST_CONTINUE;
 }
@@ -837,7 +953,12 @@
 {
     RETURN_ENUMERATOR(hash, 0, 0);
     rb_hash_modify(hash);
-    rb_hash_foreach(hash, delete_if_i, hash);
+    VALUE ary = rb_ary_new();
+    rb_hash_foreach(hash, delete_if_i, ary);
+    for (int i = 0, count = RARRAY_LEN(ary); i < count; i++) {
+	VALUE key = RARRAY_AT(ary, i);
+	rb_hash_delete_key(hash, key);	
+    }
     return hash;
 }
 
@@ -852,14 +973,10 @@
 static VALUE
 rb_hash_reject_bang(VALUE hash, SEL sel)
 {
-    CFIndex n;
-
     RETURN_ENUMERATOR(hash, 0, 0);
-    n = CFDictionaryGetCount((CFDictionaryRef)hash);
+    const long n = RHASH_SIZE(hash);
     rb_hash_delete_if(hash, 0);
-    if (n == CFDictionaryGetCount((CFDictionaryRef)hash))
-	return Qnil;
-    return hash;
+    return n == RHASH_SIZE(hash) ? Qnil : hash;
 }
 
 /*
@@ -893,9 +1010,7 @@
 rb_hash_values_at(VALUE hash, SEL sel, int argc, VALUE *argv)
 {
     VALUE result = rb_ary_new2(argc);
-    long i;
-
-    for (i=0; i<argc; i++) {
+    for (int i = 0; i < argc; i++) {
 	rb_ary_push(result, rb_hash_aref(hash, argv[i]));
     }
     return result;
@@ -904,9 +1019,12 @@
 static int
 select_i(VALUE key, VALUE value, VALUE result)
 {
-    if (key == Qundef) return ST_CONTINUE;
-    if (RTEST(rb_yield_values(2, key, value)))
+    if (key == Qundef) {
+	return ST_CONTINUE;
+    }
+    if (RTEST(rb_yield_values(2, key, value))) {
 	rb_hash_aset(result, key, value);
+    }
     return ST_CONTINUE;
 }
 
@@ -924,10 +1042,8 @@
 static VALUE
 rb_hash_select(VALUE hash, SEL sel)
 {
-    VALUE result;
-
     RETURN_ENUMERATOR(hash, 0, 0);
-    result = rb_hash_new();
+    VALUE result = rb_hash_new();
     rb_hash_iterate(hash, select_i, result);
     return result;
 }
@@ -947,8 +1063,12 @@
 rb_hash_clear(VALUE hash, SEL sel)
 {
     rb_hash_modify_check(hash);
-    CFDictionaryRemoveAllValues((CFMutableDictionaryRef)hash);
-
+    if (IS_RHASH(hash)) {
+	st_clear(RHASH(hash)->tbl);
+    }
+    else {
+	CFDictionaryRemoveAllValues((CFMutableDictionaryRef)hash);
+    }
     return hash;
 }
 
@@ -974,8 +1094,14 @@
 rb_hash_aset(VALUE hash, VALUE key, VALUE val)
 {
     rb_hash_modify(hash);
-    CFDictionarySetValue((CFMutableDictionaryRef)hash, (const void *)RB2OC(key),
-	(const void *)RB2OC(val));
+    if (IS_RHASH(hash)) {
+	st_insert(RHASH(hash)->tbl, key, val);
+    }
+    else {
+	CFDictionarySetValue((CFMutableDictionaryRef)hash,
+		(const void *)RB2OC(key),
+		(const void *)RB2OC(val));
+    }
     return val;
 }
 
@@ -991,7 +1117,6 @@
     if (key != Qundef) {
 	rb_hash_aset(hash, key, val);
     }
-
     return ST_CONTINUE;
 }
 
@@ -1017,11 +1142,11 @@
     }
     rb_hash_clear(hash, 0);
     rb_hash_foreach(hash2, replace_i, hash);
-    struct rb_objc_hash_struct *s = rb_objc_hash_get_struct(hash2);
-    if (s != NULL) {
-	rb_objc_hash_set_struct(hash, s->ifnone, s->has_proc_default);
+
+    if (IS_RHASH(hash) && IS_RHASH(hash2)) {
+	GC_WB(&RHASH(hash)->ifnone, RHASH(hash2)->ifnone);
+	RHASH(hash)->has_proc_default = RHASH(hash2)->has_proc_default;
     }
-
     return hash;
 }
 
@@ -1038,13 +1163,21 @@
  *     h.length        #=> 3
  */
 
+long
+rb_hash_size(VALUE hash)
+{
+    if (IS_RHASH(hash)) {
+	return RHASH(hash)->tbl->num_entries;
+    }
+    return CFDictionaryGetCount((CFDictionaryRef)hash);
+}
+
 static VALUE
-rb_hash_size(VALUE hash, SEL sel)
+rb_hash_size_imp(VALUE hash, SEL sel)
 {
-    return INT2FIX(CFDictionaryGetCount((CFDictionaryRef)hash));
+    return LONG2NUM(rb_hash_size(hash));
 }
 
-
 /*
  *  call-seq:
  *     hsh.empty?    => true or false
@@ -1098,7 +1231,9 @@
 static int
 each_key_i(VALUE key, VALUE value)
 {
-    if (key == Qundef) return ST_CONTINUE;
+    if (key == Qundef) {
+	return ST_CONTINUE;
+    }
     rb_yield(key);
     return ST_CONTINUE;
 }
@@ -1129,7 +1264,9 @@
 static int
 each_pair_i(VALUE key, VALUE value)
 {
-    if (key == Qundef) return ST_CONTINUE;
+    if (key == Qundef) {
+	return ST_CONTINUE;
+    }
     rb_yield(rb_assoc_new(key, value));
     return ST_CONTINUE;
 }
@@ -1163,7 +1300,9 @@
 static int
 to_a_i(VALUE key, VALUE value, VALUE ary)
 {
-    if (key == Qundef) return ST_CONTINUE;
+    if (key == Qundef) {
+	return ST_CONTINUE;
+    }
     rb_ary_push(ary, rb_assoc_new(key, value));
     return ST_CONTINUE;
 }
@@ -1187,7 +1326,6 @@
     if (OBJ_TAINTED(hash)) {
 	OBJ_TAINT(ary);
     }
-
     return ary;
 }
 
@@ -1205,7 +1343,6 @@
     rb_str_buf_cat2(str, "=>");
     str2 = rb_inspect(value);
     rb_str_buf_append(str, str2);
-
     return ST_CONTINUE;
 }
 
@@ -1219,7 +1356,6 @@
     rb_hash_iterate(hash, inspect_i, str);
     rb_str_buf_cat2(str, "}");
     OBJ_INFECT(str, hash);
-
     return str;
 }
 
@@ -1237,8 +1373,9 @@
 static VALUE
 rb_hash_inspect(VALUE hash, SEL sel)
 {
-    if (RHASH_EMPTY_P(hash))
+    if (RHASH_EMPTY_P(hash)) {
 	return rb_usascii_str_new2("{}");
+    }
     return rb_exec_recursive(inspect_hash, hash, 0);
 }
 
@@ -1339,9 +1476,13 @@
 static VALUE
 rb_hash_has_key_imp(VALUE hash, SEL sel, VALUE key)
 {
-    return CFDictionaryContainsKey((CFDictionaryRef)hash,
-	    (const void *)RB2OC(key))
-	? Qtrue : Qfalse;
+    if (IS_RHASH(hash)) {
+	return st_lookup(RHASH(hash)->tbl, key, 0) ? Qtrue : Qfalse;
+    }
+    else {
+	return CFDictionaryContainsKey((CFDictionaryRef)hash,
+		(const void *)RB2OC(key)) ? Qtrue : Qfalse;
+    }
 }
 
 VALUE
@@ -1363,29 +1504,108 @@
  *     h.has_value?(999)   #=> false
  */
 
+static int
+rb_hash_search_value(VALUE key, VALUE value, VALUE arg)
+{
+    VALUE *data = (VALUE *)arg;
+    if (key == Qundef) {
+	return ST_CONTINUE;
+    }
+    if (rb_equal(value, data[1])) {
+        data[0] = Qtrue;
+        return ST_STOP;
+    }
+    return ST_CONTINUE;
+}
+
 static VALUE
 rb_hash_has_value(VALUE hash, SEL sel, VALUE val)
 {
-    return CFDictionaryContainsValue((CFDictionaryRef)hash, (const void *)RB2OC(val))
-	? Qtrue : Qfalse;
+    if (IS_RHASH(hash)) {
+	VALUE data[2] = {Qfalse, val};
+	rb_hash_foreach(hash, rb_hash_search_value, (VALUE)data);
+	return data[0];
+    }
+    else {
+	return CFDictionaryContainsValue((CFDictionaryRef)hash,
+		(const void *)RB2OC(val)) ? Qtrue : Qfalse;
+    }
 }
 
+struct equal_data {
+    VALUE result;
+    st_table *tbl;
+    bool eql;
+};
+
+static int
+eql_i(VALUE key, VALUE val1, VALUE arg)
+{
+    struct equal_data *data = (struct equal_data *)arg;
+    VALUE val2;
+
+    if (key == Qundef) {
+	return ST_CONTINUE;
+    }
+    if (!st_lookup(data->tbl, key, &val2)) {
+        data->result = Qfalse;
+        return ST_STOP;
+    }
+    if (data->eql) {
+	if (!rb_eql(val1, val2)) {
+	    data->result = Qfalse;
+	    return ST_STOP;
+	}
+    }
+    else {
+	if (rb_equal(val1, val2) != Qtrue) {
+	    data->result = Qfalse;
+	    return ST_STOP;
+	}
+    }
+    return ST_CONTINUE;
+}
+
 static VALUE
-hash_equal(VALUE hash1, VALUE hash2, int eql)
+recursive_eql(VALUE hash1, VALUE data, int recur)
 {
-    if (hash1 == hash2) return Qtrue;
+    if (recur) {
+	return Qtrue;
+    }
+    ((struct equal_data *)data)->result = Qtrue;
+    rb_hash_foreach(hash1, eql_i, data);
+    return ((struct equal_data *)data)->result; 
+}
+
+static VALUE
+hash_equal(VALUE hash1, VALUE hash2, bool eql)
+{
+    if (hash1 == hash2) {
+	return Qtrue;
+    }
     if (TYPE(hash2) != T_HASH) {
 	if (!rb_respond_to(hash2, rb_intern("to_hash"))) {
 	    return Qfalse;
 	}
-	if (eql)
+	if (eql) {
 	    return rb_eql(hash2, hash1);
-	else
+	}
+	else {
 	    return rb_equal(hash2, hash1);
+	}
     }
-    if (RHASH_SIZE(hash1) != RHASH_SIZE(hash2))
+    if (RHASH_SIZE(hash1) != RHASH_SIZE(hash2)) {
 	return Qfalse;
-    return CFEqual((CFTypeRef)hash1, (CFTypeRef)hash2) ? Qtrue : Qfalse;
+    }
+    if (IS_RHASH(hash1) && IS_RHASH(hash2)) {
+	struct equal_data data;
+	data.tbl = RHASH(hash2)->tbl;
+	data.eql = eql;
+	return rb_exec_recursive(recursive_eql, hash1, (VALUE)&data);
+    }
+    else {
+	return CFEqual((CFTypeRef)hash1, (CFTypeRef)hash2) ? Qtrue : Qfalse;
+    }
 }
 
 /*
@@ -1408,11 +1628,17 @@
  */
 
 static VALUE
-rb_hash_equal(VALUE hash1, SEL sel, VALUE hash2)
+rb_hash_equal_imp(VALUE hash1, SEL sel, VALUE hash2)
 {
-    return hash_equal(hash1, hash2, Qfalse);
+    return hash_equal(hash1, hash2, false);
 }
 
+VALUE
+rb_hash_equal(VALUE hash1, VALUE hash2)
+{
+    return hash_equal(hash1, hash2, false);
+}
+
 /*
  *  call-seq:
  *     hash.eql?(other)  -> true or false
@@ -1424,7 +1650,7 @@
 static VALUE
 rb_hash_eql(VALUE hash1, SEL sel, VALUE hash2)
 {
-    return hash_equal(hash1, hash2, Qtrue);
+    return hash_equal(hash1, hash2, true);
 }
 
 static int
@@ -1568,10 +1794,7 @@
 VALUE
 rb_hash_assoc(VALUE hash, SEL sel, VALUE obj)
 {
-    VALUE args[2];
-
-    args[0] = obj;
-    args[1] = Qnil;
+    VALUE args[2] = {obj, Qnil};
     rb_hash_foreach(hash, assoc_i, (st_data_t)args);
     return args[1];
 }
@@ -1605,10 +1828,7 @@
 VALUE
 rb_hash_rassoc(VALUE hash, SEL sel, VALUE obj)
 {
-    VALUE args[2];
-
-    args[0] = obj;
-    args[1] = Qnil;
+    VALUE args[2] = {obj, Qnil};
     rb_hash_foreach(hash, rassoc_i, (st_data_t)args);
     return args[1];
 }
@@ -1632,9 +1852,7 @@
 static VALUE
 rb_hash_flatten(VALUE hash, SEL sel, int argc, VALUE *argv)
 {
-    VALUE ary, tmp;
-
-    ary = rb_hash_to_a(hash, 0);
+    VALUE tmp, ary = rb_hash_to_a(hash, 0);
     if (argc == 0) {
 	argc = 1;
 	tmp = INT2FIX(1);
@@ -1664,7 +1882,7 @@
 rb_hash_compare_by_id(VALUE hash, SEL sel)
 {
     rb_hash_modify(hash);
-//    HASH_KEY_CALLBACKS(hash)->equal = NULL;
+    // TODO
     return hash;
 }
 
@@ -1680,10 +1898,8 @@
 static VALUE
 rb_hash_compare_by_id_p(VALUE hash, SEL sel)
 {
+    // TODO
     return Qfalse;
-//    return HASH_KEY_CALLBACKS(hash) != &kCFTypeDictionaryKeyCallBacks 
-//	&& HASH_KEY_CALLBACKS(hash)->equal == NULL
-//	    ? Qtrue : Qfalse;
 }
 
 static int path_tainted = -1;
@@ -2397,9 +2613,25 @@
     *(Class *)x = old;
 
 bool
-rb_objc_hash_is_pure(VALUE ary)
+rb_objc_hash_is_pure(VALUE hash)
 {
-    return *(Class *)ary == (Class)rb_cCFHash;
+    return *(VALUE *)hash == rb_cCFHash || *(VALUE *)hash == rb_cRubyHash;
+#if 0
+    VALUE k = *(VALUE *)hash;
+    while (RCLASS_SINGLETON(k)) {
+        k = RCLASS_SUPER(k);
+    }
+    if (k == rb_cRubyHash) {
+	return true;
+    }
+    while (k != 0) {
+	if (k == rb_cRubyHash) {
+	    return false;
+	}
+	k = RCLASS_SUPER(k);
+    }
+    return true;
+#endif
 }
 
 static CFIndex
@@ -2415,13 +2647,13 @@
 static void *
 imp_rb_hash_keyEnumerator(void *rcv, SEL sel)
 {
-    void *keys;
     static SEL objectEnumerator = 0;
     PREPARE_RCV(rcv);
-    keys = (void *)rb_hash_keys_imp((VALUE)rcv, 0);
+    void *keys = (void *)rb_hash_keys_imp((VALUE)rcv, 0);
     RESTORE_RCV(rcv);
-    if (objectEnumerator == 0)
+    if (objectEnumerator == 0) {
 	objectEnumerator = sel_registerName("objectEnumerator");
+    }
     return objc_msgSend(keys, objectEnumerator);
 }
 
@@ -2521,6 +2753,76 @@
     rb_objc_define_method(*(VALUE *)klass, "alloc", hash_alloc, 0);
 }
 
+static VALUE rb_cRubyHashKeyEnumerator;
+
+typedef struct {
+    VALUE klass;
+    VALUE hash;
+    VALUE keys;
+    unsigned pos;
+} rb_hash_keyenum_t;
+
+static void *
+imp_rhash_keyenum_allObjects(void *rcv, SEL sel)
+{
+    rb_hash_keyenum_t *ke = (rb_hash_keyenum_t *)rcv;
+    return (void *)ke->keys;
+}
+
+static void *
+imp_rhash_keyenum_nextObject(void *rcv, SEL sel)
+{
+    rb_hash_keyenum_t *ke = (rb_hash_keyenum_t *)rcv;
+    if (ke->pos == RARRAY_LEN(ke->keys)) {
+	return NULL;
+    }
+    VALUE key = RARRAY_AT(ke->keys, ke->pos);
+    ke->pos++;
+    return (void *)RB2OC(key);
+}
+
+static CFIndex
+imp_rhash_count(void *rcv, SEL sel)
+{
+    return RHASH(rcv)->tbl->num_entries;
+}
+
+static void *
+imp_rhash_objectForKey(void *rcv, SEL sel, void *key)
+{
+    VALUE val;
+    if (!st_lookup(RHASH(rcv)->tbl, OC2RB(key), &val)) {
+	return NULL;
+    }
+    return RB2OC(val);
+}
+
+static void *
+imp_rhash_keyEnumerator(void *rcv, SEL sel)
+{
+    NEWOBJ(keyenum, rb_hash_keyenum_t);
+    keyenum->klass = rb_cRubyHashKeyEnumerator;
+    GC_WB(&keyenum->hash, rcv);
+    VALUE ary = rb_ary_new();
+    st_foreach_safe(RHASH(rcv)->tbl, keys_i, (st_data_t)ary);
+    GC_WB(&keyenum->keys, ary); 
+    keyenum->pos = 0;
+    return keyenum;
+}
+
+static void
+imp_rhash_setObjectForKey(void *rcv, SEL sel, void *val, void *key)
+{
+    st_insert(RHASH(rcv)->tbl, OC2RB(key), OC2RB(val));
+}
+
+static void
+imp_rhash_removeObjectForKey(void *rcv, SEL sel, void *key)
+{
+    VALUE rkey = OC2RB(key);
+    st_delete(RHASH(rcv)->tbl, &rkey, NULL);
+}
+
 /*
  *  A <code>Hash</code> is a collection of key-value pairs. It is
  *  similar to an <code>Array</code>, except that indexing is done via
@@ -2544,9 +2846,10 @@
 Init_Hash(void)
 {
     selDefault = sel_registerName("default:");
+    selHash = sel_registerName("hash");
     defaultCache = rb_vm_get_call_cache(selDefault);
+    hashCache = rb_vm_get_call_cache(selHash);
 
-    id_hash = rb_intern("hash");
     id_yield = rb_intern("yield");
 
     rb_cCFHash = (VALUE)objc_getClass(NSCFDICTIONARY_CNAME);
@@ -2577,7 +2880,7 @@
     rb_objc_define_method(rb_cHash, "to_s", rb_hash_inspect, 0);
     rb_objc_define_method(rb_cHash, "inspect", rb_hash_inspect, 0);
 
-    rb_objc_define_method(rb_cHash, "==", rb_hash_equal, 1);
+    rb_objc_define_method(rb_cHash, "==", rb_hash_equal_imp, 1);
     rb_objc_define_method(rb_cHash, "[]", rb_hash_aref_imp, 1);
     rb_objc_define_method(rb_cHash, "eql?", rb_hash_eql, 1);
     rb_objc_define_method(rb_cHash, "fetch", rb_hash_fetch, -1);
@@ -2588,8 +2891,8 @@
     rb_objc_define_method(rb_cHash, "default_proc", rb_hash_default_proc, 0);
     rb_objc_define_method(rb_cHash, "key", rb_hash_key, 1);
     rb_objc_define_method(rb_cHash, "index", rb_hash_index, 1);
-    rb_objc_define_method(rb_cHash, "size", rb_hash_size, 0);
-    rb_objc_define_method(rb_cHash, "length", rb_hash_size, 0);
+    rb_objc_define_method(rb_cHash, "size", rb_hash_size_imp, 0);
+    rb_objc_define_method(rb_cHash, "length", rb_hash_size_imp, 0);
     rb_objc_define_method(rb_cHash, "empty?", rb_hash_empty_p, 0);
 
     rb_objc_define_method(rb_cHash, "each_value", rb_hash_each_value, 0);
@@ -2631,6 +2934,28 @@
     rb_objc_define_method(rb_cHash, "compare_by_identity", rb_hash_compare_by_id, 0);
     rb_objc_define_method(rb_cHash, "compare_by_identity?", rb_hash_compare_by_id_p, 0);
 
+    rb_cRubyHash = rb_define_class("RubyHash", rb_cNSMutableHash);
+    rb_objc_define_method(*(VALUE *)rb_cRubyHash, "alloc", hash_alloc, 0);
+    rb_objc_install_method2((Class)rb_cRubyHash, "count",
+	    (IMP)imp_rhash_count);
+    rb_objc_install_method2((Class)rb_cRubyHash, "objectForKey:",
+	    (IMP)imp_rhash_objectForKey);
+    rb_objc_install_method2((Class)rb_cRubyHash, "keyEnumerator",
+	    (IMP)imp_rhash_keyEnumerator);
+    rb_objc_install_method2((Class)rb_cRubyHash, "setObject:forKey:",
+	    (IMP)imp_rhash_setObjectForKey);
+    rb_objc_install_method2((Class)rb_cRubyHash, "removeObjectForKey:",
+	    (IMP)imp_rhash_removeObjectForKey);
+
+    VALUE NSEnumerator = (VALUE)objc_getClass("NSEnumerator");
+    assert(NSEnumerator != 0);
+    rb_cRubyHashKeyEnumerator = rb_define_class("RubyHashKeyEnumerator",
+	NSEnumerator);
+    rb_objc_install_method2((Class)rb_cRubyHashKeyEnumerator, "allObjects",
+	(IMP)imp_rhash_keyenum_allObjects);
+    rb_objc_install_method2((Class)rb_cRubyHashKeyEnumerator, "nextObject",
+	(IMP)imp_rhash_keyenum_nextObject);
+
     origenviron = environ;
     envtbl = rb_obj_alloc(rb_cObject);
     rb_extend_object(envtbl, rb_mEnumerable);

Modified: MacRuby/trunk/include/ruby/intern.h
===================================================================
--- MacRuby/trunk/include/ruby/intern.h	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/include/ruby/intern.h	2010-01-20 23:49:09 UTC (rev 3315)
@@ -151,6 +151,7 @@
 VALUE rb_objc_create_class(const char *name, VALUE super);
 bool rb_objc_install_primitives(Class ocklass, Class ocsuper);
 void rb_define_object_special_methods(VALUE klass);
+VALUE rb_class_new_instance_imp(VALUE, SEL, int, VALUE *);
 #endif
 VALUE rb_class_boot(VALUE);
 VALUE rb_class_new(VALUE);
@@ -375,6 +376,8 @@
 VALUE rb_hash_has_key(VALUE hash, VALUE key);
 VALUE rb_hash_keys(VALUE hash);
 VALUE rb_hash_set_ifnone(VALUE hash, VALUE ifnone);
+long rb_hash_size(VALUE hash);
+VALUE rb_hash_equal(VALUE hash1, VALUE hash2);
 struct st_table *rb_hash_tbl(VALUE);
 int rb_path_check(const char*);
 int rb_env_path_tainted(void);

Modified: MacRuby/trunk/include/ruby/ruby.h
===================================================================
--- MacRuby/trunk/include/ruby/ruby.h	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/include/ruby/ruby.h	2010-01-20 23:49:09 UTC (rev 3315)
@@ -554,25 +554,12 @@
 # define RCLASS_SCOPE_MOD_FUNC	      (1<<26)  /* class opened for module_function methods */
 # define RCLASS_KVO_CHECK_DONE	      (1<<27)  /* class created by KVO and flags merged */
 # define RCLASS_NO_IV_SLOTS	      (1<<28)  /* class cannot hold ivar slots (T_DATA & friends) */
-# if defined(__LP64__)
-#  define _PTR_TYPE uint64_t
-#  define RCLASS_VERSION(m) (class_getVersion((Class)m))
-#  define RCLASS_SET_VERSION(m,f) (class_setVersion((Class)m, f))
-#  define RCLASS_SET_VERSION_FLAG(m,f) (class_setVersion((Class)m, (RCLASS_VERSION(m) | f)))
-#  define RCLASS_SUPER(m) (*(VALUE *)((_PTR_TYPE)m + (sizeof(void *) * 1)))
-#  define RCLASS_SET_SUPER(m, s) (class_setSuperclass((Class)m, (Class)s))
-#  define RCLASS_META(m) (class_isMetaClass((Class)m))
-#  define RCLASS_RC_FLAGS(m) (*(uint32_t *) ((_PTR_TYPE)(m) + sizeof(uintptr_t) + (sizeof(uint8_t) * 4)))
-# else
-#  define _PTR_TYPE uint32_t
-#  define RCLASS_VERSION(m) (class_getVersion((Class)m))
-#  define RCLASS_SET_VERSION(m,f) (class_setVersion((Class)m, f))
-#  define RCLASS_SET_VERSION_FLAG(m,f) (class_setVersion((Class)m, (RCLASS_VERSION(m) | f)))
-#  define RCLASS_SUPER(m) (*(VALUE *)((_PTR_TYPE)m + (sizeof(void *) * 1)))
-#  define RCLASS_SET_SUPER(m, s) (class_setSuperclass((Class)m, (Class)s))
-#  define RCLASS_META(m) (class_isMetaClass((Class)m))
-#  define RCLASS_RC_FLAGS(m) (*(uint32_t *) ((_PTR_TYPE)(m) + sizeof(uintptr_t) + (sizeof(uint8_t) * 4)))
-# endif
+# define RCLASS_VERSION(m) (class_getVersion((Class)m))
+# define RCLASS_SET_VERSION(m,f) (class_setVersion((Class)m, f))
+# define RCLASS_SET_VERSION_FLAG(m,f) (class_setVersion((Class)m, (RCLASS_VERSION(m) | f)))
+# define RCLASS_SUPER(m) ((VALUE)class_getSuperclass((Class)m))
+# define RCLASS_SET_SUPER(m, s) (class_setSuperclass((Class)m, (Class)s))
+# define RCLASS_META(m) (class_isMetaClass((Class)m))
 # define RCLASS_RUBY(m) ((RCLASS_VERSION(m) & RCLASS_IS_RUBY_CLASS) == RCLASS_IS_RUBY_CLASS)
 # define RCLASS_MODULE(m) ((RCLASS_VERSION(m) & RCLASS_IS_MODULE) == RCLASS_IS_MODULE)
 # define RCLASS_SINGLETON(m) ((RCLASS_VERSION(m) & RCLASS_IS_SINGLETON) == RCLASS_IS_SINGLETON)
@@ -690,7 +677,7 @@
 # define RHASH_IFNONE(h) (RHASH(h)->ifnone)
 # define RHASH_SIZE(h) (RHASH(h)->ntbl ? RHASH(h)->ntbl->num_entries : 0)
 #else
-# define RHASH_SIZE(h) (CFDictionaryGetCount((CFDictionaryRef)h))
+# define RHASH_SIZE(h) rb_hash_size(h)
 #endif
 #define RHASH_EMPTY_P(h) (RHASH_SIZE(h) == 0)
 
@@ -1159,6 +1146,7 @@
 #endif
 RUBY_EXTERN VALUE rb_cNSHash;
 RUBY_EXTERN VALUE rb_cNSMutableHash;
+RUBY_EXTERN VALUE rb_cRubyHash;
 RUBY_EXTERN VALUE rb_cCFSet;
 RUBY_EXTERN VALUE rb_cNSSet;
 RUBY_EXTERN VALUE rb_cNSMutableSet;
@@ -1374,7 +1362,7 @@
 	   ) {
 	    return T_ARRAY;
 	}
-	if (k == (Class)rb_cCFHash) {
+	if (k == (Class)rb_cCFHash || k == (Class)rb_cRubyHash) {
 	    return T_HASH;
 	}
 	if (RCLASS_META(k)) {

Modified: MacRuby/trunk/objc.m
===================================================================
--- MacRuby/trunk/objc.m	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/objc.m	2010-01-20 23:49:09 UTC (rev 3315)
@@ -493,39 +493,27 @@
     return recv;
 }
 
-#define FLAGS_AS_ASSOCIATIVE_REF 1
+static void *__obj_flags; // used as a static key
 
-static CFMutableDictionaryRef __obj_flags;
-
 long
 rb_objc_flag_get_mask(const void *obj)
 {
-#if FLAGS_AS_ASSOCIATIVE_REF
     return (long)rb_objc_get_associative_ref((void *)obj, &__obj_flags);
-#else
-    if (__obj_flags == NULL)
-	return 0;
-
-    return (long)CFDictionaryGetValue(__obj_flags, obj);
-#endif
 }
 
 bool
 rb_objc_flag_check(const void *obj, int flag)
 {
-    long v;
-
-    v = rb_objc_flag_get_mask(obj);
-    if (v == 0)
-	return false;
-
+    const long v = rb_objc_flag_get_mask(obj);
+    if (v == 0) {
+	return false; 
+    }
     return (v & flag) == flag;
 }
 
 void
 rb_objc_flag_set(const void *obj, int flag, bool val)
 {
-#if FLAGS_AS_ASSOCIATIVE_REF
     long v = (long)rb_objc_get_associative_ref((void *)obj, &__obj_flags);
     if (val) {
 	v |= flag;
@@ -534,59 +522,8 @@
 	v ^= flag;
     }
     rb_objc_set_associative_ref((void *)obj, &__obj_flags, (void *)v);
-#else
-    long v;
-
-    if (__obj_flags == NULL) {
-	__obj_flags = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
-    }
-    v = (long)CFDictionaryGetValue(__obj_flags, obj);
-    if (val) {
-	v |= flag;
-    }
-    else {
-	v ^= flag;
-    }
-    CFDictionarySetValue(__obj_flags, obj, (void *)v);
-#endif
 }
 
-long
-rb_objc_remove_flags(const void *obj)
-{
-#if FLAGS_AS_ASSOCIATIVE_REF
-    long flag = (long)rb_objc_get_associative_ref((void *)obj, &__obj_flags);
-    //rb_objc_set_associative_ref((void *)obj, &__obj_flags, (void *)0);
-    return flag;
-#else
-    long flag;
-    if (CFDictionaryGetValueIfPresent(__obj_flags, obj, 
-	(const void **)&flag)) {
-	CFDictionaryRemoveValue(__obj_flags, obj);
-	return flag;
-    }
-    return 0;
-#endif
-}
-
-extern bool __CFStringIsMutable(void *);
-extern bool _CFArrayIsMutable(void *);
-extern bool _CFDictionaryIsMutable(void *);
-
-bool
-rb_objc_is_immutable(VALUE v)
-{
-    switch(TYPE(v)) {
-	case T_STRING:
-	    return !__CFStringIsMutable((void *)v);
-	case T_ARRAY:
-	    return !_CFArrayIsMutable((void *)v);
-	case T_HASH:
-	    return !_CFDictionaryIsMutable((void *)v);	    
-    }
-    return false;
-}
-
 static IMP old_imp_isaForAutonotifying;
 
 static Class

Modified: MacRuby/trunk/object.c
===================================================================
--- MacRuby/trunk/object.c	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/object.c	2010-01-20 23:49:09 UTC (rev 3315)
@@ -165,7 +165,7 @@
     if (cl == rb_cCFArray || cl == rb_cRubyArray) {
 	return rb_cNSMutableArray;
     }
-    if (cl == rb_cCFHash) {
+    if (cl == rb_cCFHash || cl == rb_cRubyHash) {
 	return rb_cNSMutableHash;
     }
     return cl;
@@ -302,9 +302,6 @@
 	    clone = rb_obj_alloc(rb_obj_class(obj));
 	    RBASIC(clone)->klass = rb_singleton_class_clone(obj);
 	    RBASIC(clone)->flags = (RBASIC(obj)->flags | FL_TEST(clone, FL_TAINT)) & ~(FL_FREEZE|FL_FINALIZE);
-//#ifdef __LP64__
-//	    RCLASS_RC_FLAGS(clone) = RCLASS_RC_FLAGS(obj);
-//#endif
 	    break;
     }
 
@@ -782,13 +779,19 @@
  *  Returns <code>true</code> if the object is tainted.
  */
 
+bool rb_klass_is_rary(VALUE klass);
+bool rb_klass_is_rhash(VALUE klass);
+
 static VALUE
 rb_obj_tainted_p(VALUE obj, SEL sel)
 {
     if (!SPECIAL_CONST_P(obj) && NATIVE(obj)) {
 	switch (TYPE(obj)) {
+	    case T_SYMBOL:
+		return Qfalse;
+
 	    case T_ARRAY:
-		if (*(VALUE *)obj != rb_cCFArray) {
+		if (rb_klass_is_rary(*(VALUE *)obj)) {
 		    return RBASIC(obj)->flags & FL_TAINT ? Qtrue : Qfalse;
 		}
 		// fall through
@@ -798,9 +801,9 @@
 		}
 		// fall through
 	    case T_HASH:
-#ifdef __LP64__
-		return (RCLASS_RC_FLAGS(obj) & FL_TAINT) == FL_TAINT ? Qtrue : Qfalse;
-#endif
+		if (rb_klass_is_rhash(*(VALUE *)obj)) {
+		    return RBASIC(obj)->flags & FL_TAINT ? Qtrue : Qfalse;
+		}
 	    default:
 		return rb_objc_flag_check((const void *)obj, FL_TAINT) ? Qtrue : Qfalse;
 	}
@@ -832,8 +835,11 @@
     rb_secure(4);
     if (!SPECIAL_CONST_P(obj) && NATIVE(obj)) {
 	switch (TYPE(obj)) {
+	    case T_SYMBOL:
+		break;
+
 	    case T_ARRAY:
-		if (*(VALUE *)obj != rb_cCFArray) {
+		if (rb_klass_is_rary(*(VALUE *)obj)) {
 		    RBASIC(obj)->flags |= FL_TAINT;
 		    break;
 		}
@@ -845,10 +851,10 @@
 		}
 		// fall through
 	    case T_HASH:
-#ifdef __LP64__
-		RCLASS_RC_FLAGS(obj) |= FL_TAINT;
-		break;
-#endif
+		if (rb_klass_is_rhash(*(VALUE *)obj)) {
+		    RBASIC(obj)->flags |= FL_TAINT;
+		    break;
+		}
 	    default:
 		rb_objc_flag_set((const void *)obj, FL_TAINT, true);
 	}
@@ -883,8 +889,11 @@
     rb_secure(3);
     if (!SPECIAL_CONST_P(obj) && NATIVE(obj)) {
 	switch (TYPE(obj)) {
+	    case T_SYMBOL:
+		break;
+
 	    case T_ARRAY:
-		if (*(VALUE *)obj != rb_cCFArray) {
+		if (rb_klass_is_rary(*(VALUE *)obj)) {
 		    RBASIC(obj)->flags &= ~FL_TAINT;
 		    break;
 		}	
@@ -896,10 +905,10 @@
 		}
 		// fall through
 	    case T_HASH:
-#ifdef __LP64__
-		RCLASS_RC_FLAGS(obj) &= ~FL_TAINT;
-		break;
-#endif
+		if (rb_klass_is_rhash(*(VALUE *)obj)) {
+		    RBASIC(obj)->flags &= ~FL_TAINT;
+		    break;
+		}
 	    default:
 		rb_objc_flag_set((const void *)obj, FL_TAINT, false);
 	}
@@ -925,8 +934,11 @@
 {
     if (!SPECIAL_CONST_P(obj) && NATIVE(obj)) {
 	switch (TYPE(obj)) {
+	    case T_SYMBOL:
+		return Qfalse;
+
 	    case T_ARRAY:
-		if (*(VALUE *)obj != rb_cCFArray) {
+		if (rb_klass_is_rary(*(VALUE *)obj)) {
 		    return RBASIC(obj)->flags & FL_UNTRUSTED ? Qtrue : Qfalse;
 		}
 		// fall through
@@ -936,9 +948,9 @@
 		}
 		// fall through
 	    case T_HASH:
-#ifdef __LP64__
-		return (RCLASS_RC_FLAGS(obj) & FL_UNTRUSTED) == FL_UNTRUSTED ? Qtrue : Qfalse;
-#endif
+		if (rb_klass_is_rhash(*(VALUE *)obj)) {
+		    return RBASIC(obj)->flags & FL_UNTRUSTED ? Qtrue : Qfalse;
+		}
 	    default:
 		return rb_objc_flag_check((const void *)obj, FL_UNTRUSTED) ? Qtrue : Qfalse;
 	}
@@ -961,8 +973,11 @@
     rb_secure(4);
     if (!SPECIAL_CONST_P(obj) && NATIVE(obj)) {
 	switch (TYPE(obj)) {
+	    case T_SYMBOL:
+		break;
+
 	    case T_ARRAY:
-		if (*(VALUE *)obj != rb_cCFArray) {
+		if (rb_klass_is_rary(*(VALUE *)obj)) {
 		    RBASIC(obj)->flags &= ~FL_UNTRUSTED;
 		    break;
 		}
@@ -974,10 +989,10 @@
 		}
 		// fall through
 	    case T_HASH:
-#ifdef __LP64__
-		RCLASS_RC_FLAGS(obj) &= ~FL_UNTRUSTED;
-		break;
-#endif
+		if (rb_klass_is_rhash(*(VALUE *)obj)) {
+		    RBASIC(obj)->flags &= ~FL_UNTRUSTED;
+		    break;
+		}
 	    default:
 		rb_objc_flag_set((const void *)obj, FL_UNTRUSTED, false);
 	}
@@ -1004,8 +1019,11 @@
     rb_secure(4);
     if (!SPECIAL_CONST_P(obj) && NATIVE(obj)) {
 	switch (TYPE(obj)) {
+	    case T_SYMBOL:
+		break;
+
 	    case T_ARRAY:
-		if (*(VALUE *)obj != rb_cCFArray) {
+		if (rb_klass_is_rary(*(VALUE *)obj)) {
 		    RBASIC(obj)->flags |= FL_UNTRUSTED;
 		    break;
 		}
@@ -1017,10 +1035,10 @@
 		}
 		// fall through
 	    case T_HASH:
-#ifdef __LP64__
-		RCLASS_RC_FLAGS(obj) |= FL_UNTRUSTED;
-		break;
-#endif
+		if (rb_klass_is_rhash(*(VALUE *)obj)) {
+		    RBASIC(obj)->flags |= FL_UNTRUSTED;
+		    break;
+		}
 	    default:
 		rb_objc_flag_set((const void *)obj, FL_UNTRUSTED, true);
 	}
@@ -1084,12 +1102,15 @@
 	    st_insert(immediate_frozen_tbl, obj, (st_data_t)Qtrue);
 	}
 	else if (NATIVE(obj)) {
-	    switch(TYPE(obj)) {
+	    switch (TYPE(obj)) {
+		case T_SYMBOL:
+		    break;
+
 		case T_ARRAY:
-		    if (*(VALUE *)obj != rb_cCFArray) {
+		    if (rb_klass_is_rary(*(VALUE *)obj)) {
 			RBASIC(obj)->flags |= FL_FREEZE;
 			break;
-		    }	
+		    }
 		    // fall through
 		case T_STRING:
 		    if (*(VALUE *)obj == rb_cByteString) {
@@ -1098,10 +1119,10 @@
 		    }
 		    // fall through
 		case T_HASH:
-#ifdef __LP64__
-		    RCLASS_RC_FLAGS(obj) |= FL_FREEZE;
-		    break;
-#endif
+		    if (rb_klass_is_rhash(*(VALUE *)obj)) {
+			RBASIC(obj)->flags |= FL_FREEZE;
+			break;
+		    }
 		default:
 		    rb_objc_flag_set((const void *)obj, FL_FREEZE, true);
 	    }
@@ -1146,8 +1167,11 @@
 	return Qfalse;
     }
     switch (TYPE(obj)) {
+	case T_SYMBOL:
+	    return Qfalse;
+
 	case T_ARRAY:
-	    if (*(VALUE *)obj != rb_cCFArray) {
+	    if (rb_klass_is_rary(*(VALUE *)obj)) {
 		return RBASIC(obj)->flags & FL_FREEZE ? Qtrue : Qfalse;
 	    }
 	    // fall through
@@ -1157,12 +1181,11 @@
 	    }
 	    // fall through
 	case T_HASH:
-#ifdef __LP64__
-	    return (RCLASS_RC_FLAGS(obj) & FL_FREEZE) == FL_FREEZE ? Qtrue : Qfalse;
-#endif
+	    if (rb_klass_is_rhash(*(VALUE *)obj)) {
+		return RBASIC(obj)->flags & FL_FREEZE ? Qtrue : Qfalse;
+	    }
 	case T_NATIVE:
-	    return rb_objc_is_immutable(obj) 
-		|| rb_objc_flag_check((const void *)obj, FL_FREEZE)
+	    return rb_objc_flag_check((const void *)obj, FL_FREEZE)
 		? Qtrue : Qfalse;
 	case T_CLASS:
 	case T_ICLASS:
@@ -1176,7 +1199,7 @@
 VALUE
 rb_obj_frozen_p(VALUE obj)
 {
-	return rb_obj_frozen(obj, 0);
+    return rb_obj_frozen(obj, 0);
 }
 
 
@@ -1918,6 +1941,9 @@
     if (klass == rb_cNSMutableArray) {
 	klass = rb_cRubyArray;
     }
+    else if (klass == rb_cNSMutableHash) {
+	klass = rb_cRubyHash;
+    }
 
     VALUE obj = rb_obj_alloc0(klass);
 

Modified: MacRuby/trunk/re.c
===================================================================
--- MacRuby/trunk/re.c	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/re.c	2010-01-20 23:49:09 UTC (rev 3315)
@@ -3710,8 +3710,6 @@
  *
  */
 
-VALUE rb_class_new_instance_imp(VALUE, SEL, int, VALUE *);
-
 void
 Init_Regexp(void)
 {

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/marshal/load_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/marshal/load_tags.txt	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/marshal/load_tags.txt	2010-01-20 23:49:09 UTC (rev 3315)
@@ -1,4 +1,6 @@
 critical:Marshal::load calls the proc for recursively visited data
+critical:Marshal::load loads a Hash subclass
+critical:Marshal::load loads an extended_user_hash with a parameter to initialize
 fails:Marshal::load loads an extended Object
 fails:Marshal::load loads a 1...2
 fails:Marshal::load loads a 1..2

Modified: MacRuby/trunk/st.c
===================================================================
--- MacRuby/trunk/st.c	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/st.c	2010-01-20 23:49:09 UTC (rev 3315)
@@ -64,7 +64,10 @@
 #ifdef RUBY
 #define malloc xmalloc
 #define calloc xcalloc
-#define free xfree
+//#define free xfree
+#define free(x) ((void)0)
+void *rb_gc_memmove(void *dst, const void *src, size_t len);
+#define xmemmove rb_gc_memmove
 #endif
 
 #define alloc(type) (type*)malloc((size_t)sizeof(type))
@@ -344,18 +347,18 @@
     entry = alloc(st_table_entry);\
     \
     entry->hash = hash_val;\
-    entry->key = key;\
+    GC_WB(&entry->key, key);\
     GC_WB(&entry->record, value); \
     GC_WB(&entry->next, table->bins[bin_pos]);\
     if ((head = table->head) != 0) {\
-	GC_WB(&entry->fore, head);\
+	entry->fore = head;\
 	(entry->back = head->back)->fore = entry;\
-	GC_WB(&head->back, entry);\
+	head->back = entry;\
     }\
     else {\
-	GC_WB(&table->head, entry);\
-	GC_WB(&entry->fore, entry);\
-	GC_WB(&entry->back, entry);\
+	table->head = entry;\
+	entry->fore = entry;\
+	entry->back = entry;\
     }\
     GC_WB(&table->bins[bin_pos], entry); \
     table->num_entries++;\
@@ -470,21 +473,16 @@
     unsigned int hash_val;
 
     new_table = alloc(st_table);
-    if (new_table == 0) {
-	return 0;
-    }
+    assert(new_table != NULL);
 
     *new_table = *old_table;
     GC_WB(&new_table->bins, (st_table_entry**)
 	Calloc((unsigned)num_bins, sizeof(st_table_entry*)));
 
-    if (new_table->bins == 0) {
-	free(new_table);
-	return 0;
-    }
+    assert(new_table->bins != NULL);
 
     if (old_table->entries_packed) {
-        memcpy(new_table->bins, old_table->bins, sizeof(struct st_table_entry *) * old_table->num_bins);
+        xmemmove(new_table->bins, old_table->bins, sizeof(struct st_table_entry *) * old_table->num_bins);
         return new_table;
     }
 
@@ -493,22 +491,19 @@
 	tail = &new_table->head;
 	do {
 	    entry = alloc(st_table_entry);
-	    if (entry == 0) {
-		st_free_table(new_table);
-		return 0;
-	    }
+	    assert(entry != NULL);
 	    *entry = *ptr;
 	    hash_val = entry->hash % num_bins;
-	    entry->next = new_table->bins[hash_val];
+	    GC_WB(&entry->next, new_table->bins[hash_val]);
 	    GC_WB(&new_table->bins[hash_val], entry);
 	    entry->back = prev;
 	    prev = entry;
-	    GC_WB(tail, entry);
+	    *tail = entry;
 	    tail = &entry->fore;
 	} while ((ptr = ptr->fore) != old_table->head);
 	entry = new_table->head;
 	entry->back = prev;
-	GC_WB(tail, entry);
+	*tail = entry;
     }
 
     return new_table;
@@ -541,7 +536,7 @@
             if ((st_data_t)table->bins[i*2] == *key) {
                 if (value != 0) *value = (st_data_t)table->bins[i*2+1];
                 table->num_entries--;
-                memmove(&table->bins[i*2], &table->bins[(i+1)*2],
+                xmemmove(&table->bins[i*2], &table->bins[(i+1)*2],
                         sizeof(struct st_table_entry*) * 2*(table->num_entries-i));
                 return 1;
             }
@@ -570,20 +565,33 @@
 int
 st_delete_safe(register st_table *table, register st_data_t *key, st_data_t *value, st_data_t never)
 {
-    unsigned int hash_val;
+    st_index_t hash_val;
     register st_table_entry *ptr;
 
+    if (table->entries_packed) {
+        st_index_t i;
+        for (i = 0; i < table->num_entries; i++) {
+            if ((st_data_t)table->bins[i*2] == *key) {
+                if (value != 0) *value = (st_data_t)table->bins[i*2+1];
+                table->bins[i*2] = (void *)never;
+                return 1;
+            }
+        }
+        if (value != 0) *value = 0;
+        return 0;
+    }
+
     hash_val = do_hash_bin(*key, table);
     ptr = table->bins[hash_val];
 
     for (; ptr != 0; ptr = ptr->next) {
-	if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) {
-	    REMOVE_ENTRY(table, ptr);
-	    *key = ptr->key;
-	    if (value != 0) *value = ptr->record;
-	    ptr->key = ptr->record = never;
-	    return 1;
-	}
+        if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) {
+            REMOVE_ENTRY(table, ptr);
+            *key = ptr->key;
+            if (value != 0) *value = ptr->record;
+            ptr->key = ptr->record = never;
+            return 1;
+        }
     }
 
     if (value != 0) *value = 0;
@@ -643,7 +651,7 @@
 		return 0;
 	      case ST_DELETE:
                 table->num_entries--;
-                memmove(&table->bins[i*2], &table->bins[(i+1)*2],
+                xmemmove(&table->bins[i*2], &table->bins[(i+1)*2],
                         sizeof(struct st_table_entry*) * 2*(table->num_entries-i));
                 i--;
                 break;
@@ -723,7 +731,7 @@
 		return 0;
 	      case ST_DELETE:
                 table->num_entries--;
-                memmove(&table->bins[i*2], &table->bins[(i+1)*2],
+                xmemmove(&table->bins[i*2], &table->bins[(i+1)*2],
                         sizeof(struct st_table_entry*) * 2*(table->num_entries-i));
                 break;
             }

Modified: MacRuby/trunk/string.c
===================================================================
--- MacRuby/trunk/string.c	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/string.c	2010-01-20 23:49:09 UTC (rev 3315)
@@ -531,12 +531,7 @@
 static inline void
 str_modifiable(VALUE str)
 {
-    long mask;
-#ifdef __LP64__
-    mask = RCLASS_RC_FLAGS(str);
-#else
-    mask = rb_objc_flag_get_mask((void *)str);
-#endif
+    long mask = rb_objc_flag_get_mask((void *)str);
     if (RSTRING_IMMUTABLE(str)) {
 	mask |= FL_FREEZE;
     }

Modified: MacRuby/trunk/struct.c
===================================================================
--- MacRuby/trunk/struct.c	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/struct.c	2010-01-20 23:49:09 UTC (rev 3315)
@@ -180,8 +180,6 @@
     return Qnil;		/* not reached */
 }
 
-VALUE rb_class_new_instance_imp(VALUE klass, SEL sel, int argc, VALUE *argv);
-
 static VALUE
 make_struct(VALUE name, VALUE members, VALUE klass)
 {

Modified: MacRuby/trunk/time.c
===================================================================
--- MacRuby/trunk/time.c	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/time.c	2010-01-20 23:49:09 UTC (rev 3315)
@@ -2351,7 +2351,6 @@
     rb_include_module(rb_cTime, rb_mComparable);
 
     rb_objc_define_method(*(VALUE *)rb_cTime, "alloc", time_s_alloc, 0);
-    VALUE rb_class_new_instance_imp(VALUE, SEL, int, VALUE *);
     rb_objc_define_method(*(VALUE *)rb_cTime, "now", rb_class_new_instance_imp, -1);
     rb_objc_define_method(*(VALUE *)rb_cTime, "at", time_s_at, -1);
     rb_objc_define_method(*(VALUE *)rb_cTime, "utc", time_s_mkutc, -1);

Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp	2010-01-20 21:44:00 UTC (rev 3314)
+++ MacRuby/trunk/vm.cpp	2010-01-20 23:49:09 UTC (rev 3315)
@@ -4000,7 +4000,9 @@
 void
 rb_iter_break(void)
 {
-    GET_VM()->set_broken_with(Qnil);
+    RoxorVM *vm = GET_VM();
+    GC_RELEASE(vm->get_broken_with());
+    vm->set_broken_with(Qnil);
 }
 
 extern "C"
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100120/454150da/attachment-0001.html>


More information about the macruby-changes mailing list