# Optimize T\_OBJECT space

**URL:** <https://www.ruby-forum.com/t/optimize-t-object-space/246513>\
**Category:** Development\
**Created:** [September 25, 2007, 5:48am UTC](https://www.ruby-forum.com/t/optimize-t-object-space/246513 "2007-09-25T05:48:06Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tanaka\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/c67d28/32.png) [@Tanaka\_A](https://www.ruby-forum.com/u/Tanaka_A)\
**Post date:** [September 25, 2007, 5:48am UTC](https://www.ruby-forum.com/t/optimize-t-object-space/246513/1 "2007-09-25T05:48:06Z")

</div>

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%9JQ?t$NCM$@$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

e$B$?$@!"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”  
puts File.readlines("/proc/#{$$}/status").grep(/^VmSize:/)’ – --all  
–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”  
puts File.readlines("/proc/#{$$}/status").grep(/^VmSize:/)’ – --all  
–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)

e$B$?$@!“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) }  
puts File.readlines("/proc/#{$$}/status").grep(/^VmSize:/)  
’

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

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

e$B$?$@!"$=$&$$$&%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$/$@$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);

- 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 @@

- 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 RCLASS\_IV\_TBL© (RCLASS©-\>ptr-\>iv\_tbl)  
+#define RCLASS\_M\_TBL© (RCLASS©-\>m\_tbl)  
+#define RCLASS\_SUPER© (RCLASS©-\>super)  
+#define RCLASS\_IV\_INDEX\_TBL© (RCLASS©-\>ptr-\>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 (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 (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 (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;

- 

```
   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;

- 

```
   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;

- 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;

- 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 ®;  
}  
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) {  
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);

- 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;

- klass = RCLASS(klass)-\>super;

- klass = RCLASS\_SUPER(klass);  
goto again;  
}

- rklass = RCLASS(rklass)-\>super;

- rklass = RCLASS\_SUPER(rklass);  
}  
if (TYPE(klass) == T\_ICLASS)  
klass = RBASIC(klass)-\>klass;  
Index: thread.c  
===================================================================  
— thread.c (e$B%j%S%8%g%se(B 13497)  
+++ thread.c (e$B:n6H%3%T!\<e(B)  
@@ -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);

- c = RCLASS©-\>super;

- c = RCLASS\_SUPER©;  
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) {  
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 (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;

@@ -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();

- 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();

- NEWOBJ(klass, struct RClass);
- OBJSETUP(klass, rb\_cClass, T\_ICLASS);

- VALUE klass = class\_alloc(T\_ICLASS, rb\_cClass);

- 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©-\>super);

- 

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

```

RCLASS\_SUPER©);  
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;

- 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 @@  
}

- 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;  
rb\_digest\_metadata\_t \*algo;

- for (p = klass; p; p = RCLASS§-\>super) {

- for (p = klass; p; p = RCLASS\_SUPER§) {  
if (rb\_ivar\_defined(p, id\_metadata)) {  
obj = rb\_ivar\_get(p, id\_metadata);  
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 (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 (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) {  
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;
