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:
parent
041fbcbf50
commit
5c0e68c39c
17 changed files with 448 additions and 193 deletions
39
ChangeLog
39
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
|
||||
|
|
117
class.c
117
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();
|
||||
|
|
2
error.c
2
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"));
|
||||
}
|
||||
|
|
2
eval.c
2
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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
29
gc.c
29
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
29
marshal.c
29
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
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:
|
||||
w_class(TYPE_OBJECT, obj, arg, Qtrue);
|
||||
w_ivar(ROBJECT(obj)->iv_tbl, &c_arg);
|
||||
w_objivar(obj, &c_arg);
|
||||
break;
|
||||
|
||||
case T_DATA:
|
||||
|
|
84
object.c
84
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;
|
||||
|
|
4
proc.c
4
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;
|
||||
|
|
2
struct.c
2
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;
|
||||
}
|
||||
|
|
262
variable.c
262
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)) {
|
||||
|
|
4
vm.c
4
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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue