1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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
This commit is contained in:
akr 2007-09-28 06:21:46 +00:00
parent 041fbcbf50
commit 5c0e68c39c
17 changed files with 448 additions and 193 deletions

View file

@ -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> 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 * io.c (rb_io_getline_fast, rb_io_getline_1): set encoding to the

117
class.c
View file

@ -18,16 +18,27 @@
extern st_table *rb_class_tbl; 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 VALUE
rb_class_boot(VALUE super) rb_class_boot(VALUE super)
{ {
NEWOBJ(klass, struct RClass); VALUE klass = class_alloc(T_CLASS, rb_cClass);
OBJSETUP(klass, rb_cClass, T_CLASS);
klass->super = super; RCLASS_SUPER(klass) = super;
klass->iv_tbl = 0; RCLASS_M_TBL(klass) = st_init_numtable();
klass->m_tbl = 0; /* safe GC */
klass->m_tbl = st_init_numtable();
OBJ_INFECT(klass, super); OBJ_INFECT(klass, super);
return (VALUE)klass; return (VALUE)klass;
@ -87,21 +98,21 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) {
RBASIC(clone)->klass = rb_singleton_class_clone(orig); RBASIC(clone)->klass = rb_singleton_class_clone(orig);
} }
RCLASS(clone)->super = RCLASS(orig)->super; RCLASS_SUPER(clone) = RCLASS_SUPER(orig);
if (RCLASS(orig)->iv_tbl) { if (RCLASS_IV_TBL(orig)) {
ID id; 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__"); 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__"); 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; 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; data.klass = clone;
st_foreach(RCLASS(orig)->m_tbl, clone_method, st_foreach(RCLASS_M_TBL(orig), clone_method,
(st_data_t)&data); (st_data_t)&data);
} }
@ -112,7 +123,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
VALUE VALUE
rb_class_init_copy(VALUE clone, VALUE orig) 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"); rb_raise(rb_eTypeError, "already initialized class");
} }
if (FL_TEST(orig, FL_SINGLETON)) { if (FL_TEST(orig, FL_SINGLETON)) {
@ -131,8 +142,7 @@ rb_singleton_class_clone(VALUE obj)
else { else {
struct clone_method_data data; struct clone_method_data data;
/* copy singleton(unnamed) class */ /* copy singleton(unnamed) class */
NEWOBJ(clone, struct RClass); VALUE clone = class_alloc(RBASIC(klass)->flags, 0);
OBJSETUP(clone, 0, RBASIC(klass)->flags);
if (BUILTIN_TYPE(obj) == T_CLASS) { if (BUILTIN_TYPE(obj) == T_CLASS) {
RBASIC(clone)->klass = (VALUE)clone; RBASIC(clone)->klass = (VALUE)clone;
@ -141,16 +151,14 @@ rb_singleton_class_clone(VALUE obj)
RBASIC(clone)->klass = rb_singleton_class_clone(klass); RBASIC(clone)->klass = rb_singleton_class_clone(klass);
} }
clone->super = RCLASS(klass)->super; RCLASS_SUPER(clone) = RCLASS_SUPER(klass);
clone->iv_tbl = 0; if (RCLASS_IV_TBL(klass)) {
clone->m_tbl = 0; RCLASS_IV_TBL(clone) = st_copy(RCLASS_IV_TBL(klass));
if (RCLASS(klass)->iv_tbl) {
clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl);
} }
clone->m_tbl = st_init_numtable(); RCLASS_M_TBL(clone) = st_init_numtable();
data.tbl = clone->m_tbl; data.tbl = RCLASS_M_TBL(clone);
data.klass = (VALUE)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); (st_data_t)&data);
rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
FL_SET(clone, FL_SINGLETON); FL_SET(clone, FL_SINGLETON);
@ -162,10 +170,10 @@ void
rb_singleton_class_attached(VALUE klass, VALUE obj) rb_singleton_class_attached(VALUE klass, VALUE obj)
{ {
if (FL_TEST(klass, FL_SINGLETON)) { if (FL_TEST(klass, FL_SINGLETON)) {
if (!RCLASS(klass)->iv_tbl) { if (!RCLASS_IV_TBL(klass)) {
RCLASS(klass)->iv_tbl = st_init_numtable(); 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) { if (TYPE(klass) != T_CLASS) {
rb_raise(rb_eTypeError, "%s is not a class", name); 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); rb_name_error(id, "%s is already defined", name);
} }
return klass; return klass;
@ -252,7 +260,7 @@ rb_define_class_under(VALUE outer, const char *name, VALUE super)
if (TYPE(klass) != T_CLASS) { if (TYPE(klass) != T_CLASS) {
rb_raise(rb_eTypeError, "%s is not a class", name); 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); rb_name_error(id, "%s is already defined", name);
} }
return klass; return klass;
@ -272,13 +280,9 @@ rb_define_class_under(VALUE outer, const char *name, VALUE super)
VALUE VALUE
rb_module_new(void) rb_module_new(void)
{ {
NEWOBJ(mdl, struct RClass); VALUE mdl = class_alloc(T_MODULE, rb_cModule);
OBJSETUP(mdl, rb_cModule, T_MODULE);
mdl->super = 0; RCLASS_M_TBL(mdl) = st_init_numtable();
mdl->iv_tbl = 0;
mdl->m_tbl = 0;
mdl->m_tbl = st_init_numtable();
return (VALUE)mdl; return (VALUE)mdl;
} }
@ -338,18 +342,17 @@ rb_define_module_under(VALUE outer, const char *name)
static VALUE static VALUE
include_class_new(VALUE module, VALUE super) include_class_new(VALUE module, VALUE super)
{ {
NEWOBJ(klass, struct RClass); VALUE klass = class_alloc(T_ICLASS, rb_cClass);
OBJSETUP(klass, rb_cClass, T_ICLASS);
if (BUILTIN_TYPE(module) == T_ICLASS) { if (BUILTIN_TYPE(module) == T_ICLASS) {
module = RBASIC(module)->klass; module = RBASIC(module)->klass;
} }
if (!RCLASS(module)->iv_tbl) { if (!RCLASS_IV_TBL(module)) {
RCLASS(module)->iv_tbl = st_init_numtable(); RCLASS_IV_TBL(module) = st_init_numtable();
} }
klass->iv_tbl = RCLASS(module)->iv_tbl; RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
klass->m_tbl = RCLASS(module)->m_tbl; RCLASS_M_TBL(klass) = RCLASS_M_TBL(module);
klass->super = super; RCLASS_SUPER(klass) = super;
if (TYPE(module) == T_ICLASS) { if (TYPE(module) == T_ICLASS) {
RBASIC(klass)->klass = RBASIC(module)->klass; RBASIC(klass)->klass = RBASIC(module)->klass;
} }
@ -382,13 +385,13 @@ rb_include_module(VALUE klass, VALUE module)
while (module) { while (module) {
int superclass_seen = Qfalse; 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"); rb_raise(rb_eArgError, "cyclic include detected");
/* ignore if the module included already in superclasses */ /* 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)) { switch (BUILTIN_TYPE(p)) {
case T_ICLASS: case T_ICLASS:
if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) { if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) {
if (!superclass_seen) { if (!superclass_seen) {
c = p; /* move insertion point */ c = p; /* move insertion point */
} }
@ -400,10 +403,10 @@ rb_include_module(VALUE klass, VALUE module)
break; 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; changed = 1;
skip: skip:
module = RCLASS(module)->super; module = RCLASS_SUPER(module);
} }
if (changed) rb_clear_cache(); if (changed) rb_clear_cache();
} }
@ -431,7 +434,7 @@ rb_mod_included_modules(VALUE mod)
VALUE ary = rb_ary_new(); VALUE ary = rb_ary_new();
VALUE p; 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) { if (BUILTIN_TYPE(p) == T_ICLASS) {
rb_ary_push(ary, RBASIC(p)->klass); rb_ary_push(ary, RBASIC(p)->klass);
} }
@ -464,7 +467,7 @@ rb_mod_include_p(VALUE mod, VALUE mod2)
VALUE p; VALUE p;
Check_Type(mod2, T_MODULE); 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 (BUILTIN_TYPE(p) == T_ICLASS) {
if (RBASIC(p)->klass == mod2) return Qtrue; if (RBASIC(p)->klass == mod2) return Qtrue;
} }
@ -493,7 +496,7 @@ rb_mod_ancestors(VALUE mod)
{ {
VALUE p, ary = rb_ary_new(); 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)) if (FL_TEST(p, FL_SINGLETON))
continue; continue;
if (BUILTIN_TYPE(p) == T_ICLASS) { 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(); list = st_init_numtable();
for (; mod; mod = RCLASS(mod)->super) { for (; mod; mod = RCLASS_SUPER(mod)) {
st_foreach(RCLASS(mod)->m_tbl, method_entry, (st_data_t)list); st_foreach(RCLASS_M_TBL(mod), method_entry, (st_data_t)list);
if (BUILTIN_TYPE(mod) == T_ICLASS) continue; if (BUILTIN_TYPE(mod) == T_ICLASS) continue;
if (FL_TEST(mod, FL_SINGLETON)) continue; if (FL_TEST(mod, FL_SINGLETON)) continue;
if (!recur) break; if (!recur) break;
@ -756,13 +759,13 @@ rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj)
klass = CLASS_OF(obj); klass = CLASS_OF(obj);
list = st_init_numtable(); list = st_init_numtable();
if (klass && FL_TEST(klass, FL_SINGLETON)) { if (klass && FL_TEST(klass, FL_SINGLETON)) {
st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list); st_foreach(RCLASS_M_TBL(klass), method_entry, (st_data_t)list);
klass = RCLASS(klass)->super; klass = RCLASS_SUPER(klass);
} }
if (RTEST(recur)) { if (RTEST(recur)) {
while (klass && (FL_TEST(klass, FL_SINGLETON) || TYPE(klass) == T_ICLASS)) { while (klass && (FL_TEST(klass, FL_SINGLETON) || TYPE(klass) == T_ICLASS)) {
st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list); st_foreach(RCLASS_M_TBL(klass), method_entry, (st_data_t)list);
klass = RCLASS(klass)->super; klass = RCLASS_SUPER(klass);
} }
} }
ary = rb_ary_new(); ary = rb_ary_new();

View file

@ -971,7 +971,7 @@ syserr_eqq(VALUE self, VALUE exc)
VALUE klass = CLASS_OF(exc); VALUE klass = CLASS_OF(exc);
while (TYPE(klass) == T_ICLASS || FL_TEST(klass, FL_SINGLETON)) { 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")); num = rb_const_get(klass, rb_intern("Errno"));
} }

2
eval.c
View file

@ -2303,7 +2303,7 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
if (nd_type(fbody->nd_body->nd_body) != NODE_ZSUPER) { if (nd_type(fbody->nd_body->nd_body) != NODE_ZSUPER) {
break; /* normal case: need not to follow 'super' link */ break; /* normal case: need not to follow 'super' link */
} }
m = RCLASS(m)->super; m = RCLASS_SUPER(m);
if (!m) if (!m)
break; break;
} }

View file

@ -143,7 +143,7 @@ rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
st_data_t data; st_data_t data;
NODE *old_node; 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; old_node = (NODE *)data;
if (old_node) { if (old_node) {
if (nd_type(old_node->nd_body->nd_body) == NODE_CFUNC) { 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 (node && mid != ID_ALLOCATOR && ruby_running) {
if (FL_TEST(klass, FL_SINGLETON)) { if (FL_TEST(klass, FL_SINGLETON)) {
@ -216,8 +216,8 @@ search_method(VALUE klass, ID id, VALUE *klassp)
return 0; return 0;
} }
while (!st_lookup(RCLASS(klass)->m_tbl, id, &body)) { while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) {
klass = RCLASS(klass)->super; klass = RCLASS_SUPER(klass);
if (!klass) if (!klass)
return 0; return 0;
} }
@ -305,11 +305,11 @@ remove_method(VALUE klass, ID mid)
if (mid == object_id || mid == __send || mid == __send_bang || mid == init) { if (mid == object_id || mid == __send || mid == __send_bang || mid == init) {
rb_warn("removing `%s' may cause serious problem", rb_id2name(mid)); 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; body = (NODE *)data;
if (!body || !body->nd_body) body = 0; if (!body || !body->nd_body) body = 0;
else { else {
st_delete(RCLASS(klass)->m_tbl, &mid, &data); st_delete(RCLASS_M_TBL(klass), &mid, &data);
} }
} }
if (!body) { if (!body) {
@ -583,7 +583,7 @@ rb_alias(VALUE klass, ID name, ID def)
orig_fbody->nd_cnt++; 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; node = (NODE *)data;
if (node) { if (node) {
if (RTEST(ruby_verbose) && node->nd_cnt == 0 && node->nd_body) { 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( (st_data_t) NEW_FBODY(
NEW_METHOD(orig_fbody->nd_body->nd_body, NEW_METHOD(orig_fbody->nd_body->nd_body,
orig_fbody->nd_body->nd_clss, orig_fbody->nd_body->nd_clss,

View file

@ -426,7 +426,7 @@ get_digest_base_metadata(VALUE klass)
VALUE obj; VALUE obj;
rb_digest_metadata_t *algo; 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)) { if (rb_ivar_defined(p, id_metadata)) {
obj = rb_ivar_get(p, id_metadata); obj = rb_ivar_get(p, id_metadata);
break; break;

29
gc.c
View file

@ -1033,9 +1033,9 @@ gc_mark_children(VALUE ptr, int lev)
case T_ICLASS: case T_ICLASS:
case T_CLASS: case T_CLASS:
case T_MODULE: case T_MODULE:
mark_tbl(obj->as.klass.m_tbl, lev); mark_tbl(RCLASS_M_TBL(obj), lev);
mark_tbl(obj->as.klass.iv_tbl, lev); mark_tbl(RCLASS_IV_TBL(obj), lev);
ptr = obj->as.klass.super; ptr = RCLASS_SUPER(obj);
goto again; goto again;
case T_ARRAY: case T_ARRAY:
@ -1070,7 +1070,13 @@ gc_mark_children(VALUE ptr, int lev)
break; break;
case T_OBJECT: 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; break;
case T_FILE: case T_FILE:
@ -1269,17 +1275,22 @@ obj_free(VALUE obj)
switch (RANY(obj)->as.basic.flags & T_MASK) { switch (RANY(obj)->as.basic.flags & T_MASK) {
case T_OBJECT: case T_OBJECT:
if (RANY(obj)->as.object.iv_tbl) { if (!(RANY(obj)->as.basic.flags & ROBJECT_EMBED) &&
st_free_table(RANY(obj)->as.object.iv_tbl); RANY(obj)->as.object.as.heap.ptr) {
RUBY_CRITICAL(free(RANY(obj)->as.object.as.heap.ptr));
} }
break; break;
case T_MODULE: case T_MODULE:
case T_CLASS: case T_CLASS:
rb_clear_cache_by_class((VALUE)obj); rb_clear_cache_by_class((VALUE)obj);
st_free_table(RANY(obj)->as.klass.m_tbl); st_free_table(RCLASS_M_TBL(obj));
if (RANY(obj)->as.object.iv_tbl) { if (RCLASS_IV_TBL(obj)) {
st_free_table(RANY(obj)->as.object.iv_tbl); 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; break;
case T_STRING: case T_STRING:
rb_str_free(obj); rb_str_free(obj);

View file

@ -583,6 +583,7 @@ void rb_free_generic_ivar(VALUE);
VALUE rb_ivar_get(VALUE, ID); VALUE rb_ivar_get(VALUE, ID);
VALUE rb_ivar_set(VALUE, ID, VALUE); VALUE rb_ivar_set(VALUE, ID, VALUE);
VALUE rb_ivar_defined(VALUE, ID); 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_set(VALUE, const char*, VALUE);
VALUE rb_iv_get(VALUE, const char*); VALUE rb_iv_get(VALUE, const char*);
VALUE rb_attr_get(VALUE, ID); VALUE rb_attr_get(VALUE, ID);

View file

@ -402,10 +402,26 @@ struct RBasic {
VALUE klass; VALUE klass;
}; };
#define ROBJECT_EMBED_LEN_MAX 3
struct RObject { struct RObject {
struct RBasic basic; 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 RValues {
struct RBasic basic; struct RBasic basic;
@ -414,12 +430,24 @@ struct RValues {
VALUE v3; VALUE v3;
}; };
typedef struct {
struct st_table *iv_tbl;
VALUE super;
} rb_classext_t;
struct RClass { struct RClass {
struct RBasic basic; struct RBasic basic;
struct st_table *iv_tbl; rb_classext_t *ptr;
struct st_table *m_tbl; 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 RFloat {
struct RBasic basic; struct RBasic basic;

View file

@ -507,7 +507,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
break; break;
} }
case NODE_ZSUPER:{ case NODE_ZSUPER:{
klass = RCLASS(mn->nd_clss)->super; klass = RCLASS_SUPER(mn->nd_clss);
mn = rb_method_node(klass, id); mn = rb_method_node(klass, id);
if (mn != 0) { if (mn != 0) {
@ -998,8 +998,8 @@ vm_get_ev_const(rb_thread_t *th, rb_iseq_t *iseq,
} }
} }
search_continue: search_continue:
if (RCLASS(klass)->iv_tbl && if (RCLASS_IV_TBL(klass) &&
st_lookup(RCLASS(klass)->iv_tbl, id, &val)) { st_lookup(RCLASS_IV_TBL(klass), id, &val)) {
if (val == Qundef) { if (val == Qundef) {
rb_autoload_load(klass, id); rb_autoload_load(klass, id);
goto search_continue; goto search_continue;
@ -1122,16 +1122,16 @@ static inline VALUE
vm_search_normal_super_klass(VALUE klass, VALUE recv) vm_search_normal_super_klass(VALUE klass, VALUE recv)
{ {
if (BUILTIN_TYPE(klass) == T_CLASS) { if (BUILTIN_TYPE(klass) == T_CLASS) {
klass = RCLASS(klass)->super; klass = RCLASS_SUPER(klass);
} }
else if (BUILTIN_TYPE(klass) == T_MODULE) { else if (BUILTIN_TYPE(klass) == T_MODULE) {
VALUE k = CLASS_OF(recv); VALUE k = CLASS_OF(recv);
while (k) { while (k) {
if (BUILTIN_TYPE(k) == T_ICLASS && RBASIC(k)->klass == klass) { if (BUILTIN_TYPE(k) == T_ICLASS && RBASIC(k)->klass == klass) {
klass = RCLASS(k)->super; klass = RCLASS_SUPER(k);
break; break;
} }
k = RCLASS(k)->super; k = RCLASS_SUPER(k);
} }
} }
return klass; return klass;

View file

@ -973,7 +973,7 @@ defineclass
if (super != rb_cObject) { if (super != rb_cObject) {
VALUE tmp; VALUE tmp;
tmp = rb_class_real(RCLASS(klass)->super); tmp = rb_class_real(RCLASS_SUPER(klass));
if (tmp != super) { if (tmp != super) {
rb_raise(rb_eTypeError, "superclass mismatch for class %s", rb_raise(rb_eTypeError, "superclass mismatch for class %s",

View file

@ -404,17 +404,17 @@ w_extended(VALUE klass, struct dump_arg *arg, int check)
char *path; char *path;
if (check && FL_TEST(klass, FL_SINGLETON)) { if (check && FL_TEST(klass, FL_SINGLETON)) {
if (RCLASS(klass)->m_tbl->num_entries || if (RCLASS_M_TBL(klass)->num_entries ||
(RCLASS(klass)->iv_tbl && RCLASS(klass)->iv_tbl->num_entries > 1)) { (RCLASS_IV_TBL(klass) && RCLASS_IV_TBL(klass)->num_entries > 1)) {
rb_raise(rb_eTypeError, "singleton can't be dumped"); rb_raise(rb_eTypeError, "singleton can't be dumped");
} }
klass = RCLASS(klass)->super; klass = RCLASS_SUPER(klass);
} }
while (BUILTIN_TYPE(klass) == T_ICLASS) { while (BUILTIN_TYPE(klass) == T_ICLASS) {
path = rb_class2name(RBASIC(klass)->klass); path = rb_class2name(RBASIC(klass)->klass);
w_byte(TYPE_EXTENDED, arg); w_byte(TYPE_EXTENDED, arg);
w_unique(path, arg); w_unique(path, arg);
klass = RCLASS(klass)->super; klass = RCLASS_SUPER(klass);
} }
} }
@ -470,6 +470,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 static void
w_object(VALUE obj, struct dump_arg *arg, int limit) w_object(VALUE obj, struct dump_arg *arg, int limit)
{ {
@ -682,7 +701,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
case T_OBJECT: case T_OBJECT:
w_class(TYPE_OBJECT, obj, arg, Qtrue); w_class(TYPE_OBJECT, obj, arg, Qtrue);
w_ivar(ROBJECT(obj)->iv_tbl, &c_arg); w_objivar(obj, &c_arg);
break; break;
case T_DATA: case T_DATA:

View file

@ -100,7 +100,7 @@ VALUE
rb_class_real(VALUE cl) rb_class_real(VALUE cl)
{ {
while (FL_TEST(cl, FL_SINGLETON) || TYPE(cl) == T_ICLASS) { while (FL_TEST(cl, FL_SINGLETON) || TYPE(cl) == T_ICLASS) {
cl = RCLASS(cl)->super; cl = RCLASS_SUPER(cl);
} }
return cl; return cl;
} }
@ -137,15 +137,34 @@ init_copy(VALUE dest, VALUE obj)
rb_gc_copy_finalizer(dest, obj); rb_gc_copy_finalizer(dest, obj);
switch (TYPE(obj)) { switch (TYPE(obj)) {
case T_OBJECT: 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_CLASS:
case T_MODULE: case T_MODULE:
if (ROBJECT(dest)->iv_tbl) { if (RCLASS_IV_TBL(dest)) {
st_free_table(ROBJECT(dest)->iv_tbl); st_free_table(RCLASS_IV_TBL(dest));
ROBJECT(dest)->iv_tbl = 0; RCLASS_IV_TBL(dest) = 0;
} }
if (ROBJECT(obj)->iv_tbl) { if (RCLASS_IV_TBL(obj)) {
ROBJECT(dest)->iv_tbl = st_copy(ROBJECT(obj)->iv_tbl); RCLASS_IV_TBL(dest) = st_copy(RCLASS_IV_TBL(obj));
} }
break;
} }
rb_funcall(dest, id_init_copy, 1, obj); rb_funcall(dest, id_init_copy, 1, obj);
} }
@ -296,7 +315,7 @@ inspect_obj(VALUE obj, VALUE str, int recur)
rb_str_cat2(str, " ..."); rb_str_cat2(str, " ...");
} }
else { else {
st_foreach_safe(ROBJECT(obj)->iv_tbl, inspect_i, str); rb_ivar_foreach(obj, inspect_i, str);
} }
rb_str_cat2(str, ">"); rb_str_cat2(str, ">");
RSTRING_PTR(str)[0] = '#'; RSTRING_PTR(str)[0] = '#';
@ -321,9 +340,21 @@ inspect_obj(VALUE obj, VALUE str, int recur)
static VALUE static VALUE
rb_obj_inspect(VALUE obj) rb_obj_inspect(VALUE obj)
{ {
if (TYPE(obj) == T_OBJECT
&& ROBJECT(obj)->iv_tbl if (TYPE(obj) == T_OBJECT) {
&& ROBJECT(obj)->iv_tbl->num_entries > 0) { 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; VALUE str;
char *c; char *c;
@ -331,6 +362,7 @@ rb_obj_inspect(VALUE obj)
str = rb_sprintf("-<%s:%p", c, (void*)obj); str = rb_sprintf("-<%s:%p", c, (void*)obj);
return rb_exec_recursive(inspect_obj, obj, str); return rb_exec_recursive(inspect_obj, obj, str);
} }
}
return rb_funcall(obj, rb_intern("to_s"), 0, 0); 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) { 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; return Qtrue;
cl = RCLASS(cl)->super; cl = RCLASS_SUPER(cl);
} }
return Qfalse; return Qfalse;
} }
@ -1104,15 +1136,15 @@ rb_class_inherited_p(VALUE mod, VALUE arg)
rb_raise(rb_eTypeError, "compared with non class/module"); rb_raise(rb_eTypeError, "compared with non class/module");
} }
while (mod) { while (mod) {
if (RCLASS(mod)->m_tbl == RCLASS(arg)->m_tbl) if (RCLASS_M_TBL(mod) == RCLASS_M_TBL(arg))
return Qtrue; return Qtrue;
mod = RCLASS(mod)->super; mod = RCLASS_SUPER(mod);
} }
/* not mod < arg; check if mod > arg */ /* not mod < arg; check if mod > arg */
while (arg) { while (arg) {
if (RCLASS(arg)->m_tbl == RCLASS(start)->m_tbl) if (RCLASS_M_TBL(arg) == RCLASS_M_TBL(start))
return Qfalse; return Qfalse;
arg = RCLASS(arg)->super; arg = RCLASS_SUPER(arg);
} }
return Qnil; return Qnil;
} }
@ -1277,7 +1309,7 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass)
{ {
VALUE super; VALUE super;
if (RCLASS(klass)->super != 0) { if (RCLASS_SUPER(klass) != 0) {
rb_raise(rb_eTypeError, "already initialized class"); rb_raise(rb_eTypeError, "already initialized class");
} }
if (rb_scan_args(argc, argv, "01", &super) == 0) { if (rb_scan_args(argc, argv, "01", &super) == 0) {
@ -1286,7 +1318,7 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass)
else { else {
rb_check_inheritable(super); rb_check_inheritable(super);
} }
RCLASS(klass)->super = super; RCLASS_SUPER(klass) = super;
rb_make_metaclass(klass, RBASIC(super)->klass); rb_make_metaclass(klass, RBASIC(super)->klass);
rb_class_inherited(super, klass); rb_class_inherited(super, klass);
rb_mod_initialize(klass); rb_mod_initialize(klass);
@ -1308,7 +1340,7 @@ rb_obj_alloc(VALUE klass)
{ {
VALUE obj; 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"); rb_raise(rb_eTypeError, "can't instantiate uninitialized class");
} }
if (FL_TEST(klass, FL_SINGLETON)) { if (FL_TEST(klass, FL_SINGLETON)) {
@ -1367,13 +1399,13 @@ rb_class_new_instance(int argc, VALUE *argv, VALUE klass)
static VALUE static VALUE
rb_class_superclass(VALUE klass) rb_class_superclass(VALUE klass)
{ {
VALUE super = RCLASS(klass)->super; VALUE super = RCLASS_SUPER(klass);
if (!super) { if (!super) {
rb_raise(rb_eTypeError, "uninitialized class"); rb_raise(rb_eTypeError, "uninitialized class");
} }
while (TYPE(super) == T_ICLASS) { while (TYPE(super) == T_ICLASS) {
super = RCLASS(super)->super; super = RCLASS_SUPER(super);
} }
if (!super) { if (!super) {
return Qnil; return Qnil;

4
proc.c
View file

@ -620,13 +620,13 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mklass)
body = body->nd_body; body = body->nd_body;
if (nd_type(body) == NODE_ZSUPER) { if (nd_type(body) == NODE_ZSUPER) {
klass = RCLASS(klass)->super; klass = RCLASS_SUPER(klass);
goto again; goto again;
} }
while (rklass != klass && while (rklass != klass &&
(FL_TEST(rklass, FL_SINGLETON) || TYPE(rklass) == T_ICLASS)) { (FL_TEST(rklass, FL_SINGLETON) || TYPE(rklass) == T_ICLASS)) {
rklass = RCLASS(rklass)->super; rklass = RCLASS_SUPER(rklass);
} }
if (TYPE(klass) == T_ICLASS) if (TYPE(klass) == T_ICLASS)
klass = RBASIC(klass)->klass; klass = RBASIC(klass)->klass;

View file

@ -25,7 +25,7 @@ rb_struct_iv_get(VALUE c, const char *name)
for (;;) { for (;;) {
if (rb_ivar_defined(c, id)) if (rb_ivar_defined(c, id))
return rb_ivar_get(c, id); return rb_ivar_get(c, id);
c = RCLASS(c)->super; c = RCLASS_SUPER(c);
if (c == 0 || c == rb_cStruct) if (c == 0 || c == rb_cStruct)
return Qnil; return Qnil;
} }

View file

@ -48,8 +48,8 @@ fc_path(struct fc_result *fc, ID name)
path = rb_str_new2(rb_id2name(name)); path = rb_str_new2(rb_id2name(name));
while (fc) { while (fc) {
if (fc->track == rb_cObject) break; if (fc->track == rb_cObject) break;
if (ROBJECT(fc->track)->iv_tbl && if (RCLASS_IV_TBL(fc->track) &&
st_lookup(ROBJECT(fc->track)->iv_tbl, classpath, &tmp)) { st_lookup(RCLASS_IV_TBL(fc->track), classpath, &tmp)) {
tmp = rb_str_dup(tmp); tmp = rb_str_dup(tmp);
rb_str_cat2(tmp, "::"); rb_str_cat2(tmp, "::");
rb_str_append(tmp, path); rb_str_append(tmp, path);
@ -78,7 +78,7 @@ fc_i(ID key, VALUE value, struct fc_result *res)
switch (TYPE(value)) { switch (TYPE(value)) {
case T_MODULE: case T_MODULE:
case T_CLASS: case T_CLASS:
if (!RCLASS(value)->iv_tbl) return ST_CONTINUE; if (!RCLASS_IV_TBL(value)) return ST_CONTINUE;
else { else {
struct fc_result arg; struct fc_result arg;
struct fc_result *list; struct fc_result *list;
@ -94,7 +94,7 @@ fc_i(ID key, VALUE value, struct fc_result *res)
arg.klass = res->klass; arg.klass = res->klass;
arg.track = value; arg.track = value;
arg.prev = res; 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) { if (arg.path) {
res->path = arg.path; res->path = arg.path;
return ST_STOP; return ST_STOP;
@ -118,18 +118,18 @@ find_class_path(VALUE klass)
arg.klass = klass; arg.klass = klass;
arg.track = rb_cObject; arg.track = rb_cObject;
arg.prev = 0; arg.prev = 0;
if (RCLASS(rb_cObject)->iv_tbl) { if (RCLASS_IV_TBL(rb_cObject)) {
st_foreach_safe(RCLASS(rb_cObject)->iv_tbl, fc_i, (st_data_t)&arg); st_foreach_safe(RCLASS_IV_TBL(rb_cObject), fc_i, (st_data_t)&arg);
} }
if (arg.path == 0) { if (arg.path == 0) {
st_foreach_safe(rb_class_tbl, fc_i, (st_data_t)&arg); st_foreach_safe(rb_class_tbl, fc_i, (st_data_t)&arg);
} }
if (arg.path) { if (arg.path) {
if (!ROBJECT(klass)->iv_tbl) { if (!RCLASS_IV_TBL(klass)) {
ROBJECT(klass)->iv_tbl = st_init_numtable(); RCLASS_IV_TBL(klass) = st_init_numtable();
} }
st_insert(ROBJECT(klass)->iv_tbl, classpath, arg.path); st_insert(RCLASS_IV_TBL(klass), classpath, arg.path);
st_delete(RCLASS(klass)->iv_tbl, &tmp_classpath, 0); st_delete(RCLASS_IV_TBL(klass), &tmp_classpath, 0);
return arg.path; return arg.path;
} }
return Qnil; return Qnil;
@ -141,17 +141,17 @@ classname(VALUE klass)
VALUE path = Qnil; VALUE path = Qnil;
if (!klass) klass = rb_cObject; if (!klass) klass = rb_cObject;
if (ROBJECT(klass)->iv_tbl) { if (RCLASS_IV_TBL(klass)) {
if (!st_lookup(ROBJECT(klass)->iv_tbl, classpath, &path)) { if (!st_lookup(RCLASS_IV_TBL(klass), classpath, &path)) {
ID classid = rb_intern("__classid__"); 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); return find_class_path(klass);
} }
path = rb_str_new2(rb_id2name(SYM2ID(path))); path = rb_str_new2(rb_id2name(SYM2ID(path)));
OBJ_FREEZE(path); OBJ_FREEZE(path);
st_insert(ROBJECT(klass)->iv_tbl, classpath, path); st_insert(RCLASS_IV_TBL(klass), classpath, path);
st_delete(RCLASS(klass)->iv_tbl, (st_data_t*)&classid, 0); st_delete(RCLASS_IV_TBL(klass), (st_data_t*)&classid, 0);
} }
if (TYPE(path) != T_STRING) { if (TYPE(path) != T_STRING) {
rb_bug("class path is not set properly"); rb_bug("class path is not set properly");
@ -183,7 +183,7 @@ rb_class_path(VALUE klass)
VALUE path = classname(klass); VALUE path = classname(klass);
if (!NIL_P(path)) return path; 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)) { tmp_classpath, &path)) {
return path; return path;
} }
@ -926,12 +926,22 @@ static VALUE
ivar_get(VALUE obj, ID id, int warn) ivar_get(VALUE obj, ID id, int warn)
{ {
VALUE val; VALUE val;
VALUE klass;
st_data_t index;
switch (TYPE(obj)) { switch (TYPE(obj)) {
case T_OBJECT: 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_CLASS:
case T_MODULE: 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; return val;
break; break;
default: default:
@ -960,16 +970,63 @@ rb_attr_get(VALUE obj, ID id)
VALUE VALUE
rb_ivar_set(VALUE obj, ID id, VALUE val) 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) if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
if (OBJ_FROZEN(obj)) rb_error_frozen("object"); if (OBJ_FROZEN(obj)) rb_error_frozen("object");
switch (TYPE(obj)) { switch (TYPE(obj)) {
case T_OBJECT: 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_CLASS:
case T_MODULE: case T_MODULE:
if (!ROBJECT(obj)->iv_tbl) ROBJECT(obj)->iv_tbl = st_init_numtable(); if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();
st_insert(ROBJECT(obj)->iv_tbl, id, val); st_insert(RCLASS_IV_TBL(obj), id, val);
break;
default: default:
generic_ivar_set(obj, id, val); generic_ivar_set(obj, id, val);
break; break;
@ -980,11 +1037,21 @@ rb_ivar_set(VALUE obj, ID id, VALUE val)
VALUE VALUE
rb_ivar_defined(VALUE obj, ID id) rb_ivar_defined(VALUE obj, ID id)
{ {
VALUE klass, val;
st_data_t index;
switch (TYPE(obj)) { switch (TYPE(obj)) {
case T_OBJECT: 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_CLASS:
case T_MODULE: 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; return Qtrue;
break; break;
default: default:
@ -995,8 +1062,69 @@ rb_ivar_defined(VALUE obj, ID id)
return Qfalse; return Qfalse;
} }
struct obj_ivar_tag {
VALUE obj;
int (*func)(ID key, VALUE val, st_data_t arg);
st_data_t arg;
};
static int 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)) { if (rb_is_instance_id(key)) {
rb_ary_push(ary, ID2SYM(key)); rb_ary_push(ary, ID2SYM(key));
@ -1027,25 +1155,7 @@ rb_obj_instance_variables(VALUE obj)
VALUE ary; VALUE ary;
ary = rb_ary_new(); ary = rb_ary_new();
switch (TYPE(obj)) { rb_ivar_foreach(obj, ivar_i, ary);
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;
}
return ary; return ary;
} }
@ -1076,6 +1186,8 @@ rb_obj_remove_instance_variable(VALUE obj, VALUE name)
{ {
VALUE val = Qnil; VALUE val = Qnil;
ID id = rb_to_id(name); ID id = rb_to_id(name);
VALUE klass;
st_data_t index;
if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); 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)) { switch (TYPE(obj)) {
case T_OBJECT: 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_CLASS:
case T_MODULE: 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; return val;
} }
break; break;
@ -1185,11 +1307,11 @@ rb_autoload(VALUE mod, ID id, const char *file)
rb_raise(rb_eArgError, "empty file name"); 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; return;
rb_const_set(mod, id, Qundef); rb_const_set(mod, id, Qundef);
tbl = RCLASS(mod)->iv_tbl; tbl = RCLASS_IV_TBL(mod);
if (st_lookup(tbl, autoload, &av)) { if (st_lookup(tbl, autoload, &av)) {
tbl = check_autoload_table(av); tbl = check_autoload_table(av);
} }
@ -1210,8 +1332,8 @@ autoload_delete(VALUE mod, ID id)
VALUE val; VALUE val;
st_data_t load = 0; st_data_t load = 0;
st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, 0); st_delete(RCLASS_IV_TBL(mod), (st_data_t*)&id, 0);
if (st_lookup(RCLASS(mod)->iv_tbl, autoload, &val)) { if (st_lookup(RCLASS_IV_TBL(mod), autoload, &val)) {
struct st_table *tbl = check_autoload_table(val); struct st_table *tbl = check_autoload_table(val);
st_delete(tbl, (st_data_t*)&id, &load); st_delete(tbl, (st_data_t*)&id, &load);
@ -1220,7 +1342,7 @@ autoload_delete(VALUE mod, ID id)
DATA_PTR(val) = 0; DATA_PTR(val) = 0;
st_free_table(tbl); st_free_table(tbl);
id = autoload; 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); rb_gc_force_recycle(val);
} }
} }
@ -1248,7 +1370,7 @@ autoload_file(VALUE mod, ID id)
struct st_table *tbl; struct st_table *tbl;
st_data_t load; 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)) { !(tbl = check_autoload_table(val)) || !st_lookup(tbl, id, &load)) {
return Qnil; return Qnil;
} }
@ -1267,7 +1389,7 @@ autoload_file(VALUE mod, ID id)
DATA_PTR(val) = 0; DATA_PTR(val) = 0;
st_free_table(tbl); st_free_table(tbl);
id = autoload; 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); rb_gc_force_recycle(val);
} }
} }
@ -1277,7 +1399,7 @@ autoload_file(VALUE mod, ID id)
VALUE VALUE
rb_autoload_p(VALUE mod, ID id) 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; VALUE val;
if (!tbl || !st_lookup(tbl, id, &val) || val != Qundef) { 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; tmp = klass;
retry: retry:
while (tmp && !NIL_P(tmp)) { 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 (value == Qundef) {
if (!RTEST(rb_autoload_load(tmp, id))) break; if (!RTEST(rb_autoload_load(tmp, id))) break;
continue; continue;
@ -1307,7 +1429,7 @@ rb_const_get_0(VALUE klass, ID id, int exclude, int recurse)
return value; return value;
} }
if (!recurse && klass != rb_cObject) break; if (!recurse && klass != rb_cObject) break;
tmp = RCLASS(tmp)->super; tmp = RCLASS_SUPER(tmp);
} }
if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) { if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
mod_retry = 1; mod_retry = 1;
@ -1360,7 +1482,7 @@ rb_mod_remove_const(VALUE mod, VALUE name)
rb_raise(rb_eSecurityError, "Insecure: can't remove constant"); rb_raise(rb_eSecurityError, "Insecure: can't remove constant");
if (OBJ_FROZEN(mod)) rb_error_frozen("class/module"); 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) { if (val == Qundef) {
autoload_delete(mod, id); autoload_delete(mod, id);
val = Qnil; val = Qnil;
@ -1394,8 +1516,8 @@ rb_mod_const_at(VALUE mod, void *data)
if (!tbl) { if (!tbl) {
tbl = st_init_numtable(); tbl = st_init_numtable();
} }
if (RCLASS(mod)->iv_tbl) { if (RCLASS_IV_TBL(mod)) {
st_foreach_safe(RCLASS(mod)->iv_tbl, sv_i, (st_data_t)tbl); st_foreach_safe(RCLASS_IV_TBL(mod), sv_i, (st_data_t)tbl);
} }
return tbl; return tbl;
} }
@ -1406,7 +1528,7 @@ rb_mod_const_of(VALUE mod, void *data)
VALUE tmp = mod; VALUE tmp = mod;
for (;;) { for (;;) {
data = rb_mod_const_at(tmp, data); data = rb_mod_const_at(tmp, data);
tmp = RCLASS(tmp)->super; tmp = RCLASS_SUPER(tmp);
if (!tmp) break; if (!tmp) break;
if (tmp == rb_cObject && mod != rb_cObject) 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; tmp = klass;
retry: retry:
while (tmp) { 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))) if (value == Qundef && NIL_P(autoload_file(klass, id)))
return Qfalse; return Qfalse;
return Qtrue; return Qtrue;
} }
if (!recurse && klass != rb_cObject) break; if (!recurse && klass != rb_cObject) break;
tmp = RCLASS(tmp)->super; tmp = RCLASS_SUPER(tmp);
} }
if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) { if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
mod_retry = 1; mod_retry = 1;
@ -1528,13 +1650,13 @@ mod_av_set(VALUE klass, ID id, VALUE val, int isconst)
rb_error_frozen("class"); rb_error_frozen("class");
} }
} }
if (!RCLASS(klass)->iv_tbl) { if (!RCLASS_IV_TBL(klass)) {
RCLASS(klass)->iv_tbl = st_init_numtable(); RCLASS_IV_TBL(klass) = st_init_numtable();
} }
else if (isconst) { else if (isconst) {
VALUE value = Qfalse; VALUE value = Qfalse;
if (st_lookup(RCLASS(klass)->iv_tbl, id, &value)) { if (st_lookup(RCLASS_IV_TBL(klass), id, &value)) {
if (value == Qundef) if (value == Qundef)
autoload_delete(klass, id); autoload_delete(klass, id);
else else
@ -1545,7 +1667,7 @@ mod_av_set(VALUE klass, ID id, VALUE val, int isconst)
if(isconst){ if(isconst){
rb_vm_change_state(); rb_vm_change_state();
} }
st_insert(RCLASS(klass)->iv_tbl, id, val); st_insert(RCLASS_IV_TBL(klass), id, val);
} }
void void
@ -1585,7 +1707,7 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
} }
#define CVAR_LOOKUP(v,r) do {\ #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);\ return (r);\
}\ }\
if (FL_TEST(klass, FL_SINGLETON) ) {\ if (FL_TEST(klass, FL_SINGLETON) ) {\
@ -1596,18 +1718,18 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
klass = obj;\ klass = obj;\
break;\ break;\
default:\ default:\
klass = RCLASS(klass)->super;\ klass = RCLASS_SUPER(klass);\
break;\ break;\
}\ }\
}\ }\
else {\ else {\
klass = RCLASS(klass)->super;\ klass = RCLASS_SUPER(klass);\
}\ }\
while (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);\ return (r);\
}\ }\
klass = RCLASS(klass)->super;\ klass = RCLASS_SUPER(klass);\
}\ }\
} while(0) } while(0)
@ -1695,8 +1817,8 @@ rb_mod_class_variables(VALUE obj)
{ {
VALUE ary = rb_ary_new(); VALUE ary = rb_ary_new();
if (RCLASS(obj)->iv_tbl) { if (RCLASS_IV_TBL(obj)) {
st_foreach_safe(RCLASS(obj)->iv_tbl, cv_i, ary); st_foreach_safe(RCLASS_IV_TBL(obj), cv_i, ary);
} }
return 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"); rb_raise(rb_eSecurityError, "Insecure: can't remove class variable");
if (OBJ_FROZEN(mod)) rb_error_frozen("class/module"); 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; return val;
} }
if (rb_cvar_defined(mod, id)) { if (rb_cvar_defined(mod, id)) {

4
vm.c
View file

@ -503,7 +503,7 @@ vm_call_super(rb_thread_t *th, int argc, const VALUE *argv)
if (!cfp->iseq) { if (!cfp->iseq) {
klass = cfp->method_klass; klass = cfp->method_klass;
klass = RCLASS(klass)->super; klass = RCLASS_SUPER(klass);
if (klass == 0) { if (klass == 0) {
klass = vm_search_normal_super_klass(cfp->method_klass, recv); 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) add_opt_method(VALUE klass, ID mid, VALUE bop)
{ {
NODE *node; 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) { nd_type(node->nd_body->nd_body) == NODE_CFUNC) {
st_insert(vm_opt_method_table, (st_data_t)node, (st_data_t)bop); st_insert(vm_opt_method_table, (st_data_t)node, (st_data_t)bop);
} }