static VALUE include_class_new(VALUE module, VALUE super) { NEWOBJ(klass, struct RClass); OBJSETUP(klass, rb_cClass, T_ICLASS); if (BUILTIN_TYPE(module) == T_ICLASS) { module = RBASIC(module)->klass; } if (!RCLASS(module)->iv_tbl) { RCLASS(module)->iv_tbl = st_init_numtable(); } klass->iv_tbl = RCLASS(module)->iv_tbl; klass->m_tbl = RCLASS(module)->m_tbl; klass->super = super; if (TYPE(module) == T_ICLASS) { RBASIC(klass)->klass = RBASIC(module)->klass; } else { RBASIC(klass)->klass = module; } OBJ_INFECT(klass, module); OBJ_INFECT(klass, super); return (VALUE)klass; }
static VALUE singleton_class_clone_int(VALUE obj, VALUE nklass) { VALUE klass = RBASIC(obj)->klass; if (!FL_TEST(klass, FL_SINGLETON)) return klass; else { /* copy singleton(unnamed) class */ NEWOBJ(clone, struct RClass); OBJSETUP(clone, 0, RBASIC(klass)->flags); if (BUILTIN_TYPE(obj) == T_CLASS) { RBASIC(clone)->klass = (VALUE)clone; } else { 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); } clone->m_tbl = st_init_numtable(); st_foreach(RCLASS(klass)->m_tbl, (int (*)(...))clone_method, NIL_P(nklass) ? (VALUE)clone : nklass); rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); FL_SET(clone, FL_SINGLETON); return (VALUE)clone; } }
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(); } st_insert(RCLASS(klass)->iv_tbl, rb_intern("__attached__"), obj); } }
VALUE 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) { if (BUILTIN_TYPE(p) == T_ICLASS) { if (RBASIC(p)->klass == mod2) return Qtrue; } } return Qfalse; }
VALUE rb_mod_included_modules(VALUE mod) { VALUE ary = rb_ary_new(); VALUE p; for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) { if (BUILTIN_TYPE(p) == T_ICLASS) { rb_ary_push(ary, RBASIC(p)->klass); } } return ary; }
/* call-seq: * swap_method_tables(other) -> self * * Swap the method table of the receiver with the method table of the given * class or module. If +other+ is not a class or module, raise a +TypeError+. */ static VALUE evilr_swap_method_tables(VALUE self, VALUE other) { struct st_table *tmp; evilr__check_immediate(other); if(BUILTIN_TYPE(other) != T_MODULE && BUILTIN_TYPE(other) != T_CLASS) { rb_raise(rb_eTypeError, "non-class or module used"); } tmp = RCLASS_M_TBL(self); RCLASS(self)->m_tbl = RCLASS_M_TBL(other); RCLASS(other)->m_tbl = tmp; rb_clear_cache_by_class(self); rb_clear_cache_by_class(other); return self; }
static VALUE create_class_restorer(VALUE klass) { /* On Ruby 1.8, there is a check in marshal_dump() to ensure that * the object being dumped has no modifications to its singleton * class (e.g. no singleton instance variables, and no singleton * methods defined). Since we need to dump the class's singleton * class in order to dump class methods, we need a way around this * restriction. The solution found here temporarily removes the * singleton instance variables and singleton methods while the * class is being dumped, and sets a special singleton instance * variable that restores the tables when dumping is complete. A * hack for sure, but it seems to work. */ struct RClass * singleton_class = RCLASS(CLASS_OF(klass)); struct Class_Restorer * class_restorer; if(!RCLASS_IV_TBL(singleton_class)) { rb_raise( rb_eTypeError, "can't dump singleton class on Ruby 1.8 without iv_tbl"); } class_restorer = ALLOC(struct Class_Restorer); class_restorer->klass = CLASS_OF(klass); class_restorer->m_tbl = *RCLASS_M_TBL(singleton_class); class_restorer->iv_tbl = *RCLASS_IV_TBL(singleton_class); #ifndef RUBY_VM class_restorer->thread_critical = rb_thread_critical; #endif return Data_Wrap_Struct( rb_cClass_Restorer, mark_class_restorer, ruby_xfree, class_restorer); }
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super) { VALUE klass; ID id; id = rb_intern(name); if (rb_const_defined_at(outer, id)) { klass = rb_const_get_at(outer, id); if (TYPE(klass) != T_CLASS) { rb_raise(rb_eTypeError, "%s is not a class", name); } if (rb_class_real(RCLASS(klass)->super) != super) { rb_name_error(id, "%s is already defined", name); } return klass; } if (!super) { rb_warn("no super class for `%s::%s', Object assumed", rb_class2name(outer), name); } klass = rb_define_class_id(id, super); rb_set_class_path(klass, outer, name); rb_const_set(outer, id, klass); rb_class_inherited(super, klass); return klass; }
VALUE rb_define_class(const char *name, VALUE super) { VALUE klass; ID id; id = rb_intern(name); if (rb_const_defined(rb_cObject, id)) { klass = rb_const_get(rb_cObject, id); if (TYPE(klass) != T_CLASS) { rb_raise(rb_eTypeError, "%s is not a class", name); } if (rb_class_real(RCLASS(klass)->super) != super) { rb_name_error(id, "%s is already defined", name); } return klass; } if (!super) { rb_warn("no super class for `%s', Object assumed", name); } klass = rb_define_class_id(id, super); st_add_direct(rb_class_tbl, id, klass); rb_name_class(klass, id); rb_const_set(rb_cObject, id, klass); rb_class_inherited(super, klass); return klass; }
static int clone_method(ID mid, NODE *body, VALUE nklass) { NODE *fbody = body->nd_body; if (fbody) { VALUE nbody; switch (nd_type(fbody)) { case NODE_SCOPE: fbody = rb_copy_node_scope(fbody, ruby_cref); break; case NODE_BMETHOD: nbody = rb_block_dup(fbody->nd_cval, nklass, (VALUE)ruby_cref); fbody = NEW_BMETHOD(nbody); break; case NODE_DMETHOD: nbody = rb_method_dup(fbody->nd_cval, nklass, (VALUE)ruby_cref); fbody = NEW_DMETHOD(nbody); break; } } st_insert(RCLASS(nklass)->m_tbl, mid, (st_data_t)NEW_METHOD(fbody, body->nd_noex)); return ST_CONTINUE; }
static rb_digest_metadata_t * get_digest_base_metadata(VALUE klass) { VALUE p; VALUE obj; rb_digest_metadata_t *algo; for (p = klass; p; p = RCLASS(p)->super) { if (rb_ivar_defined(p, id_metadata)) { obj = rb_ivar_get(p, id_metadata); break; } } if (!p) rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby"); Data_Get_Struct(obj, rb_digest_metadata_t, algo); switch (algo->api_version) { case 2: break; /* * put conversion here if possible when API is updated */ default: rb_raise(rb_eRuntimeError, "Incompatible digest API version"); } return algo; }
/* * call-seq: * remove_features(mod) => mod * * When this module is unincluded from another, Ruby Internal calls * remove_features in this module. The default behavior is to remove * the constants, methods, and module variables of this module from * _mod_. If this module has not been included by _mod_, an exception * will be raised. */ static VALUE module_remove_features(VALUE module, VALUE uninclude) { VALUE prev, mod; if(TYPE(uninclude) != T_CLASS && TYPE(uninclude) != T_MODULE) { Check_Type(uninclude, T_CLASS); } rb_frozen_class_p(uninclude); if(!OBJ_TAINTED(uninclude)) { rb_secure(4); } OBJ_INFECT(uninclude, module); if(RCLASS(uninclude)->m_tbl == RCLASS(module)->m_tbl) { rb_raise(rb_eArgError, "Cannot remove module from itself"); } prev = uninclude; mod = RCLASS_SUPER(uninclude); while(mod) { if(RCLASS(module)->m_tbl == RCLASS(mod)->m_tbl) { RCLASS_SUPER(prev) = RCLASS_SUPER(mod); rb_clear_cache(); return module; } if(BUILTIN_TYPE(mod) == T_CLASS) { break; } prev = mod; mod = RCLASS_SUPER(mod); } rb_raise(rb_eArgError, "Could not find included module"); return module; }
static void set_class_restore_state(VALUE klass) { struct RClass * singleton_class = RCLASS(CLASS_OF(klass)); RCLASS_IV_TBL(singleton_class)->num_entries = 1; RCLASS_M_TBL(singleton_class)->num_entries = 0; #ifndef RUBY_VM rb_thread_critical = 1; #endif }
/* call-seq: * swap_instance_variables(other) -> self * * Swaps only the instance variables of the receiver and +other+. * You can only swap the instance variables between two objects that * use the internal type number T_OBJECT, or between Classes and Modules. * You cannot swap instance variables of immediate values, since they * do not have instance variables. Invalid swap attempts will raise * +TypeError+. */ static VALUE evilr_swap_instance_variables(VALUE self, VALUE other) { #ifndef RUBY19 struct st_table *tmp; #endif evilr__check_immediates(self, other); switch(BUILTIN_TYPE(self)) { case T_OBJECT: if (BUILTIN_TYPE(other) != T_OBJECT) { goto bad_types; } break; case T_MODULE: case T_CLASS: if (BUILTIN_TYPE(other) != T_MODULE && BUILTIN_TYPE(other) != T_CLASS) { goto bad_types; } break; default: bad_types: rb_raise(rb_eTypeError, "incompatible types used"); } #ifdef RUBY19 if (BUILTIN_TYPE(self) == T_MODULE || BUILTIN_TYPE(self) == T_CLASS) { struct st_table *tmp; tmp = RCLASS_IV_TBL(self); RCLASS(self)->ptr->iv_tbl = RCLASS_IV_TBL(other); RCLASS(other)->ptr->iv_tbl = tmp; } else { char tmp[OBJECT_SIZE]; memcpy(tmp, &(ROBJECT(self)->as), sizeof(ROBJECT(tmp)->as)); memcpy(&(ROBJECT(self)->as), &(ROBJECT(other)->as), sizeof(ROBJECT(self)->as)); memcpy(&(ROBJECT(other)->as), tmp, sizeof(ROBJECT(other)->as)); } #else /* RClass and RObject have iv_tbl at same position in the structure * so no funny business is needed */ tmp = ROBJECT_IVPTR(self); ROBJECT(self)->iv_tbl = ROBJECT_IVPTR(other); ROBJECT(other)->iv_tbl = tmp; #endif return self; }
/* ================ Helper Functions =================*/ static VALUE figure_singleton_name(VALUE klass) { VALUE result = Qnil; /* We have come across a singleton object. First figure out what it is attached to.*/ VALUE attached = rb_iv_get(klass, "__attached__"); /* Is this a singleton class acting as a metaclass? */ if (BUILTIN_TYPE(attached) == T_CLASS) { result = rb_str_new2("<Class::"); rb_str_append(result, rb_inspect(attached)); rb_str_cat2(result, ">"); } /* Is this for singleton methods on a module? */ else if (BUILTIN_TYPE(attached) == T_MODULE) { result = rb_str_new2("<Module::"); rb_str_append(result, rb_inspect(attached)); rb_str_cat2(result, ">"); } /* Is this for singleton methods on an object? */ else if (BUILTIN_TYPE(attached) == T_OBJECT) { /* Make sure to get the super class so that we don't mistakenly grab a T_ICLASS which would lead to unknown method errors. */ #ifdef HAVE_RB_CLASS_SUPERCLASS // 1.9.3 VALUE super = rb_class_superclass(klass); #else # ifdef RCLASS_SUPER VALUE super = rb_class_real(RCLASS_SUPER(klass)); # else VALUE super = rb_class_real(RCLASS(klass)->super); # endif #endif result = rb_str_new2("<Object::"); rb_str_append(result, rb_inspect(super)); rb_str_cat2(result, ">"); } /* Ok, this could be other things like an array made put onto a singleton object (yeah, it happens, see the singleton objects test case). */ else { result = rb_inspect(klass); } return result; }
/* :nodoc: */ VALUE rb_class_init_copy(VALUE clone, VALUE orig) { if (RCLASS(clone)->super != 0) { rb_raise(rb_eTypeError, "already initialized class"); } if (FL_TEST(orig, FL_SINGLETON)) { rb_raise(rb_eTypeError, "can't copy singleton class"); } return rb_mod_init_copy(clone, orig); }
void rb_include_module(VALUE klass, VALUE module) { VALUE p, c; int changed = 0; rb_frozen_class_p(klass); if (!OBJ_TAINTED(klass)) { rb_secure(4); } if (TYPE(module) != T_MODULE) { Check_Type(module, T_MODULE); } OBJ_INFECT(klass, module); c = klass; while (module) { int superclass_seen = Qfalse; if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl) 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) { switch (BUILTIN_TYPE(p)) { case T_ICLASS: if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) { if (!superclass_seen) { c = p; /* move insertion point */ } goto skip; } break; case T_CLASS: superclass_seen = Qtrue; break; } } c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super); changed = 1; skip: module = RCLASS(module)->super; } if (changed) rb_clear_cache(); }
static VALUE mnew(VALUE klass, VALUE obj, ID id, VALUE mklass) { VALUE method; NODE *body; struct METHOD *data; VALUE rklass = klass; ID oid = id; again: if ((body = rb_get_method_body(klass, id, 0)) == 0) { print_undef(rklass, oid); } klass = body->nd_clss; body = body->nd_body; if (nd_type(body) == NODE_ZSUPER) { klass = RCLASS(klass)->super; goto again; } while (rklass != klass && (FL_TEST(rklass, FL_SINGLETON) || TYPE(rklass) == T_ICLASS)) { rklass = RCLASS(rklass)->super; } if (TYPE(klass) == T_ICLASS) klass = RBASIC(klass)->klass; method = Data_Make_Struct(mklass, struct METHOD, bm_mark, -1, data); data->klass = klass; data->recv = obj; data->id = id; data->body = body; data->rklass = rklass; data->oid = oid; OBJ_INFECT(method, klass); return method; }
VALUE rb_make_metaclass(VALUE obj, VALUE super) { VALUE klass = rb_class_boot(super); FL_SET(klass, FL_SINGLETON); RBASIC(obj)->klass = klass; rb_singleton_class_attached(klass, obj); if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) { RBASIC(klass)->klass = klass; RCLASS(klass)->super = RBASIC(rb_class_real(RCLASS(obj)->super))->klass; } else { VALUE metasuper = RBASIC(rb_class_real(super))->klass; /* metaclass of a superclass may be NULL at boot time */ if (metasuper) { RBASIC(klass)->klass = metasuper; } } return klass; }
static VALUE instance_method_hash(VALUE module) { VALUE methods = rb_hash_new(); st_foreach( RCLASS(module)->m_tbl, add_to_method_hash, #ifdef ST_DATA_T_DEFINED (st_data_t)methods #else methods #endif ); return methods; }
VALUE rb_struct_iv_get(VALUE c, const char *name) { ID id; id = rb_intern(name); for (;;) { if (rb_ivar_defined(c, id)) return rb_ivar_get(c, id); c = RCLASS(c)->super; if (c == 0 || c == rb_cStruct) return Qnil; } }
/* :nodoc: */ VALUE rb_mod_init_copy(VALUE clone, VALUE orig) { rb_obj_init_copy(clone, orig); if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { RBASIC(clone)->klass = singleton_class_clone_int(orig, clone); } RCLASS(clone)->super = RCLASS(orig)->super; if (RCLASS(orig)->iv_tbl) { ID id; RCLASS(clone)->iv_tbl = st_copy(RCLASS(orig)->iv_tbl); id = rb_intern("__classpath__"); st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0); id = rb_intern("__classid__"); st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0); } if (RCLASS(orig)->m_tbl) { RCLASS(clone)->m_tbl = st_init_numtable(); st_foreach(RCLASS(orig)->m_tbl, (int (*)(...))clone_method, clone); } return clone; }
static VALUE rb_gsl_odeiv_step_info(VALUE obj) { gsl_odeiv_step *s; char buf[256]; Data_Get_Struct(obj, gsl_odeiv_step, s); sprintf(buf, "Class: %s\n", rb_class2name(CLASS_OF(obj))); #ifdef RUBY_1_9_LATER sprintf(buf, "%sSuperClass: %s\n", buf, rb_class2name(RCLASS_SUPER(CLASS_OF(obj)))); #else sprintf(buf, "%sSuperClass: %s\n", buf, rb_class2name(RCLASS(CLASS_OF(obj))->super)); #endif sprintf(buf, "%sType: %s\n", buf, gsl_odeiv_step_name(s)); sprintf(buf, "%sDimension: %d\n", buf, (int) s->dimension); return rb_str_new2(buf); }
static VALUE rb_gsl_object_info(VALUE obj) { char buf[256]; VALUE s; sprintf(buf, "Class: %s\n", rb_class2name(CLASS_OF(obj))); #ifdef RUBY_1_9_LATER sprintf(buf, "%sSuperClass: %s\n", buf, rb_class2name(RCLASS_SUPER(CLASS_OF(obj)))); #else sprintf(buf, "%sSuperClass: %s\n", buf, rb_class2name(RCLASS(CLASS_OF(obj))->super)); #endif s = rb_rescue(rb_gsl_call_name, obj, rb_gsl_call_rescue, obj); if (s) sprintf(buf, "%sType: %s\n", buf, STR2CSTR(s)); s = rb_rescue(rb_gsl_call_size, obj, rb_gsl_call_rescue, obj); if (s) sprintf(buf, "%sSize: %d\n", buf, (int) FIX2INT(s)); return rb_str_new2(buf); }
static void restore_class(VALUE ruby_class_restorer) { struct Class_Restorer * class_restorer; struct RClass * klass; Data_Get_Struct( ruby_class_restorer, struct Class_Restorer, class_restorer); klass = RCLASS(class_restorer->klass); *RCLASS_M_TBL(klass) = class_restorer->m_tbl; *RCLASS_IV_TBL(klass) = class_restorer->iv_tbl; #ifndef RUBY_VM rb_thread_critical = class_restorer->thread_critical; #endif }
VALUE rb_mod_ancestors(VALUE mod) { VALUE p, ary = rb_ary_new(); for (p = mod; p; p = RCLASS(p)->super) { if (FL_TEST(p, FL_SINGLETON)) continue; if (BUILTIN_TYPE(p) == T_ICLASS) { rb_ary_push(ary, RBASIC(p)->klass); } else { rb_ary_push(ary, p); } } return ary; }
static VALUE rb_gsl_interp_info(VALUE obj) { rb_gsl_interp *p; char buf[256]; Data_Get_Struct(obj, rb_gsl_interp, p); sprintf(buf, "Class: %s\n", rb_class2name(CLASS_OF(obj))); #ifdef RUBY_1_9_LATER sprintf(buf, "%sSuperClass: %s\n", buf, rb_class2name(RCLASS_SUPER(CLASS_OF(obj)))); #else sprintf(buf, "%sSuperClass: %s\n", buf, rb_class2name(RCLASS(CLASS_OF(obj))->super)); #endif sprintf(buf, "%sType: %s\n", buf, gsl_interp_name(p->p)); sprintf(buf, "%sxmin: %f\n", buf, p->p->xmin); sprintf(buf, "%sxmax: %f\n", buf, p->p->xmax); sprintf(buf, "%sSize: %d\n", buf, (int) p->p->size); return rb_str_new2(buf); }
static VALUE syserr_eqq(VALUE self, VALUE exc) { VALUE num, e; if (!rb_obj_is_kind_of(exc, rb_eSystemCallError)) return Qfalse; if (self == rb_eSystemCallError) return Qtrue; num = rb_attr_get(exc, rb_intern("errno")); if (NIL_P(num)) { VALUE klass = CLASS_OF(exc); while (TYPE(klass) == T_ICLASS || FL_TEST(klass, FL_SINGLETON)) { klass = (VALUE)RCLASS(klass)->super; } num = rb_const_get(klass, rb_intern("Errno")); } e = rb_const_get(self, rb_intern("Errno")); if (FIXNUM_P(num) ? num == e : rb_equal(num, e)) return Qtrue; return Qfalse; }
void obj_dump(VALUE obj, yajl_gen gen) { int type; yajl_gen_map_open(gen); yajl_gen_cstr(gen, "_id"); yajl_gen_value(gen, obj); struct obj_track *tracker = NULL; if (st_lookup(objs, (st_data_t)obj, (st_data_t *)&tracker) && BUILTIN_TYPE(obj) != T_NODE) { yajl_gen_cstr(gen, "file"); yajl_gen_cstr(gen, tracker->source); yajl_gen_cstr(gen, "line"); yajl_gen_integer(gen, tracker->line); } yajl_gen_cstr(gen, "type"); switch (type=BUILTIN_TYPE(obj)) { case T_DATA: yajl_gen_cstr(gen, "data"); if (RBASIC(obj)->klass) { yajl_gen_cstr(gen, "class"); yajl_gen_value(gen, RBASIC(obj)->klass); yajl_gen_cstr(gen, "class_name"); VALUE name = rb_classname(RBASIC(obj)->klass); if (RTEST(name)) yajl_gen_cstr(gen, RSTRING(name)->ptr); else yajl_gen_cstr(gen, 0); } break; case T_FILE: yajl_gen_cstr(gen, "file"); break; case T_FLOAT: yajl_gen_cstr(gen, "float"); yajl_gen_cstr(gen, "data"); yajl_gen_double(gen, RFLOAT(obj)->value); break; case T_BIGNUM: yajl_gen_cstr(gen, "bignum"); yajl_gen_cstr(gen, "negative"); yajl_gen_bool(gen, RBIGNUM(obj)->sign == 0); yajl_gen_cstr(gen, "length"); yajl_gen_integer(gen, RBIGNUM(obj)->len); yajl_gen_cstr(gen, "data"); yajl_gen_string(gen, RBIGNUM(obj)->digits, RBIGNUM(obj)->len); break; case T_MATCH: yajl_gen_cstr(gen, "match"); yajl_gen_cstr(gen, "data"); yajl_gen_value(gen, RMATCH(obj)->str); break; case T_REGEXP: yajl_gen_cstr(gen, "regexp"); yajl_gen_cstr(gen, "length"); yajl_gen_integer(gen, RREGEXP(obj)->len); yajl_gen_cstr(gen, "data"); yajl_gen_cstr(gen, RREGEXP(obj)->str); break; case T_SCOPE: yajl_gen_cstr(gen, "scope"); struct SCOPE *scope = (struct SCOPE *)obj; if (scope->local_tbl) { int i = 1; int n = scope->local_tbl[0]; VALUE *list = &scope->local_vars[-1]; VALUE cur = *list++; yajl_gen_cstr(gen, "node"); yajl_gen_value(gen, cur); if (n) { yajl_gen_cstr(gen, "variables"); yajl_gen_map_open(gen); while (n--) { cur = *list++; yajl_gen_cstr(gen, scope->local_tbl[i] == 95 ? "_" : rb_id2name(scope->local_tbl[i])); yajl_gen_value(gen, cur); i++; } yajl_gen_map_close(gen); } } break; case T_NODE: yajl_gen_cstr(gen, "node"); yajl_gen_cstr(gen, "node_type"); yajl_gen_cstr(gen, nd_type_str(obj)); yajl_gen_cstr(gen, "file"); yajl_gen_cstr(gen, RNODE(obj)->nd_file); yajl_gen_cstr(gen, "line"); yajl_gen_integer(gen, nd_line(obj)); yajl_gen_cstr(gen, "node_code"); yajl_gen_integer(gen, nd_type(obj)); switch (nd_type(obj)) { case NODE_SCOPE: break; } break; case T_STRING: yajl_gen_cstr(gen, "string"); yajl_gen_cstr(gen, "length"); yajl_gen_integer(gen, RSTRING(obj)->len); if (FL_TEST(obj, ELTS_SHARED|FL_USER3)) { yajl_gen_cstr(gen, "shared"); yajl_gen_value(gen, RSTRING(obj)->aux.shared); yajl_gen_cstr(gen, "flags"); yajl_gen_array_open(gen); if (FL_TEST(obj, ELTS_SHARED)) yajl_gen_cstr(gen, "elts_shared"); if (FL_TEST(obj, FL_USER3)) yajl_gen_cstr(gen, "str_assoc"); yajl_gen_array_close(gen); } else { yajl_gen_cstr(gen, "data"); yajl_gen_string(gen, (unsigned char *)RSTRING(obj)->ptr, RSTRING(obj)->len); } break; case T_VARMAP: yajl_gen_cstr(gen, "varmap"); struct RVarmap *vars = (struct RVarmap *)obj; if (vars->next) { yajl_gen_cstr(gen, "next"); yajl_gen_value(gen, (VALUE)vars->next); } if (vars->id) { yajl_gen_cstr(gen, "data"); yajl_gen_map_open(gen); yajl_gen_cstr(gen, rb_id2name(vars->id)); yajl_gen_value(gen, vars->val); yajl_gen_map_close(gen); } break; case T_CLASS: case T_MODULE: case T_ICLASS: yajl_gen_cstr(gen, type==T_CLASS ? "class" : type==T_MODULE ? "module" : "iclass"); yajl_gen_cstr(gen, "name"); VALUE name = rb_classname(obj); if (RTEST(name)) yajl_gen_cstr(gen, RSTRING(name)->ptr); else yajl_gen_cstr(gen, 0); yajl_gen_cstr(gen, "super"); yajl_gen_value(gen, RCLASS(obj)->super); yajl_gen_cstr(gen, "super_name"); VALUE super_name = rb_classname(RCLASS(obj)->super); if (RTEST(super_name)) yajl_gen_cstr(gen, RSTRING(super_name)->ptr); else yajl_gen_cstr(gen, 0); if (FL_TEST(obj, FL_SINGLETON)) { yajl_gen_cstr(gen, "singleton"); yajl_gen_bool(gen, 1); } if (RCLASS(obj)->iv_tbl && RCLASS(obj)->iv_tbl->num_entries) { yajl_gen_cstr(gen, "ivars"); yajl_gen_map_open(gen); st_foreach(RCLASS(obj)->iv_tbl, each_ivar, (st_data_t)gen); yajl_gen_map_close(gen); } if (type != T_ICLASS && RCLASS(obj)->m_tbl && RCLASS(obj)->m_tbl->num_entries) { yajl_gen_cstr(gen, "methods"); yajl_gen_map_open(gen); st_foreach(RCLASS(obj)->m_tbl, each_ivar, (st_data_t)gen); yajl_gen_map_close(gen); } break; case T_OBJECT: yajl_gen_cstr(gen, "object"); yajl_gen_cstr(gen, "class"); yajl_gen_value(gen, RBASIC(obj)->klass); yajl_gen_cstr(gen, "class_name"); yajl_gen_cstr(gen, rb_obj_classname(obj)); struct RClass *klass = RCLASS(obj); if (klass->iv_tbl && klass->iv_tbl->num_entries) { yajl_gen_cstr(gen, "ivars"); yajl_gen_map_open(gen); st_foreach(klass->iv_tbl, each_ivar, (st_data_t)gen); yajl_gen_map_close(gen); } break; case T_ARRAY: yajl_gen_cstr(gen, "array"); struct RArray *ary = RARRAY(obj); yajl_gen_cstr(gen, "length"); yajl_gen_integer(gen, ary->len); if (FL_TEST(obj, ELTS_SHARED)) { yajl_gen_cstr(gen, "shared"); yajl_gen_value(gen, ary->aux.shared); } else if (ary->len) { yajl_gen_cstr(gen, "data"); yajl_gen_array_open(gen); int i; for(i=0; i < ary->len; i++) yajl_gen_value(gen, ary->ptr[i]); yajl_gen_array_close(gen); } break; case T_HASH: yajl_gen_cstr(gen, "hash"); struct RHash *hash = RHASH(obj); yajl_gen_cstr(gen, "length"); if (hash->tbl) yajl_gen_integer(gen, hash->tbl->num_entries); else yajl_gen_integer(gen, 0); yajl_gen_cstr(gen, "default"); yajl_gen_value(gen, hash->ifnone); if (hash->tbl && hash->tbl->num_entries) { yajl_gen_cstr(gen, "data"); //yajl_gen_map_open(gen); yajl_gen_array_open(gen); st_foreach(hash->tbl, each_hash_entry, (st_data_t)gen); yajl_gen_array_close(gen); //yajl_gen_map_close(gen); } break; default: yajl_gen_cstr(gen, "unknown"); } yajl_gen_cstr(gen, "code"); yajl_gen_integer(gen, BUILTIN_TYPE(obj)); yajl_gen_map_close(gen); }
static size_t memsize_of(VALUE obj) { size_t size = 0; if (SPECIAL_CONST_P(obj)) { return 0; } if (FL_TEST(obj, FL_EXIVAR)) { size += rb_generic_ivar_memsize(obj); } switch (BUILTIN_TYPE(obj)) { case T_OBJECT: if (!(RBASIC(obj)->flags & ROBJECT_EMBED) && ROBJECT(obj)->as.heap.ivptr) { size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE); } break; case T_MODULE: case T_CLASS: size += st_memsize(RCLASS_M_TBL(obj)); if (RCLASS_IV_TBL(obj)) { size += st_memsize(RCLASS_IV_TBL(obj)); } if (RCLASS_IV_INDEX_TBL(obj)) { size += st_memsize(RCLASS_IV_INDEX_TBL(obj)); } if (RCLASS(obj)->ptr->iv_tbl) { size += st_memsize(RCLASS(obj)->ptr->iv_tbl); } if (RCLASS(obj)->ptr->const_tbl) { size += st_memsize(RCLASS(obj)->ptr->const_tbl); } size += sizeof(rb_classext_t); break; case T_STRING: size += rb_str_memsize(obj); break; case T_ARRAY: size += rb_ary_memsize(obj); break; case T_HASH: if (RHASH(obj)->ntbl) { size += st_memsize(RHASH(obj)->ntbl); } break; case T_REGEXP: if (RREGEXP(obj)->ptr) { size += onig_memsize(RREGEXP(obj)->ptr); } break; case T_DATA: size += rb_objspace_data_type_memsize(obj); break; case T_MATCH: if (RMATCH(obj)->rmatch) { struct rmatch *rm = RMATCH(obj)->rmatch; size += sizeof(struct re_registers); /* TODO: onig_region_memsize(&rm->regs); */ size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated; size += sizeof(struct rmatch); } break; case T_FILE: if (RFILE(obj)->fptr) { size += rb_io_memsize(RFILE(obj)->fptr); } break; case T_RATIONAL: case T_COMPLEX: break; case T_ICLASS: /* iClass shares table with the module */ break; case T_FLOAT: break; case T_BIGNUM: if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) { size += RBIGNUM_LEN(obj) * sizeof(BDIGIT); } break; case T_NODE: switch (nd_type(obj)) { case NODE_SCOPE: if (RNODE(obj)->u1.tbl) { /* TODO: xfree(RANY(obj)->as.node.u1.tbl); */ } break; case NODE_ALLOCA: /* TODO: xfree(RANY(obj)->as.node.u1.node); */ ; } break; /* no need to free iv_tbl */ case T_STRUCT: if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 && RSTRUCT(obj)->as.heap.ptr) { size += sizeof(VALUE) * RSTRUCT_LEN(obj); } break; case T_ZOMBIE: break; default: rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)", BUILTIN_TYPE(obj), (void*)obj); } return size; }