summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-09-28 06:21:46 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-09-28 06:21:46 +0000
commit5c0e68c39c3fc7717311826549a30d1615eb2007 (patch)
treeddf952542b46d0c180ed6200fcdb7b3e00036b32
parent041fbcbf50993925b2d61fbfca4d16b766d8ea5d (diff)
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13543 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog39
-rw-r--r--class.c117
-rw-r--r--error.c2
-rw-r--r--eval.c2
-rw-r--r--eval_method.ci16
-rw-r--r--ext/digest/digest.c2
-rw-r--r--gc.c29
-rw-r--r--include/ruby/intern.h1
-rw-r--r--include/ruby/ruby.h34
-rw-r--r--insnhelper.ci12
-rw-r--r--insns.def2
-rw-r--r--marshal.c29
-rw-r--r--object.c84
-rw-r--r--proc.c4
-rw-r--r--struct.c2
-rw-r--r--variable.c262
-rw-r--r--vm.c4
17 files changed, 448 insertions, 193 deletions
diff --git a/ChangeLog b/ChangeLog
index 5c32125ea4..d629a4c281 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+Fri Sep 28 15:05:24 2007 Tanaka Akira <akr@fsij.org>
+
+ * 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@ruby-lang.org>
* io.c (rb_io_getline_fast, rb_io_getline_1): set encoding to the
diff --git a/class.c b/class.c
index dff402c759..ead4d767ae 100644
--- a/class.c
+++ b/class.c
@@ -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 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
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 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
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 @@ rb_singleton_class_clone(VALUE obj)
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 @@ rb_singleton_class_clone(VALUE obj)
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 @@ void
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 @@ rb_define_class(const char *name, VALUE super)
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 @@ rb_define_class_under(VALUE outer, const char *name, VALUE super)
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 @@ rb_define_class_under(VALUE outer, const char *name, VALUE super)
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 @@ rb_define_module_under(VALUE outer, const char *name)
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 @@ rb_include_module(VALUE klass, VALUE module)
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 @@ rb_include_module(VALUE klass, VALUE module)
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 @@ rb_mod_included_modules(VALUE mod)
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 @@ rb_mod_include_p(VALUE mod, VALUE mod2)
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 @@ rb_mod_ancestors(VALUE mod)
{
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 @@ class_instance_method_list(int argc, VALUE *argv, VALUE mod, int (*func) (ID, lo
}
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 @@ rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj)
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();
diff --git a/error.c b/error.c
index e972bdd1b0..c72873d9b3 100644
--- a/error.c
+++ b/error.c
@@ -971,7 +971,7 @@ syserr_eqq(VALUE self, VALUE exc)
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"));
}
diff --git a/eval.c b/eval.c
index 639010efd8..49c6f5213d 100644
--- a/eval.c
+++ b/eval.c
@@ -2303,7 +2303,7 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
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;
}
diff --git a/eval_method.ci b/eval_method.ci
index 61ff38f532..6d86e52c50 100644
--- a/eval_method.ci
+++ b/eval_method.ci
@@ -143,7 +143,7 @@ rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
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 @@ rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
}
}
- 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 @@ search_method(VALUE klass, ID id, VALUE *klassp)
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 @@ remove_method(VALUE klass, ID mid)
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 @@ rb_alias(VALUE klass, ID name, ID def)
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 @@ rb_alias(VALUE klass, ID name, ID def)
}
}
- 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,
diff --git a/ext/digest/digest.c b/ext/digest/digest.c
index 0b910e8c47..41565759bb 100644
--- a/ext/digest/digest.c
+++ b/ext/digest/digest.c
@@ -426,7 +426,7 @@ get_digest_base_metadata(VALUE klass)
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;
diff --git a/gc.c b/gc.c
index 3a073d39d8..7dd5c4e681 100644
--- a/gc.c
+++ b/gc.c
@@ -1033,9 +1033,9 @@ gc_mark_children(VALUE ptr, int lev)
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 @@ gc_mark_children(VALUE ptr, int lev)
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 @@ obj_free(VALUE obj)
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);
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index d9443f5788..1b453d1f30 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -583,6 +583,7 @@ void rb_free_generic_ivar(VALUE);
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);
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 5ccf246734..4939609e31 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -402,10 +402,26 @@ struct RBasic {
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 @@ struct RValues {
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;
diff --git a/insnhelper.ci b/insnhelper.ci
index 4be9c7259e..afb0bd0e76 100644
--- a/insnhelper.ci
+++ b/insnhelper.ci
@@ -507,7 +507,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
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 @@ vm_get_ev_const(rb_thread_t *th, rb_iseq_t *iseq,
}
}
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 @@ static inline VALUE
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;
diff --git a/insns.def b/insns.def
index d31a9656bc..3cf8e4d67f 100644
--- a/insns.def
+++ b/insns.def
@@ -973,7 +973,7 @@ defineclass
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",
diff --git a/marshal.c b/marshal.c
index 6b7108e4df..f4cc37942e 100644
--- a/marshal.c
+++ b/marshal.c
@@ -404,17 +404,17 @@ w_extended(VALUE klass, struct dump_arg *arg, int check)
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 @@ w_ivar(st_table *tbl, struct dump_call_arg *arg)
}
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 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
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:
diff --git a/object.c b/object.c
index c6fa1176f3..e2b3e43bd0 100644
--- a/object.c
+++ b/object.c
@@ -100,7 +100,7 @@ VALUE
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 @@ init_copy(VALUE dest, VALUE obj)
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 @@ inspect_obj(VALUE obj, VALUE str, int recur)
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 @@ inspect_obj(VALUE obj, VALUE str, int recur)
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 @@ rb_obj_is_kind_of(VALUE obj, VALUE c)
}
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_class_inherited_p(VALUE mod, VALUE arg)
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 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass)
{
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 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass)
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 @@ rb_obj_alloc(VALUE klass)
{
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 @@ rb_class_new_instance(int argc, VALUE *argv, VALUE klass)
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;
diff --git a/proc.c b/proc.c
index 3b6d9a94f4..127a1bd073 100644
--- a/proc.c
+++ b/proc.c
@@ -620,13 +620,13 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mklass)
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;
diff --git a/struct.c b/struct.c
index 57050b7422..e87a082c23 100644
--- a/struct.c
+++ b/struct.c
@@ -25,7 +25,7 @@ rb_struct_iv_get(VALUE c, const char *name)
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;
}
diff --git a/variable.c b/variable.c
index 2ddfb1ac5b..d5c3bfe100 100644
--- a/variable.c
+++ b/variable.c
@@ -48,8 +48,8 @@ fc_path(struct fc_result *fc, ID name)
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 @@ fc_i(ID key, VALUE value, struct fc_result *res)
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 @@ fc_i(ID key, VALUE value, struct fc_result *res)
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 @@ find_class_path(VALUE klass)
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 @@ classname(VALUE klass)
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 @@ rb_class_path(VALUE klass)
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 @@ static VALUE
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 @@ rb_attr_get(VALUE obj, ID id)
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 @@ rb_ivar_set(VALUE obj, ID id, VALUE val)
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,8 +1062,69 @@ rb_ivar_defined(VALUE obj, ID id)
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 @@ rb_obj_instance_variables(VALUE obj)
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 @@ rb_obj_remove_instance_variable(VALUE obj, VALUE name)
{
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 @@ rb_obj_remove_instance_variable(VALUE obj, VALUE name)
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_autoload(VALUE mod, ID id, const char *file)
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 @@ autoload_delete(VALUE mod, ID id)
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 @@ autoload_delete(VALUE mod, ID id)
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 @@ autoload_file(VALUE mod, ID id)
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 @@ autoload_file(VALUE mod, ID id)
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 @@ autoload_file(VALUE mod, ID id)
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 @@ rb_const_get_0(VALUE klass, ID id, int exclude, int recurse)
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 @@ rb_const_get_0(VALUE klass, ID id, int exclude, int recurse)
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_mod_remove_const(VALUE mod, VALUE name)
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 @@ rb_mod_const_at(VALUE mod, void *data)
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 @@ rb_mod_const_of(VALUE mod, void *data)
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 @@ rb_const_defined_0(VALUE klass, ID id, int exclude, int recurse)
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 @@ mod_av_set(VALUE klass, ID id, VALUE val, int isconst)
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 @@ mod_av_set(VALUE klass, ID id, VALUE val, int isconst)
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 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
}
#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 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
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 @@ rb_mod_class_variables(VALUE obj)
{
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_mod_remove_cvar(VALUE mod, VALUE name)
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)) {
diff --git a/vm.c b/vm.c
index f2c96eaeb0..0267ee93a4 100644
--- a/vm.c
+++ b/vm.c
@@ -503,7 +503,7 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv)
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 @@ static void
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);
}