# Optimize T_OBJECT space

T_OBJECT e\$B\$J%\$%s%9%?%s%9\$G!"%\$%s%9%?%s%9JQ?t\$NL>A0\$r%/%i%9B&e(B
e\$B\$K;}\$?\$;\$F>CHq%a%b%j\$r:o8:\$9\$k\$N\$O\$I\$&\$G\$7\$g\$&\$+!#e(B

e\$B\$D\$^\$j!"%\$%s%9%?%s%9\$K\$O%\$%s%9%?%s%[email protected]\$1\$rJ];}\$9\$kG[e(B
e\$BNs\$rMQ0U\$7!"%/%i%9\$K%\$%s%9%?%s%9JQ?t\$NL>A0\$+\$i\$=\$NG[Ns\$N%\$%se(B
e\$B%G%C%/%9\$X\$N%O%C%7%eI=\$r\$D\$/\$j\$^\$9!#\$^\$?!"\$=\$NG[Ns\$,e(B 3e\$BMWAG0Je(B
e\$B2<\$G\$"\$l\$Pe(B e\$BEvA3e(B RObject e\$B\$KKd\$a9~\$_\$^\$9!#e(B

[email protected]!"e(BRuby e\$B\$K\$\$\$\$F\$OF1\$8%/%i%9\$G\$b8D!9\$N%%V%8%’%/%H\$4\$H\$Ke(B
e\$B%\$%s%9%?%s%9JQ?t\$,B8:\$7\$?\$j\$7\$J\$+\$C\$?\$j\$G\$-\$^\$9!#\$=\$3\$G!"%/e(B
e\$B%i%9\$K\$D\$/\$C\$?%O%C%7%eI=\$K\$O0l2s\$G\$bB8:
\$7\$?%\$%s%9%?%s%9JQ?te(B
e\$B\$O\$<\$s\$VEPO?\$9\$k\$3\$H\$K\$7\$F!"8D!9\$N%\$%s%9%?%s%9\$GB8:_\$7\$J\$\$>le(B
e\$B9g\$O\$=\$NJQ?t\$KAjEv\$9\$kG[Ns\$NMWAG\$re(B Qundef e\$B\$H\$7\$F\$*\$-\$^\$9!#e(B

r13509 e\$B\$K\$=\$&\$\$\$&JQ99\$r\$7\$FNc\$N\$4\$H\$/e(B rdoc e\$B\$r;n\$9\$H!"<!\$N\$he(B
e\$B\$&\$K\$J\$j\$^\$9e(B

e\$BJQ99A0e(B:
% time ./ruby -e ‘load “./bin/rdoc”
–ri --op “.ext/rdoc” “.”

Files: 568
Classes: 1612
Modules: 832
Methods: 8644
Elapsed: 165.757s
VmSize: 120056 kB
./ruby -e – --all --ri --op “.ext/rdoc” “.” 152.30s user 1.04s system
92% cpu 2:45.94 total

e\$BJQ998ee(B:
% time ./ruby -e ‘load “./bin/rdoc”
–ri --op “.ext/rdoc” “.”

Files: 568
Classes: 1612
Modules: 832
Methods: 8644
Elapsed: 149.130s
VmSize: 80876 kB
./ruby -e – --all --ri --op “.ext/rdoc” “.” 137.16s user 0.90s system
92% cpu 2:29.31 total

e\$B\$D\$^\$j!"\$3\$NA0\$N%O%C%7%eI=\$Ne(B bins e\$B\$K5M\$a\$?>u67\$+\$i\$5\$i\$Ke(B 1/3
e\$B\$/\$i\$\$e(B (40MB e\$B\$/\$i\$\$e(B) e\$B%a%b%j\$r:o\$k\$3\$H\$,\$G\$-\$^\$9!#e(B

e\$B\$^\$?!"B.EY\$b\$\$\$/\$i\$+B.\$/\$J\$C\$F\$\$\$k\$h\$&\$G\$9!#e(B(e\$B8m:9\$G\$J\$1\$l\$Pe(B)

[email protected]!“F1\$8%/%i%9\$N8D!9\$N%\$%s%9%?%s%9\$K\$h\$C\$F%\$%s%9%?%s%9JQ?te(B
e\$B\$NB8:_\$N\$7\$+\$?\$,0[\$J\$C\$F\$\$\$k>l9g\$O!”;HMQ\$7\$J\$\$%\$%s%9%?%s%9JQe(B
e\$B?t\$K\$b%a%b%j\$r3d\$jEv\$F\$k\$3\$H\$K\$J\$k\$N\$G!"%a%b%j>CHq\$,A}\$(\$k\$3e(B
e\$B\$H\$b\$"\$j\$^\$9!#e(B

e\$B\$?\$H\$(\$P!“0J2<\$N!“e(B1000e\$B8D%\$%s%9%?%s%9JQ?t\$,\$”\$k%%V%8%’%/%H\$,e(B
e\$B\$R\$H\$D\$H!“e(B2e\$B8D%\$%s%9%?%s%9JQ?t\$,\$”\$k%
%V%8%’%/%H\$,e(B
5000e\$B8D!”\$He(B
e\$B\$\$\$&\$h\$&\$J>l9g\$O%a%b%j>CHq\$,A}\$(\$^\$9!#e(B

% ./ruby -e ’
class C
def initialize(s)
if !s
n = “a”
1000.times { self.instance_variable_set “@#{n}”, 0; n.succ! }
else
@a = @A = s
end
end
end
C.new(false)
o = nil
5000.times { o = C.new(o) }

e\$BJQ99A0\$N7k2Le(B:
VmSize: 4832 kB

e\$BJQ998e\$N7k2Le(B:
VmSize: 24100 kB

[email protected]!"\$=\$&\$\$\$&%1!<%9\$O\$"\$^\$j\$J\$\$\$G\$"\$m\$&!"\$H;d\$OM=A[\$7\$F\$\$\$^e(B
e\$B\$9!#e(B

e\$B\$"\$H!"%/%i%9\$,JQ2=\$9\$k\$H:\$\$k\$N\$G\$9\$,!";d\$NCN\$k8B\$je(B T_OBJECT
e\$B\$J%1!<%9\$G\$O%/%i%9\$,JQ2=\$9\$k\$3\$H\$O\$"\$j\$^\$;\$s!#%/%i%9\$,JQ2=\$9e(B
e\$B\$k\$N\$Oe(B IO#reopen e\$B\$He(B marshal e\$B\$Ne(B user class
e\$B\$,\$"\$j\$^\$9\$,!"\$I\$Ae(B
e\$B\$i\$be(B T_OBJECT e\$B\$K\$OE,MQ\$G\$-\$^\$;\$s!#\$b\$7\$J\$K\$+B>\$K%/%i%9\$,JQ2=e(B
e\$B\$9\$k%1!<%9\$,\$"\$C\$?\$i65\$(\$F\$/[email protected]\$5\$\$!#e(B

e\$B\$I\$&\$G\$7\$g\$&\$+!#e(B

# Index: eval_method.ci

— eval_method.ci (e\$B%j%S%8%g%se(B 13497)
+++ eval_method.ci (e\$B:n6H%3%T!<e(B)
@@ -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,7 +305,7 @@
if (mid == object_id || mid == __send || mid == __send_bang || mid
== init) {
rb_warn(“removing `%s’ may cause serious problem”, rb_id2name(mid));
}
• if (!st_delete(RCLASS(klass)->m_tbl, &mid, &data) ||
• if (!st_delete(RCLASS_M_TBL(klass), &mid, &data) ||
!(body = (NODE *)data) || !body->nd_body) {
rb_name_error(mid, “method `%s’ not defined in %s”,
rb_id2name(mid), rb_class2name(klass));
@@ -577,7 +577,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) {
@@ -589,7 +589,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 (e\$B%j%S%8%g%se(B 13497)
+++ include/ruby/intern.h (e\$B:n6H%3%T!<e(B)
@@ -580,6 +580,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 (e\$B%j%S%8%g%se(B 13497)
+++ include/ruby/ruby.h (e\$B:n6H%3%T!<e(B)
@@ -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;
• struct st_table *iv_index_tbl;
+} rb_classext_t;

struct RClass {
struct RBasic basic;

• struct st_table *iv_tbl;
• rb_classext_t *ptr;
struct st_table *m_tbl;
VALUE super;
};
+#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 (e\$B%j%S%8%g%se(B 13497)
+++ insns.def (e\$B:n6H%3%T!<e(B)
@@ -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: variable.c
===================================================================
— variable.c (e\$B%j%S%8%g%se(B 13497)
+++ variable.c (e\$B:n6H%3%T!<e(B)
@@ -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);
}
@@ -1210,8 +1332,8 @@
VALUE val;
• 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)) {

@@ -1220,7 +1342,7 @@
DATA_PTR(val) = 0;
st_free_table(tbl);

• `````` 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;
• if (!st_lookup(RCLASS(mod)->iv_tbl, autoload, &val) ||
• if (!st_lookup(RCLASS_IV_TBL(mod), autoload, &val) ||
return Qnil;
}
@@ -1267,7 +1389,7 @@
DATA_PTR(val) = 0;
st_free_table(tbl);
• 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
{
• 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) {
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) {
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)
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 ®;
}
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 ®;
}\
• 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 (e\$B%j%S%8%g%se(B 13497)
+++ object.c (e\$B:n6H%3%T!<e(B)
@@ -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©->m_tbl)
• if (cl == c || RCLASS_M_TBL(cl) == RCLASS_M_TBL©)
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) {
}
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 (e\$B%j%S%8%g%se(B 13497)
+++ proc.c (e\$B:n6H%3%T!<e(B)
@@ -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;
===================================================================
@@ -2704,6 +2704,7 @@
*root = hook->next;
}
xfree(hook);
• ``````       return 0;
``````
}
prev = hook;
hook = hook->next;
Index: struct.c
===================================================================
— struct.c (e\$B%j%S%8%g%se(B 13497)
+++ struct.c (e\$B:n6H%3%T!<e(B)
@@ -25,7 +25,7 @@
for (; {
if (rb_ivar_defined(c, id))
return rb_ivar_get(c, id);
if (c == 0 || c == rb_cStruct)
return Qnil;
}
Index: eval.c
===================================================================
— eval.c (e\$B%j%S%8%g%se(B 13497)
+++ eval.c (e\$B:n6H%3%T!<e(B)
@@ -2295,7 +2295,7 @@
if (nd_type(fbody->nd_body->nd_body) != NODE_ZSUPER) {
}
• `````` m = RCLASS(m)->super;
``````
• `````` m = RCLASS_SUPER(m);
if (!m)
``````
break;
}
Index: gc.c
===================================================================
— gc.c (e\$B%j%S%8%g%se(B 13497)
+++ gc.c (e\$B:n6H%3%T!<e(B)
@@ -1013,9 +1013,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:
``````

@@ -1050,7 +1050,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:
``````

@@ -1249,17 +1255,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 (e\$B%j%S%8%g%se(B 13497)
+++ class.c (e\$B:n6H%3%T!<e(B)
@@ -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) {
}
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,
``````

• ``````  c = RCLASS_SUPER(c) = include_class_new(module,
``````

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§->super) {
• for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER§) {
if (BUILTIN_TYPE§ == T_ICLASS) {
rb_ary_push(ary, RBASIC§->klass);
}
@@ -464,7 +467,7 @@
VALUE p;

Check_Type(mod2, T_MODULE);

• for (p = RCLASS(mod)->super; p; p = RCLASS§->super) {
• for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER§) {
if (BUILTIN_TYPE§ == T_ICLASS) {
if (RBASIC§->klass == mod2) return Qtrue;
}
@@ -493,7 +496,7 @@
{
VALUE p, ary = rb_ary_new();
• for (p = mod; p; p = RCLASS§->super) {
• for (p = mod; p; p = RCLASS_SUPER§) {
if (FL_TEST(p, FL_SINGLETON))
continue;
if (BUILTIN_TYPE§ == 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 (e\$B%j%S%8%g%se(B 13497)
+++ ext/digest/digest.c (e\$B:n6H%3%T!<e(B)
@@ -426,7 +426,7 @@
VALUE obj;
• for (p = klass; p; p = RCLASS§->super) {
• for (p = klass; p; p = RCLASS_SUPER§) {
break;
Index: error.c
===================================================================
— error.c (e\$B%j%S%8%g%se(B 13497)
+++ error.c (e\$B:n6H%3%T!<e(B)
@@ -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 (e\$B%j%S%8%g%se(B 13497)
+++ vm.c (e\$B:n6H%3%T!<e(B)
@@ -502,7 +502,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);
@@ -1000,7 +1000,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 (e\$B%j%S%8%g%se(B 13497)
+++ marshal.c (e\$B:n6H%3%T!<e(B)
@@ -377,17 +377,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);
}
}

@@ -444,6 +444,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;
@@ -654,7 +673,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 (e\$B%j%S%8%g%se(B 13497)
+++ insnhelper.ci (e\$B:n6H%3%T!<e(B)
@@ -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) {
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;