[前][次][番号順一覧][スレッド一覧]

ruby-changes:2052

From: ko1@a...
Date: 28 Sep 2007 15:22:03 +0900
Subject: [ruby-changes:2052] akr - Ruby:r13543 (trunk): * include/ruby/intern.h: export rb_ivar_foreach.

akr	2007-09-28 15:21:46 +0900 (Fri, 28 Sep 2007)

  New Revision: 13543

  Modified files:
    trunk/ChangeLog
    trunk/class.c
    trunk/error.c
    trunk/eval.c
    trunk/eval_method.ci
    trunk/ext/digest/digest.c
    trunk/gc.c
    trunk/include/ruby/intern.h
    trunk/include/ruby/ruby.h
    trunk/insnhelper.ci
    trunk/insns.def
    trunk/marshal.c
    trunk/object.c
    trunk/proc.c
    trunk/struct.c
    trunk/variable.c
    trunk/vm.c

  Log:
    * include/ruby/intern.h: export rb_ivar_foreach.
    
    * include/ruby/ruby.h: modify struct RObject and RClass for optimizing
      T_OBJECT space.  [ruby-dev:31853]
      (ROBJECT_LEN, ROBJECT_PTR)
      (RCLASS_IV_TBL, RCLASS_M_TBL, RCLASS_SUPER, RCLASS_IV_INDEX_TBL)
      (RMODULE_IV_TBL, RMODULE_M_TBL, RMODULE_SUPER): abstract accessor
      defined.
    
    * variable.c: support the modified RObject and RClass.
    
    * object.c: ditto.
    
    * class.c: ditto.
    
    * gc.c: ditto.
    
    * marshal.c: ditto.
    
    * eval_method.ci: use the abstract accessor.
    
    * insns.def: ditto.
    
    * proc.c: ditto.
    
    * struct.c: ditto.
    
    * eval.c: ditto.
    
    * error.c: ditto.
    
    * vm.c: ditto.
    
    * insnhelper.ci: ditto.
    
    * ext/digest/digest.c: ditto.


  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/insnhelper.ci?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/include/ruby/ruby.h?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/class.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/variable.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/eval_method.ci?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/struct.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/gc.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ext/digest/digest.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/eval.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/proc.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/marshal.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/error.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/vm.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/object.c?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/insns.def?r1=13543&r2=13542
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/include/ruby/intern.h?r1=13543&r2=13542

Index: eval_method.ci
===================================================================
--- eval_method.ci	(revision 13542)
+++ eval_method.ci	(revision 13543)
@@ -143,7 +143,7 @@
 	st_data_t data;
 	NODE *old_node;
 
-	if (st_lookup(RCLASS(klass)->m_tbl, mid, &data)) {
+	if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) {
 	    old_node = (NODE *)data;
 	    if (old_node) {
 		if (nd_type(old_node->nd_body->nd_body) == NODE_CFUNC) {
@@ -166,7 +166,7 @@
 	}
     }
 
-    st_insert(RCLASS(klass)->m_tbl, mid, (st_data_t) body);
+    st_insert(RCLASS_M_TBL(klass), mid, (st_data_t) body);
 
     if (node && mid != ID_ALLOCATOR && ruby_running) {
 	if (FL_TEST(klass, FL_SINGLETON)) {
@@ -216,8 +216,8 @@
 	return 0;
     }
 
-    while (!st_lookup(RCLASS(klass)->m_tbl, id, &body)) {
-	klass = RCLASS(klass)->super;
+    while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) {
+	klass = RCLASS_SUPER(klass);
 	if (!klass)
 	    return 0;
     }
@@ -305,11 +305,11 @@
     if (mid == object_id || mid == __send || mid == __send_bang || mid == init) {
 	rb_warn("removing `%s' may cause serious problem", rb_id2name(mid));
     }
-    if (st_lookup(RCLASS(klass)->m_tbl, mid, &data)) {
+    if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) {
 	body = (NODE *)data;
 	if (!body || !body->nd_body) body = 0;
 	else {
-	    st_delete(RCLASS(klass)->m_tbl, &mid, &data);
+	    st_delete(RCLASS_M_TBL(klass), &mid, &data);
 	}
     }
     if (!body) {
@@ -583,7 +583,7 @@
 
     orig_fbody->nd_cnt++;
 
-    if (st_lookup(RCLASS(klass)->m_tbl, name, &data)) {
+    if (st_lookup(RCLASS_M_TBL(klass), name, &data)) {
 	node = (NODE *)data;
 	if (node) {
 	    if (RTEST(ruby_verbose) && node->nd_cnt == 0 && node->nd_body) {
@@ -595,7 +595,7 @@
 	}
     }
 
-    st_insert(RCLASS(klass)->m_tbl, name,
+    st_insert(RCLASS_M_TBL(klass), name,
 	      (st_data_t) NEW_FBODY(
 		  NEW_METHOD(orig_fbody->nd_body->nd_body,
 			     orig_fbody->nd_body->nd_clss,
Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 13542)
+++ include/ruby/intern.h	(revision 13543)
@@ -583,6 +583,7 @@
 VALUE rb_ivar_get(VALUE, ID);
 VALUE rb_ivar_set(VALUE, ID, VALUE);
 VALUE rb_ivar_defined(VALUE, ID);
+void rb_ivar_foreach(VALUE, int (*)(ANYARGS), st_data_t);
 VALUE rb_iv_set(VALUE, const char*, VALUE);
 VALUE rb_iv_get(VALUE, const char*);
 VALUE rb_attr_get(VALUE, ID);
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 13542)
+++ include/ruby/ruby.h	(revision 13543)
@@ -402,10 +402,26 @@
     VALUE klass;
 };
 
+#define ROBJECT_EMBED_LEN_MAX 3
 struct RObject {
     struct RBasic basic;
-    struct st_table *iv_tbl;
+    union {
+	struct {
+	    long len;
+	    VALUE *ptr;
+	} heap;
+	VALUE ary[ROBJECT_EMBED_LEN_MAX];
+    } as;
 };
+#define ROBJECT_EMBED FL_USER1
+#define ROBJECT_LEN(o) \
+    ((RBASIC(o)->flags & ROBJECT_EMBED) ? \
+     ROBJECT_EMBED_LEN_MAX : \
+     ROBJECT(o)->as.heap.len)
+#define ROBJECT_PTR(o) \
+    ((RBASIC(o)->flags & ROBJECT_EMBED) ? \
+     ROBJECT(o)->as.ary : \
+     ROBJECT(o)->as.heap.ptr)
 
 struct RValues {
     struct RBasic basic;
@@ -414,12 +430,24 @@
     VALUE v3;
 };
 
+typedef struct {
+    struct st_table *iv_tbl;
+    VALUE super;
+} rb_classext_t;
+
 struct RClass {
     struct RBasic basic;
-    struct st_table *iv_tbl;
+    rb_classext_t *ptr;
     struct st_table *m_tbl;
-    VALUE super;
+    struct st_table *iv_index_tbl;
 };
+#define RCLASS_IV_TBL(c) (RCLASS(c)->ptr->iv_tbl)
+#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
+#define RCLASS_SUPER(c) (RCLASS(c)->ptr->super)
+#define RCLASS_IV_INDEX_TBL(c) (RCLASS(c)->iv_index_tbl)
+#define RMODULE_IV_TBL(m) RCLASS_IV_TBL(m)
+#define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
+#define RMODULE_SUPER(m) RCLASS_SUPER(m)
 
 struct RFloat {
     struct RBasic basic;
Index: insns.def
===================================================================
--- insns.def	(revision 13542)
+++ insns.def	(revision 13543)
@@ -973,7 +973,7 @@
 
 	    if (super != rb_cObject) {
 		VALUE tmp;
-		tmp = rb_class_real(RCLASS(klass)->super);
+		tmp = rb_class_real(RCLASS_SUPER(klass));
 
 		if (tmp != super) {
 		    rb_raise(rb_eTypeError, "superclass mismatch for class %s",
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 13542)
+++ ChangeLog	(revision 13543)
@@ -1,3 +1,42 @@
+Fri Sep 28 15:05:24 2007  Tanaka Akira  <akr@f...>
+
+	* include/ruby/intern.h: export rb_ivar_foreach.
+
+	* include/ruby/ruby.h: modify struct RObject and RClass for optimizing
+	  T_OBJECT space.  [ruby-dev:31853]
+	  (ROBJECT_LEN, ROBJECT_PTR)
+	  (RCLASS_IV_TBL, RCLASS_M_TBL, RCLASS_SUPER, RCLASS_IV_INDEX_TBL)
+	  (RMODULE_IV_TBL, RMODULE_M_TBL, RMODULE_SUPER): abstract accessor
+	  defined.
+
+	* variable.c: support the modified RObject and RClass.
+
+	* object.c: ditto.
+
+	* class.c: ditto.
+
+	* gc.c: ditto.
+
+	* marshal.c: ditto.
+
+	* eval_method.ci: use the abstract accessor.
+
+	* insns.def: ditto.
+
+	* proc.c: ditto.
+
+	* struct.c: ditto.
+
+	* eval.c: ditto.
+
+	* error.c: ditto.
+
+	* vm.c: ditto.
+
+	* insnhelper.ci: ditto.
+
+	* ext/digest/digest.c: ditto.
+
 Fri Sep 28 13:20:10 2007  Nobuyoshi Nakada  <nobu@r...>
 
 	* io.c (rb_io_getline_fast, rb_io_getline_1): set encoding to the
Index: variable.c
===================================================================
--- variable.c	(revision 13542)
+++ variable.c	(revision 13543)
@@ -48,8 +48,8 @@
     path = rb_str_new2(rb_id2name(name));
     while (fc) {
 	if (fc->track == rb_cObject) break;
-	if (ROBJECT(fc->track)->iv_tbl &&
-	    st_lookup(ROBJECT(fc->track)->iv_tbl, classpath, &tmp)) {
+	if (RCLASS_IV_TBL(fc->track) &&
+	    st_lookup(RCLASS_IV_TBL(fc->track), classpath, &tmp)) {
 	    tmp = rb_str_dup(tmp);
 	    rb_str_cat2(tmp, "::");
 	    rb_str_append(tmp, path);
@@ -78,7 +78,7 @@
     switch (TYPE(value)) {
       case T_MODULE:
       case T_CLASS:
-	if (!RCLASS(value)->iv_tbl) return ST_CONTINUE;
+	if (!RCLASS_IV_TBL(value)) return ST_CONTINUE;
 	else {
 	    struct fc_result arg;
 	    struct fc_result *list;
@@ -94,7 +94,7 @@
 	    arg.klass = res->klass;
 	    arg.track = value;
 	    arg.prev = res;
-	    st_foreach(RCLASS(value)->iv_tbl, fc_i, (st_data_t)&arg);
+	    st_foreach(RCLASS_IV_TBL(value), fc_i, (st_data_t)&arg);
 	    if (arg.path) {
 		res->path = arg.path;
 		return ST_STOP;
@@ -118,18 +118,18 @@
     arg.klass = klass;
     arg.track = rb_cObject;
     arg.prev = 0;
-    if (RCLASS(rb_cObject)->iv_tbl) {
-	st_foreach_safe(RCLASS(rb_cObject)->iv_tbl, fc_i, (st_data_t)&arg);
+    if (RCLASS_IV_TBL(rb_cObject)) {
+	st_foreach_safe(RCLASS_IV_TBL(rb_cObject), fc_i, (st_data_t)&arg);
     }
     if (arg.path == 0) {
 	st_foreach_safe(rb_class_tbl, fc_i, (st_data_t)&arg);
     }
     if (arg.path) {
-	if (!ROBJECT(klass)->iv_tbl) {
-	    ROBJECT(klass)->iv_tbl = st_init_numtable();
+	if (!RCLASS_IV_TBL(klass)) {
+	    RCLASS_IV_TBL(klass) = st_init_numtable();
 	}
-	st_insert(ROBJECT(klass)->iv_tbl, classpath, arg.path);
-	st_delete(RCLASS(klass)->iv_tbl, &tmp_classpath, 0);
+	st_insert(RCLASS_IV_TBL(klass), classpath, arg.path);
+	st_delete(RCLASS_IV_TBL(klass), &tmp_classpath, 0);
 	return arg.path;
     }
     return Qnil;
@@ -141,17 +141,17 @@
     VALUE path = Qnil;
 
     if (!klass) klass = rb_cObject;
-    if (ROBJECT(klass)->iv_tbl) {
-	if (!st_lookup(ROBJECT(klass)->iv_tbl, classpath, &path)) {
+    if (RCLASS_IV_TBL(klass)) {
+	if (!st_lookup(RCLASS_IV_TBL(klass), classpath, &path)) {
 	    ID classid = rb_intern("__classid__");
 
-	    if (!st_lookup(ROBJECT(klass)->iv_tbl, classid, &path)) {
+	    if (!st_lookup(RCLASS_IV_TBL(klass), classid, &path)) {
 		return find_class_path(klass);
 	    }
 	    path = rb_str_new2(rb_id2name(SYM2ID(path)));
 	    OBJ_FREEZE(path);
-	    st_insert(ROBJECT(klass)->iv_tbl, classpath, path);
-	    st_delete(RCLASS(klass)->iv_tbl, (st_data_t*)&classid, 0);
+	    st_insert(RCLASS_IV_TBL(klass), classpath, path);
+	    st_delete(RCLASS_IV_TBL(klass), (st_data_t*)&classid, 0);
 	}
 	if (TYPE(path) != T_STRING) {
 	    rb_bug("class path is not set properly");
@@ -183,7 +183,7 @@
     VALUE path = classname(klass);
 
     if (!NIL_P(path)) return path;
-    if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl,
+    if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),
 					   tmp_classpath, &path)) {
 	return path;
     }
@@ -926,12 +926,22 @@
 ivar_get(VALUE obj, ID id, int warn)
 {
     VALUE val;
+    VALUE klass;
+    st_data_t index;
 
     switch (TYPE(obj)) {
       case T_OBJECT:
+        klass = rb_obj_class(obj);
+        if (!RCLASS_IV_INDEX_TBL(klass)) break; 
+        if (!st_lookup(RCLASS_IV_INDEX_TBL(klass), id, &index)) break;
+        if (ROBJECT_LEN(obj) <= index) break;
+        val = ROBJECT_PTR(obj)[index];
+        if (val != Qundef)
+            return val;
+	break;
       case T_CLASS:
       case T_MODULE:
-	if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, &val))
+	if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), id, &val))
 	    return val;
 	break;
       default:
@@ -960,16 +970,63 @@
 VALUE
 rb_ivar_set(VALUE obj, ID id, VALUE val)
 {
+    VALUE klass;
+    st_data_t index;
+    long i, len;
+    int ivar_extended;
+
     if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
     if (OBJ_FROZEN(obj)) rb_error_frozen("object");
     switch (TYPE(obj)) {
       case T_OBJECT:
+        klass = rb_obj_class(obj);
+        if (!RCLASS_IV_INDEX_TBL(klass))
+            RCLASS_IV_INDEX_TBL(klass) = st_init_numtable();
+        ivar_extended = 0;
+        if (!st_lookup(RCLASS_IV_INDEX_TBL(klass), id, &index)) {
+            index = RCLASS_IV_INDEX_TBL(klass)->num_entries;
+            st_add_direct(RCLASS_IV_INDEX_TBL(klass), id, index);
+            ivar_extended = 1;
+        }
+        len = ROBJECT_LEN(obj);
+        if (len <= index) {
+            VALUE *ptr = ROBJECT_PTR(obj);
+            if (index < ROBJECT_EMBED_LEN_MAX) {
+                RBASIC(obj)->flags |= ROBJECT_EMBED;
+                ptr = ROBJECT(obj)->as.ary;
+                for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) {
+                    ptr[i] = Qundef;
+                }
+            }
+            else {
+                VALUE *newptr;
+                long newsize = (index+1) + (index+1)/4; /* (index+1)*1.25 */
+                if (!ivar_extended &&
+                    RCLASS_IV_INDEX_TBL(klass)->num_entries < newsize) {
+                    newsize = RCLASS_IV_INDEX_TBL(klass)->num_entries;
+                }
+                if (RBASIC(obj)->flags & ROBJECT_EMBED) {
+                    newptr = ALLOC_N(VALUE, newsize);
+                    MEMCPY(newptr, ptr, VALUE, len);
+                    RBASIC(obj)->flags &= ~ROBJECT_EMBED;
+                    ROBJECT(obj)->as.heap.ptr = newptr;
+                }
+                else {
+                    REALLOC_N(ROBJECT(obj)->as.heap.ptr, VALUE, newsize);
+                    newptr = ROBJECT(obj)->as.heap.ptr;
+                }
+                for (; len < newsize; len++)
+                    newptr[len] = Qundef;
+                ROBJECT(obj)->as.heap.len = newsize;
+            }
+        }
+        ROBJECT_PTR(obj)[index] = val;
+	break;
       case T_CLASS:
       case T_MODULE:
-	if (!ROBJECT(obj)->iv_tbl) ROBJECT(obj)->iv_tbl = st_init_numtable();
-	st_insert(ROBJECT(obj)->iv_tbl, id, val);
-	break;
+	if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();
+	st_insert(RCLASS_IV_TBL(obj), id, val);
       default:
 	generic_ivar_set(obj, id, val);
 	break;
@@ -980,11 +1037,21 @@
 VALUE
 rb_ivar_defined(VALUE obj, ID id)
 {
+    VALUE klass, val;
+    st_data_t index;
     switch (TYPE(obj)) {
       case T_OBJECT:
+        klass = rb_obj_class(obj);
+        if (!RCLASS_IV_INDEX_TBL(klass)) break; 
+        if (!st_lookup(RCLASS_IV_INDEX_TBL(klass), id, &index)) break;
+        if (ROBJECT_LEN(obj) <= index) break;
+        val = ROBJECT_PTR(obj)[index];
+        if (val != Qundef)
+            return Qtrue;
+	break;
       case T_CLASS:
       case T_MODULE:
-	if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, 0))
+	if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), id, 0))
 	    return Qtrue;
 	break;
       default:
@@ -995,9 +1062,70 @@
     return Qfalse;
 }
 
+struct obj_ivar_tag {
+    VALUE obj;
+    int (*func)(ID key, VALUE val, st_data_t arg);
+    st_data_t arg;
+};
+
 static int
-ivar_i(ID key, struct global_entry *entry, VALUE ary)
+obj_ivar_i(ID key, VALUE index, struct obj_ivar_tag *data)
 {
+    if (index < ROBJECT_LEN(data->obj)) {
+        VALUE val = ROBJECT_PTR(data->obj)[index];
+        if (val != Qundef) {
+            return (data->func)(key, val, data->arg);
+        }
+    }
+    return ST_CONTINUE;
+}
+
+static void
+obj_ivar_each(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
+{
+    VALUE klass = rb_obj_class(obj);
+    st_table *tbl;
+    struct obj_ivar_tag data;
+
+    tbl = RCLASS_IV_INDEX_TBL(klass);
+    if (!tbl)
+        return;
+
+    data.obj = obj;
+    data.func = func;
+    data.arg = arg;
+
+    st_foreach_safe(tbl, obj_ivar_i, (st_data_t)&data);
+}
+
+void rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
+{
+    switch (TYPE(obj)) {
+      case T_OBJECT:
+        obj_ivar_each(obj, func, arg);
+	break;
+      case T_CLASS:
+      case T_MODULE:
+	if (RCLASS_IV_TBL(obj)) {
+	    st_foreach_safe(RCLASS_IV_TBL(obj), func, arg);
+	}
+	break;
+      default:
+	if (!generic_iv_tbl) break;
+	if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
+	    st_data_t tbl;
+
+	    if (st_lookup(generic_iv_tbl, obj, &tbl)) {
+		st_foreach_safe((st_table *)tbl, func, arg);
+	    }
+	}
+	break;
+    }
+}
+
+static int
+ivar_i(ID key, VALUE val, VALUE ary)
+{
     if (rb_is_instance_id(key)) {
 	rb_ary_push(ary, ID2SYM(key));
     }
@@ -1027,25 +1155,7 @@
     VALUE ary;
 
     ary = rb_ary_new();
-    switch (TYPE(obj)) {
-      case T_OBJECT:
-      case T_CLASS:
-      case T_MODULE:
-	if (ROBJECT(obj)->iv_tbl) {
-	    st_foreach_safe(ROBJECT(obj)->iv_tbl, ivar_i, ary);
-	}
-	break;
-      default:
-	if (!generic_iv_tbl) break;
-	if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
-	    st_data_t tbl;
-
-	    if (st_lookup(generic_iv_tbl, obj, &tbl)) {
-		st_foreach_safe((st_table *)tbl, ivar_i, ary);
-	    }
-	}
-	break;
-    }
+    rb_ivar_foreach(obj, ivar_i, ary);
     return ary;
 }
 
@@ -1076,6 +1186,8 @@
 {
     VALUE val = Qnil;
     ID id = rb_to_id(name);
+    VALUE klass;
+    st_data_t index;
 
     if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
@@ -1086,9 +1198,19 @@
 
     switch (TYPE(obj)) {
       case T_OBJECT:
+        klass = rb_obj_class(obj);
+        if (!RCLASS_IV_INDEX_TBL(klass)) break; 
+        if (!st_lookup(RCLASS_IV_INDEX_TBL(klass), id, &index)) break;
+        if (ROBJECT_LEN(obj) <= index) break;
+        val = ROBJECT_PTR(obj)[index];
+        if (val != Qundef) {
+            ROBJECT_PTR(obj)[index] = Qundef;
+            return val;
+        }
+	break;
       case T_CLASS:
       case T_MODULE:
-	if (ROBJECT(obj)->iv_tbl && st_delete(ROBJECT(obj)->iv_tbl, (st_data_t*)&id, &val)) {
+	if (RCLASS_IV_TBL(obj) && st_delete(RCLASS_IV_TBL(obj), (st_data_t*)&id, &val)) {
 	    return val;
 	}
 	break;
@@ -1185,11 +1307,11 @@
 	rb_raise(rb_eArgError, "empty file name");
     }
 
-    if ((tbl = RCLASS(mod)->iv_tbl) && st_lookup(tbl, id, &av) && av != Qundef)
+    if ((tbl = RCLASS_IV_TBL(mod)) && st_lookup(tbl, id, &av) && av != Qundef)
 	return;
 
     rb_const_set(mod, id, Qundef);
-    tbl = RCLASS(mod)->iv_tbl;
+    tbl = RCLASS_IV_TBL(mod);
     if (st_lookup(tbl, autoload, &av)) {
 	tbl = check_autoload_table(av);
     }
@@ -1210,8 +1332,8 @@
     VALUE val;
     st_data_t load = 0;
 
-    st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, 0);
-    if (st_lookup(RCLASS(mod)->iv_tbl, autoload, &val)) {
+    st_delete(RCLASS_IV_TBL(mod), (st_data_t*)&id, 0);
+    if (st_lookup(RCLASS_IV_TBL(mod), autoload, &val)) {
 	struct st_table *tbl = check_autoload_table(val);
 
 	st_delete(tbl, (st_data_t*)&id, &load);
@@ -1220,7 +1342,7 @@
 	    DATA_PTR(val) = 0;
 	    st_free_table(tbl);
 	    id = autoload;
-	    if (st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, &val)) {
+	    if (st_delete(RCLASS_IV_TBL(mod), (st_data_t*)&id, &val)) {
 		rb_gc_force_recycle(val);
 	    }
 	}
@@ -1248,7 +1370,7 @@
     struct st_table *tbl;
     st_data_t load;
 
-    if (!st_lookup(RCLASS(mod)->iv_tbl, autoload, &val) ||
+    if (!st_lookup(RCLASS_IV_TBL(mod), autoload, &val) ||
 	!(tbl = check_autoload_table(val)) || !st_lookup(tbl, id, &load)) {
 	return Qnil;
     }
@@ -1267,7 +1389,7 @@
 	DATA_PTR(val) = 0;
 	st_free_table(tbl);
 	id = autoload;
-	if (st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, &val)) {
+	if (st_delete(RCLASS_IV_TBL(mod), (st_data_t*)&id, &val)) {
 	    rb_gc_force_recycle(val);
 	}
     }
@@ -1277,7 +1399,7 @@
 VALUE
 rb_autoload_p(VALUE mod, ID id)
 {
-    struct st_table *tbl = RCLASS(mod)->iv_tbl;
+    struct st_table *tbl = RCLASS_IV_TBL(mod);
     VALUE val;
 
     if (!tbl || !st_lookup(tbl, id, &val) || val != Qundef) {
@@ -1295,7 +1417,7 @@
     tmp = klass;
   retry:
     while (tmp && !NIL_P(tmp)) {
-	while (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
+	while (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp),id,&value)) {
 	    if (value == Qundef) {
 		if (!RTEST(rb_autoload_load(tmp, id))) break;
 		continue;
@@ -1307,7 +1429,7 @@
 	    return value;
 	}
 	if (!recurse && klass != rb_cObject) break;
-	tmp = RCLASS(tmp)->super;
+	tmp = RCLASS_SUPER(tmp);
     }
     if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
 	mod_retry = 1;
@@ -1360,7 +1482,7 @@
 	rb_raise(rb_eSecurityError, "Insecure: can't remove constant");
     if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
 
-    if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, (st_data_t*)&id, &val)) {
+    if (RCLASS_IV_TBL(mod) && st_delete(RCLASS_IV_TBL(mod), (st_data_t*)&id, &val)) {
 	if (val == Qundef) {
 	    autoload_delete(mod, id);
 	    val = Qnil;
@@ -1394,8 +1516,8 @@
     if (!tbl) {
 	tbl = st_init_numtable();
     }
-    if (RCLASS(mod)->iv_tbl) {
-	st_foreach_safe(RCLASS(mod)->iv_tbl, sv_i, (st_data_t)tbl);
+    if (RCLASS_IV_TBL(mod)) {
+	st_foreach_safe(RCLASS_IV_TBL(mod), sv_i, (st_data_t)tbl);
     }
     return tbl;
 }
@@ -1406,7 +1528,7 @@
     VALUE tmp = mod;
     for (;;) {
 	data = rb_mod_const_at(tmp, data);
-	tmp = RCLASS(tmp)->super;
+	tmp = RCLASS_SUPER(tmp);
 	if (!tmp) break;
 	if (tmp == rb_cObject && mod != rb_cObject) break;
     }
@@ -1479,13 +1601,13 @@
     tmp = klass;
   retry:
     while (tmp) {
-	if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl, id, &value)) {
+	if (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp), id, &value)) {
 	    if (value == Qundef && NIL_P(autoload_file(klass, id)))
 		return Qfalse;
 	    return Qtrue;
 	}
 	if (!recurse && klass != rb_cObject) break;
-	tmp = RCLASS(tmp)->super;
+	tmp = RCLASS_SUPER(tmp);
     }
     if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
 	mod_retry = 1;
@@ -1528,13 +1650,13 @@
 	    rb_error_frozen("class");
 	}
     }
-    if (!RCLASS(klass)->iv_tbl) {
-	RCLASS(klass)->iv_tbl = st_init_numtable();
+    if (!RCLASS_IV_TBL(klass)) {
+	RCLASS_IV_TBL(klass) = st_init_numtable();
     }
     else if (isconst) {
 	VALUE value = Qfalse;
 
-	if (st_lookup(RCLASS(klass)->iv_tbl, id, &value)) {
+	if (st_lookup(RCLASS_IV_TBL(klass), id, &value)) {
 	    if (value == Qundef)
 	      autoload_delete(klass, id);
 	    else
@@ -1545,7 +1667,7 @@
     if(isconst){
 	rb_vm_change_state();
     }
-    st_insert(RCLASS(klass)->iv_tbl, id, val);
+    st_insert(RCLASS_IV_TBL(klass), id, val);
 }
 
 void
@@ -1585,7 +1707,7 @@
 }
 
 #define CVAR_LOOKUP(v,r) do {\
-    if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl,id,(v))) {\
+    if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),id,(v))) {\
 	return (r);\
     }\
     if (FL_TEST(klass, FL_SINGLETON) ) {\
@@ -1596,18 +1718,18 @@
 	    klass = obj;\
 	    break;\
 	  default:\
-	    klass = RCLASS(klass)->super;\
+	    klass = RCLASS_SUPER(klass);\
 	    break;\
 	}\
     }\
     else {\
-	klass = RCLASS(klass)->super;\
+	klass = RCLASS_SUPER(klass);\
     }\
     while (klass) {\
-	if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl,id,(v))) {\
+	if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),id,(v))) {\
 	    return (r);\
 	}\
-	klass = RCLASS(klass)->super;\
+	klass = RCLASS_SUPER(klass);\
     }\
 } while(0)
 
@@ -1695,8 +1817,8 @@
 {
     VALUE ary = rb_ary_new();
 
-    if (RCLASS(obj)->iv_tbl) {
-	st_foreach_safe(RCLASS(obj)->iv_tbl, cv_i, ary);
+    if (RCLASS_IV_TBL(obj)) {
+	st_foreach_safe(RCLASS_IV_TBL(obj), cv_i, ary);
     }
     return ary;
 }
@@ -1734,7 +1856,7 @@
 	rb_raise(rb_eSecurityError, "Insecure: can't remove class variable");
     if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
 
-    if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, (st_data_t*)&id, &val)) {
+    if (RCLASS_IV_TBL(mod) && st_delete(RCLASS_IV_TBL(mod), (st_data_t*)&id, &val)) {
 	return val;
     }
     if (rb_cvar_defined(mod, id)) {
Index: object.c
===================================================================
--- object.c	(revision 13542)
+++ object.c	(revision 13543)
@@ -100,7 +100,7 @@
 rb_class_real(VALUE cl)
 {
     while (FL_TEST(cl, FL_SINGLETON) || TYPE(cl) == T_ICLASS) {
-	cl = RCLASS(cl)->super;
+	cl = RCLASS_SUPER(cl);
     }
     return cl;
 }
@@ -137,15 +137,34 @@
     rb_gc_copy_finalizer(dest, obj);
     switch (TYPE(obj)) {
       case T_OBJECT:
+        if (!(RBASIC(dest)->flags & ROBJECT_EMBED) && ROBJECT_PTR(dest)) {
+            xfree(ROBJECT_PTR(dest));
+            ROBJECT(dest)->as.heap.ptr = 0;
+            ROBJECT(dest)->as.heap.len = 0;
+        }
+        if (RBASIC(obj)->flags & ROBJECT_EMBED) {
+            MEMCPY(ROBJECT(dest)->as.ary, ROBJECT(obj)->as.ary, VALUE, ROBJECT_EMBED_LEN_MAX);
+            RBASIC(dest)->flags |= ROBJECT_EMBED;
+        }
+        else {
+            long len = ROBJECT(obj)->as.heap.len;
+            VALUE *ptr = ALLOC_N(VALUE, len);
+            MEMCPY(ptr, ROBJECT(obj)->as.heap.ptr, VALUE, len);
+            ROBJECT(dest)->as.heap.ptr = ptr;
+            ROBJECT(dest)->as.heap.len = len;
+            RBASIC(dest)->flags &= ~ROBJECT_EMBED;
+        }
+        break;
       case T_CLASS:
       case T_MODULE:
-	if (ROBJECT(dest)->iv_tbl) {
-	    st_free_table(ROBJECT(dest)->iv_tbl);
-	    ROBJECT(dest)->iv_tbl = 0;
+	if (RCLASS_IV_TBL(dest)) {
+	    st_free_table(RCLASS_IV_TBL(dest));
+	    RCLASS_IV_TBL(dest) = 0;
 	}
-	if (ROBJECT(obj)->iv_tbl) {
-	    ROBJECT(dest)->iv_tbl = st_copy(ROBJECT(obj)->iv_tbl);
+	if (RCLASS_IV_TBL(obj)) {
+	    RCLASS_IV_TBL(dest) = st_copy(RCLASS_IV_TBL(obj));
 	}
+        break;
     }
     rb_funcall(dest, id_init_copy, 1, obj);
 }
@@ -296,7 +315,7 @@
 	rb_str_cat2(str, " ...");
     }
     else {
-	st_foreach_safe(ROBJECT(obj)->iv_tbl, inspect_i, str);
+	rb_ivar_foreach(obj, inspect_i, str);
     }
     rb_str_cat2(str, ">");
     RSTRING_PTR(str)[0] = '#';
@@ -321,15 +340,28 @@
 static VALUE
 rb_obj_inspect(VALUE obj)
 {
-    if (TYPE(obj) == T_OBJECT
-	&& ROBJECT(obj)->iv_tbl
-	&& ROBJECT(obj)->iv_tbl->num_entries > 0) {
-	VALUE str;
-	char *c;
 
-	c = rb_obj_classname(obj);
-	str = rb_sprintf("-<%s:%p", c, (void*)obj);
-	return rb_exec_recursive(inspect_obj, obj, str);
+    if (TYPE(obj) == T_OBJECT) {
+        int has_ivar = 0;
+        VALUE *ptr = ROBJECT_PTR(obj);
+        long len = ROBJECT_LEN(obj);
+        long i;
+
+        for (i = 0; i < len; i++) {
+            if (ptr[i] != Qundef) {
+                has_ivar = 1;
+                break;
+            }
+        }
+
+        if (has_ivar) {
+            VALUE str;
+            char *c;
+
+            c = rb_obj_classname(obj);
+            str = rb_sprintf("-<%s:%p", c, (void*)obj);
+            return rb_exec_recursive(inspect_obj, obj, str);
+        }
     }
     return rb_funcall(obj, rb_intern("to_s"), 0, 0);
 }
@@ -402,9 +434,9 @@
     }
 
     while (cl) {
-	if (cl == c || RCLASS(cl)->m_tbl == RCLASS(c)->m_tbl)
+	if (cl == c || RCLASS_M_TBL(cl) == RCLASS_M_TBL(c))
 	    return Qtrue;
-	cl = RCLASS(cl)->super;
+	cl = RCLASS_SUPER(cl);
     }
     return Qfalse;
 }
@@ -1104,15 +1136,15 @@
 	rb_raise(rb_eTypeError, "compared with non class/module");
     }
     while (mod) {
-	if (RCLASS(mod)->m_tbl == RCLASS(arg)->m_tbl)
+	if (RCLASS_M_TBL(mod) == RCLASS_M_TBL(arg))
 	    return Qtrue;
-	mod = RCLASS(mod)->super;
+	mod = RCLASS_SUPER(mod);
     }
     /* not mod < arg; check if mod > arg */
     while (arg) {
-	if (RCLASS(arg)->m_tbl == RCLASS(start)->m_tbl)
+	if (RCLASS_M_TBL(arg) == RCLASS_M_TBL(start))
 	    return Qfalse;
-	arg = RCLASS(arg)->super;
+	arg = RCLASS_SUPER(arg);
     }
     return Qnil;
 }
@@ -1277,7 +1309,7 @@
 {
     VALUE super;
 
-    if (RCLASS(klass)->super != 0) {
+    if (RCLASS_SUPER(klass) != 0) {
 	rb_raise(rb_eTypeError, "already initialized class");
     }
     if (rb_scan_args(argc, argv, "01", &super) == 0) {
@@ -1286,7 +1318,7 @@
     else {
 	rb_check_inheritable(super);
     }
-    RCLASS(klass)->super = super;
+    RCLASS_SUPER(klass) = super;
     rb_make_metaclass(klass, RBASIC(super)->klass);
     rb_class_inherited(super, klass);
     rb_mod_initialize(klass);
@@ -1308,7 +1340,7 @@
 {
     VALUE obj;
 
-    if (RCLASS(klass)->super == 0 && klass != rb_cBasicObject) {
+    if (RCLASS_SUPER(klass) == 0 && klass != rb_cBasicObject) {
 	rb_raise(rb_eTypeError, "can't instantiate uninitialized class");
     }
     if (FL_TEST(klass, FL_SINGLETON)) {
@@ -1367,13 +1399,13 @@
 static VALUE
 rb_class_superclass(VALUE klass)
 {
-    VALUE super = RCLASS(klass)->super;
+    VALUE super = RCLASS_SUPER(klass);
 
     if (!super) {
 	rb_raise(rb_eTypeError, "uninitialized class");
     }
     while (TYPE(super) == T_ICLASS) {
-	super = RCLASS(super)->super;
+	super = RCLASS_SUPER(super);
     }
     if (!super) {
 	return Qnil;
Index: proc.c
===================================================================
--- proc.c	(revision 13542)
+++ proc.c	(revision 13543)
@@ -620,13 +620,13 @@
     body = body->nd_body;
 
     if (nd_type(body) == NODE_ZSUPER) {
-	klass = RCLASS(klass)->super;
+	klass = RCLASS_SUPER(klass);
 	goto again;
     }
 
     while (rklass != klass &&
 	   (FL_TEST(rklass, FL_SINGLETON) || TYPE(rklass) == T_ICLASS)) {
-	rklass = RCLASS(rklass)->super;
+	rklass = RCLASS_SUPER(rklass);
     }
     if (TYPE(klass) == T_ICLASS)
 	klass = RBASIC(klass)->klass;
Index: struct.c
===================================================================
--- struct.c	(revision 13542)
+++ struct.c	(revision 13543)
@@ -25,7 +25,7 @@
     for (;;) {
 	if (rb_ivar_defined(c, id))
 	    return rb_ivar_get(c, id);
-	c = RCLASS(c)->super;
+	c = RCLASS_SUPER(c);
 	if (c == 0 || c == rb_cStruct)
 	    return Qnil;
     }
Index: eval.c
===================================================================
--- eval.c	(revision 13542)
+++ eval.c	(revision 13543)
@@ -2303,7 +2303,7 @@
 	    if (nd_type(fbody->nd_body->nd_body) != NODE_ZSUPER) {
 		break;		/* normal case: need not to follow 'super' link */
 	    }
-	    m = RCLASS(m)->super;
+	    m = RCLASS_SUPER(m);
 	    if (!m)
 		break;
 	}
Index: gc.c
===================================================================
--- gc.c	(revision 13542)
+++ gc.c	(revision 13543)
@@ -1033,9 +1033,9 @@
       case T_ICLASS:
       case T_CLASS:
       case T_MODULE:
-	mark_tbl(obj->as.klass.m_tbl, lev);
-	mark_tbl(obj->as.klass.iv_tbl, lev);
-	ptr = obj->as.klass.super;
+	mark_tbl(RCLASS_M_TBL(obj), lev);
+	mark_tbl(RCLASS_IV_TBL(obj), lev);
+	ptr = RCLASS_SUPER(obj);
 	goto again;
 
       case T_ARRAY:
@@ -1070,7 +1070,13 @@
 	break;
 
       case T_OBJECT:
-	mark_tbl(obj->as.object.iv_tbl, lev);
+        {
+            long i, len = ROBJECT_LEN(obj);
+	    VALUE *ptr = ROBJECT_PTR(obj);
+            for (i  = 0; i < len; i++) {
+		gc_mark(*ptr++, lev);
+            }
+        }
 	break;
 
       case T_FILE:
@@ -1269,17 +1275,22 @@
 
     switch (RANY(obj)->as.basic.flags & T_MASK) {
       case T_OBJECT:
-	if (RANY(obj)->as.object.iv_tbl) {
-	    st_free_table(RANY(obj)->as.object.iv_tbl);
+	if (!(RANY(obj)->as.basic.flags & ROBJECT_EMBED) &&
+            RANY(obj)->as.object.as.heap.ptr) {
+	    RUBY_CRITICAL(free(RANY(obj)->as.object.as.heap.ptr));
 	}
 	break;
       case T_MODULE:
       case T_CLASS:
 	rb_clear_cache_by_class((VALUE)obj);
-	st_free_table(RANY(obj)->as.klass.m_tbl);
-	if (RANY(obj)->as.object.iv_tbl) {
-	    st_free_table(RANY(obj)->as.object.iv_tbl);
+	st_free_table(RCLASS_M_TBL(obj));
+	if (RCLASS_IV_TBL(obj)) {
+	    st_free_table(RCLASS_IV_TBL(obj));
 	}
+	if (RCLASS_IV_INDEX_TBL(obj)) {
+	    st_free_table(RCLASS_IV_INDEX_TBL(obj));
+	}
+        RUBY_CRITICAL(free(RANY(obj)->as.klass.ptr));
 	break;
       case T_STRING:
 	rb_str_free(obj);
Index: class.c
===================================================================
--- class.c	(revision 13542)
+++ class.c	(revision 13543)
@@ -18,16 +18,27 @@
 
 extern st_table *rb_class_tbl;
 
+static VALUE
+class_alloc(VALUE flags, VALUE klass)
+{
+    rb_classext_t *ext = ALLOC(rb_classext_t);
+    NEWOBJ(obj, struct RClass);
+    OBJSETUP(obj, klass, flags);
+    obj->ptr = ext;
+    RCLASS_IV_TBL(obj) = 0;
+    RCLASS_M_TBL(obj) = 0;
+    RCLASS_SUPER(obj) = 0;
+    RCLASS_IV_INDEX_TBL(obj) = 0;
+    return (VALUE)obj;
+}
+
 VALUE
 rb_class_boot(VALUE super)
 {
-    NEWOBJ(klass, struct RClass);
-    OBJSETUP(klass, rb_cClass, T_CLASS);
+    VALUE klass = class_alloc(T_CLASS, rb_cClass);
 
-    klass->super = super;
-    klass->iv_tbl = 0;
-    klass->m_tbl = 0;		/* safe GC */
-    klass->m_tbl = st_init_numtable();
+    RCLASS_SUPER(klass) = super;
+    RCLASS_M_TBL(klass) = st_init_numtable();
 
     OBJ_INFECT(klass, super);
     return (VALUE)klass;
@@ -87,21 +98,21 @@
     if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) {
 	RBASIC(clone)->klass = rb_singleton_class_clone(orig);
     }
-    RCLASS(clone)->super = RCLASS(orig)->super;
-    if (RCLASS(orig)->iv_tbl) {
+    RCLASS_SUPER(clone) = RCLASS_SUPER(orig);
+    if (RCLASS_IV_TBL(orig)) {
 	ID id;
 
-	RCLASS(clone)->iv_tbl = st_copy(RCLASS(orig)->iv_tbl);
+	RCLASS_IV_TBL(clone) = st_copy(RCLASS_IV_TBL(orig));
 	id = rb_intern("__classpath__");
-	st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0);
+	st_delete(RCLASS_IV_TBL(clone), (st_data_t*)&id, 0);
 	id = rb_intern("__classid__");
-	st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0);
+	st_delete(RCLASS_IV_TBL(clone), (st_data_t*)&id, 0);
     }
-    if (RCLASS(orig)->m_tbl) {
+    if (RCLASS_M_TBL(orig)) {
 	struct clone_method_data data;
-	data.tbl = RCLASS(clone)->m_tbl = st_init_numtable();
+	data.tbl = RCLASS_M_TBL(clone) = st_init_numtable();
 	data.klass = clone;
-	st_foreach(RCLASS(orig)->m_tbl, clone_method,
+	st_foreach(RCLASS_M_TBL(orig), clone_method,
 	  (st_data_t)&data);
     }
 
@@ -112,7 +123,7 @@
 VALUE
 rb_class_init_copy(VALUE clone, VALUE orig)
 {
-    if (RCLASS(clone)->super != 0) {
+    if (RCLASS_SUPER(clone) != 0) {
 	rb_raise(rb_eTypeError, "already initialized class");
     }
     if (FL_TEST(orig, FL_SINGLETON)) {
@@ -131,8 +142,7 @@
     else {
 	struct clone_method_data data;
 	/* copy singleton(unnamed) class */
-	NEWOBJ(clone, struct RClass);
-	OBJSETUP(clone, 0, RBASIC(klass)->flags);
+        VALUE clone = class_alloc(RBASIC(klass)->flags, 0);
 
 	if (BUILTIN_TYPE(obj) == T_CLASS) {
 	    RBASIC(clone)->klass = (VALUE)clone;
@@ -141,16 +151,14 @@
 	    RBASIC(clone)->klass = rb_singleton_class_clone(klass);
 	}
 
-	clone->super = RCLASS(klass)->super;
-	clone->iv_tbl = 0;
-	clone->m_tbl = 0;
-	if (RCLASS(klass)->iv_tbl) {
-	    clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl);
+	RCLASS_SUPER(clone) = RCLASS_SUPER(klass);
+	if (RCLASS_IV_TBL(klass)) {
+	    RCLASS_IV_TBL(clone) = st_copy(RCLASS_IV_TBL(klass));
 	}
-	clone->m_tbl = st_init_numtable();
-	data.tbl = clone->m_tbl;
+	RCLASS_M_TBL(clone) = st_init_numtable();
+	data.tbl = RCLASS_M_TBL(clone);
 	data.klass = (VALUE)clone;
-	st_foreach(RCLASS(klass)->m_tbl, clone_method,
+	st_foreach(RCLASS_M_TBL(klass), clone_method,
 	  (st_data_t)&data);
 	rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
 	FL_SET(clone, FL_SINGLETON);
@@ -162,10 +170,10 @@
 rb_singleton_class_attached(VALUE klass, VALUE obj)
 {
     if (FL_TEST(klass, FL_SINGLETON)) {
-	if (!RCLASS(klass)->iv_tbl) {
-	    RCLASS(klass)->iv_tbl = st_init_numtable();
+	if (!RCLASS_IV_TBL(klass)) {
+	    RCLASS_IV_TBL(klass) = st_init_numtable();
 	}
-	st_insert(RCLASS(klass)->iv_tbl, rb_intern("__attached__"), obj);
+	st_insert(RCLASS_IV_TBL(klass), rb_intern("__attached__"), obj);
     }
 }
 
@@ -223,7 +231,7 @@
 	if (TYPE(klass) != T_CLASS) {
 	    rb_raise(rb_eTypeError, "%s is not a class", name);
 	}
-	if (rb_class_real(RCLASS(klass)->super) != super) {
+	if (rb_class_real(RCLASS_SUPER(klass)) != super) {
 	    rb_name_error(id, "%s is already defined", name);
 	}
 	return klass;
@@ -252,7 +260,7 @@
 	if (TYPE(klass) != T_CLASS) {
 	    rb_raise(rb_eTypeError, "%s is not a class", name);
 	}
-	if (rb_class_real(RCLASS(klass)->super) != super) {
+	if (rb_class_real(RCLASS_SUPER(klass)) != super) {
 	    rb_name_error(id, "%s is already defined", name);
 	}
 	return klass;
@@ -272,13 +280,9 @@
 VALUE
 rb_module_new(void)
 {
-    NEWOBJ(mdl, struct RClass);
-    OBJSETUP(mdl, rb_cModule, T_MODULE);
+    VALUE mdl = class_alloc(T_MODULE, rb_cModule);
 
-    mdl->super = 0;
-    mdl->iv_tbl = 0;
-    mdl->m_tbl = 0;
-    mdl->m_tbl = st_init_numtable();
+    RCLASS_M_TBL(mdl) = st_init_numtable();
 
     return (VALUE)mdl;
 }
@@ -338,18 +342,17 @@
 static VALUE
 include_class_new(VALUE module, VALUE super)
 {
-    NEWOBJ(klass, struct RClass);
-    OBJSETUP(klass, rb_cClass, T_ICLASS);
+    VALUE klass = class_alloc(T_ICLASS, rb_cClass);
 
     if (BUILTIN_TYPE(module) == T_ICLASS) {
 	module = RBASIC(module)->klass;
     }
-    if (!RCLASS(module)->iv_tbl) {
-	RCLASS(module)->iv_tbl = st_init_numtable();
+    if (!RCLASS_IV_TBL(module)) {
+	RCLASS_IV_TBL(module) = st_init_numtable();
     }
-    klass->iv_tbl = RCLASS(module)->iv_tbl;
-    klass->m_tbl = RCLASS(module)->m_tbl;
-    klass->super = super;
+    RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
+    RCLASS_M_TBL(klass) = RCLASS_M_TBL(module);
+    RCLASS_SUPER(klass) = super;
     if (TYPE(module) == T_ICLASS) {
 	RBASIC(klass)->klass = RBASIC(module)->klass;
     }
@@ -382,13 +385,13 @@
     while (module) {
        int superclass_seen = Qfalse;
 
-	if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl)
+	if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module))
 	    rb_raise(rb_eArgError, "cyclic include detected");
        /* ignore if the module included already in superclasses */
-       for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) {
+       for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) {
            switch (BUILTIN_TYPE(p)) {
              case T_ICLASS:
-               if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) {
+               if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) {
                    if (!superclass_seen) {
                        c = p;  /* move insertion point */
                    }
@@ -400,10 +403,10 @@
                break;
            }
        }
-       c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super);
+       c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c));
 	changed = 1;
       skip:
-	module = RCLASS(module)->super;
+	module = RCLASS_SUPER(module);
     }
     if (changed) rb_clear_cache();
 }
@@ -431,7 +434,7 @@
     VALUE ary = rb_ary_new();
     VALUE p;
 
-    for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) {
+    for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER(p)) {
 	if (BUILTIN_TYPE(p) == T_ICLASS) {
 	    rb_ary_push(ary, RBASIC(p)->klass);
 	}
@@ -464,7 +467,7 @@
     VALUE p;
 
     Check_Type(mod2, T_MODULE);
-    for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) {
+    for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER(p)) {
 	if (BUILTIN_TYPE(p) == T_ICLASS) {
 	    if (RBASIC(p)->klass == mod2) return Qtrue;
 	}
@@ -493,7 +496,7 @@
 {
     VALUE p, ary = rb_ary_new();
 
-    for (p = mod; p; p = RCLASS(p)->super) {
+    for (p = mod; p; p = RCLASS_SUPER(p)) {
 	if (FL_TEST(p, FL_SINGLETON))
 	    continue;
 	if (BUILTIN_TYPE(p) == T_ICLASS) {
@@ -599,8 +602,8 @@
     }
 
     list = st_init_numtable();
-    for (; mod; mod = RCLASS(mod)->super) {
-	st_foreach(RCLASS(mod)->m_tbl, method_entry, (st_data_t)list);
+    for (; mod; mod = RCLASS_SUPER(mod)) {
+	st_foreach(RCLASS_M_TBL(mod), method_entry, (st_data_t)list);
 	if (BUILTIN_TYPE(mod) == T_ICLASS) continue;
 	if (FL_TEST(mod, FL_SINGLETON)) continue;
 	if (!recur) break;
@@ -756,13 +759,13 @@
     klass = CLASS_OF(obj);
     list = st_init_numtable();
     if (klass && FL_TEST(klass, FL_SINGLETON)) {
-	st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list);
-	klass = RCLASS(klass)->super;
+	st_foreach(RCLASS_M_TBL(klass), method_entry, (st_data_t)list);
+	klass = RCLASS_SUPER(klass);
     }
     if (RTEST(recur)) {
 	while (klass && (FL_TEST(klass, FL_SINGLETON) || TYPE(klass) == T_ICLASS)) {
-	    st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list);
-	    klass = RCLASS(klass)->super;
+	    st_foreach(RCLASS_M_TBL(klass), method_entry, (st_data_t)list);
+	    klass = RCLASS_SUPER(klass);
 	}
     }
     ary = rb_ary_new();
Index: ext/digest/digest.c
===================================================================
--- ext/digest/digest.c	(revision 13542)
+++ ext/digest/digest.c	(revision 13543)
@@ -426,7 +426,7 @@
     VALUE obj;
     rb_digest_metadata_t *algo;
 
-    for (p = klass; p; p = RCLASS(p)->super) {
+    for (p = klass; p; p = RCLASS_SUPER(p)) {
         if (rb_ivar_defined(p, id_metadata)) {
             obj = rb_ivar_get(p, id_metadata);
             break;
Index: error.c
===================================================================
--- error.c	(revision 13542)
+++ error.c	(revision 13543)
@@ -971,7 +971,7 @@
 	VALUE klass = CLASS_OF(exc);
 
 	while (TYPE(klass) == T_ICLASS || FL_TEST(klass, FL_SINGLETON)) {
-	    klass = (VALUE)RCLASS(klass)->super;
+	    klass = (VALUE)RCLASS_SUPER(klass);
 	}
 	num = rb_const_get(klass, rb_intern("Errno"));
     }
Index: vm.c
===================================================================
--- vm.c	(revision 13542)
+++ vm.c	(revision 13543)
@@ -503,7 +503,7 @@
 
     if (!cfp->iseq) {
 	klass = cfp->method_klass;
-	klass = RCLASS(klass)->super;
+	klass = RCLASS_SUPER(klass);
 
 	if (klass == 0) {
 	    klass = vm_search_normal_super_klass(cfp->method_klass, recv);
@@ -1001,7 +1001,7 @@
 add_opt_method(VALUE klass, ID mid, VALUE bop)
 {
     NODE *node;
-    if (st_lookup(RCLASS(klass)->m_tbl, mid, (void *)&node) &&
+    if (st_lookup(RCLASS_M_TBL(klass), mid, (void *)&node) &&
 	nd_type(node->nd_body->nd_body) == NODE_CFUNC) {
 	st_insert(vm_opt_method_table, (st_data_t)node, (st_data_t)bop);
     }
Index: marshal.c
===================================================================
--- marshal.c	(revision 13542)
+++ marshal.c	(revision 13543)
@@ -404,17 +404,17 @@
     char *path;
 
     if (check && FL_TEST(klass, FL_SINGLETON)) {
-	if (RCLASS(klass)->m_tbl->num_entries ||
-	    (RCLASS(klass)->iv_tbl && RCLASS(klass)->iv_tbl->num_entries > 1)) {
+	if (RCLASS_M_TBL(klass)->num_entries ||
+	    (RCLASS_IV_TBL(klass) && RCLASS_IV_TBL(klass)->num_entries > 1)) {
 	    rb_raise(rb_eTypeError, "singleton can't be dumped");
 	}
-	klass = RCLASS(klass)->super;
+	klass = RCLASS_SUPER(klass);
     }
     while (BUILTIN_TYPE(klass) == T_ICLASS) {
 	path = rb_class2name(RBASIC(klass)->klass);
 	w_byte(TYPE_EXTENDED, arg);
 	w_unique(path, arg);
-	klass = RCLASS(klass)->super;
+	klass = RCLASS_SUPER(klass);
     }
 }
 
@@ -471,6 +471,25 @@
 }
 
 static void
+w_objivar(VALUE obj, struct dump_call_arg *arg)
+{
+    VALUE *ptr;
+    long i, len, num;
+
+    len = ROBJECT_LEN(obj);
+    ptr = ROBJECT_PTR(obj);
+    num = 0;
+    for (i = 0; i < len; i++)
+        if (ptr[i] != Qundef)
+            num += 1;
+
+    w_long(num, arg->arg);
+    if (num != 0) {
+        rb_ivar_foreach(obj, w_obj_each, (st_data_t)arg);
+    }
+}
+
+static void
 w_object(VALUE obj, struct dump_arg *arg, int limit)
 {
     struct dump_call_arg c_arg;
@@ -682,7 +701,7 @@
 
 	  case T_OBJECT:
 	    w_class(TYPE_OBJECT, obj, arg, Qtrue);
-	    w_ivar(ROBJECT(obj)->iv_tbl, &c_arg);
+	    w_objivar(obj, &c_arg);
 	    break;
 
 	  case T_DATA:
Index: insnhelper.ci
===================================================================
--- insnhelper.ci	(revision 13542)
+++ insnhelper.ci	(revision 13543)
@@ -507,7 +507,7 @@
 		  break;
 	      }
 	      case NODE_ZSUPER:{
-		  klass = RCLASS(mn->nd_clss)->super;
+		  klass = RCLASS_SUPER(mn->nd_clss);
 		  mn = rb_method_node(klass, id);
 
 		  if (mn != 0) {
@@ -998,8 +998,8 @@
 		}
 	    }
 	  search_continue:
-	    if (RCLASS(klass)->iv_tbl &&
-		st_lookup(RCLASS(klass)->iv_tbl, id, &val)) {
+	    if (RCLASS_IV_TBL(klass) &&
+		st_lookup(RCLASS_IV_TBL(klass), id, &val)) {
 		if (val == Qundef) {
 		    rb_autoload_load(klass, id);
 		    goto search_continue;
@@ -1122,16 +1122,16 @@
 vm_search_normal_super_klass(VALUE klass, VALUE recv)
 {
     if (BUILTIN_TYPE(klass) == T_CLASS) {
-	klass = RCLASS(klass)->super;
+	klass = RCLASS_SUPER(klass);
     }
     else if (BUILTIN_TYPE(klass) == T_MODULE) {
 	VALUE k = CLASS_OF(recv);
 	while (k) {
 	    if (BUILTIN_TYPE(k) == T_ICLASS && RBASIC(k)->klass == klass) {
-		klass = RCLASS(k)->super;
+		klass = RCLASS_SUPER(k);
 		break;
 	    }
-	    k = RCLASS(k)->super;
+	    k = RCLASS_SUPER(k);
 	}
     }
     return klass;

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧]