diff options
Diffstat (limited to 'object.c')
| -rw-r--r-- | object.c | 471 |
1 files changed, 304 insertions, 167 deletions
@@ -46,14 +46,9 @@ /* Flags of RObject * - * 1: ROBJECT_EMBED - * The object has its instance variables embedded (the array of - * instance variables directly follow the object, rather than being - * on a separately allocated buffer). - * if !SHAPE_IN_BASIC_FLAGS - * 4-19: SHAPE_FLAG_MASK - * Shape ID for the object. - * endif + * 4: ROBJECT_HEAP + * The object has its instance variables in a separately allocated buffer. + * This can be either a flat buffer of reference, or an st_table for complex objects. */ /*! @@ -87,6 +82,7 @@ static VALUE rb_cFalseClass_to_s; #define id_init_dup idInitialize_dup #define id_const_missing idConst_missing #define id_to_f idTo_f +static ID id_instance_variables_to_inspect; #define CLASS_OR_MODULE_P(obj) \ (!SPECIAL_CONST_P(obj) && \ @@ -128,21 +124,22 @@ rb_class_allocate_instance(VALUE klass) size = sizeof(struct RObject); } - NEWOBJ_OF(o, struct RObject, klass, - T_OBJECT | ROBJECT_EMBED | (RGENGC_WB_PROTECTED_OBJECT ? FL_WB_PROTECTED : 0), size, 0); + // There might be a NEWOBJ tracepoint callback, and it may set fields. + // So the shape must be passed to `NEWOBJ_OF`. + VALUE flags = T_OBJECT | (RGENGC_WB_PROTECTED_OBJECT ? FL_WB_PROTECTED : 0); + NEWOBJ_OF_WITH_SHAPE(o, struct RObject, klass, flags, rb_shape_root(rb_gc_heap_id_for_size(size)), size, 0); VALUE obj = (VALUE)o; - RUBY_ASSERT(rb_obj_shape(obj)->type == SHAPE_ROOT); - - // Set the shape to the specific T_OBJECT shape. - ROBJECT_SET_SHAPE_ID(obj, rb_shape_root(rb_gc_heap_id_for_size(size))); - #if RUBY_DEBUG RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); VALUE *ptr = ROBJECT_FIELDS(obj); - for (size_t i = 0; i < ROBJECT_FIELDS_CAPACITY(obj); i++) { + size_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj)); + for (size_t i = fields_count; i < ROBJECT_FIELDS_CAPACITY(obj); i++) { ptr[i] = Qundef; } + if (rb_obj_class(obj) != rb_class_real(klass)) { + rb_bug("Expected rb_class_allocate_instance to set the class correctly"); + } #endif return obj; @@ -165,7 +162,7 @@ rb_obj_setup(VALUE obj, VALUE klass, VALUE type) * * Returns +true+ or +false+. * - * Like Object#==, if +object+ is an instance of Object + * Like Object#==, if +other+ is an instance of \Object * (and not an instance of one of its many subclasses). * * This method is commonly overridden by those subclasses, @@ -203,14 +200,18 @@ rb_eql(VALUE obj1, VALUE obj2) /** * call-seq: - * obj == other -> true or false - * obj.equal?(other) -> true or false - * obj.eql?(other) -> true or false + * self == other -> true or false + * equal?(other) -> true or false + * eql?(other) -> true or false * - * Equality --- At the Object level, #== returns <code>true</code> - * only if +obj+ and +other+ are the same object. Typically, this - * method is overridden in descendant classes to provide - * class-specific meaning. + * Returns whether +self+ and +other+ are the same object: + * + * object = Object.new + * object == object # => true + * object == Object.new # => false + * + * Here in class \Object, #==, #equal?, and #eql? are the same method. + * A subclass may override #== to provide class-specific meaning. * * Unlike #==, the #equal? method should never be overridden by * subclasses as it is used to determine object identity (that is, @@ -283,12 +284,32 @@ rb_obj_not_equal(VALUE obj1, VALUE obj2) return rb_obj_not(result); } +static inline VALUE +fake_class_p(VALUE klass) +{ + RUBY_ASSERT(klass); + RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS)); + STATIC_ASSERT(t_iclass_overlap_t_class, !(T_CLASS & T_ICLASS)); + STATIC_ASSERT(t_iclass_overlap_t_module, !(T_MODULE & T_ICLASS)); + + return FL_TEST_RAW(klass, T_ICLASS | FL_SINGLETON); +} + +static inline VALUE +class_real(VALUE cl) +{ + RUBY_ASSERT(cl); + while (RB_UNLIKELY(fake_class_p(cl))) { + cl = RCLASS_SUPER(cl); + } + return cl; +} + VALUE rb_class_real(VALUE cl) { - while (cl && - (RCLASS_SINGLETON_P(cl) || BUILTIN_TYPE(cl) == T_ICLASS)) { - cl = RCLASS_SUPER(cl); + if (cl) { + cl = class_real(cl); } return cl; } @@ -296,7 +317,17 @@ rb_class_real(VALUE cl) VALUE rb_obj_class(VALUE obj) { - return rb_class_real(CLASS_OF(obj)); + VALUE cl = CLASS_OF(obj); + if (cl) { + cl = class_real(cl); + } + return cl; +} + +static inline VALUE +rb_obj_class_must(VALUE obj) +{ + return class_real(CLASS_OF(obj)); } /* @@ -327,7 +358,6 @@ void rb_obj_copy_ivar(VALUE dest, VALUE obj) { RUBY_ASSERT(!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE)); - RUBY_ASSERT(BUILTIN_TYPE(dest) == BUILTIN_TYPE(obj)); unsigned long src_num_ivs = rb_ivar_count(obj); @@ -335,69 +365,39 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj) return; } - rb_shape_t *src_shape = rb_obj_shape(obj); - - if (rb_shape_too_complex_p(src_shape)) { - // obj is TOO_COMPLEX so we can copy its iv_hash - st_table *table = st_copy(ROBJECT_FIELDS_HASH(obj)); - if (rb_shape_has_object_id(src_shape)) { - st_data_t id = (st_data_t)ruby_internal_object_id; - st_delete(table, &id, NULL); - } - rb_obj_init_too_complex(dest, table); + shape_id_t src_shape_id = RBASIC_SHAPE_ID(obj); + if (rb_shape_too_complex_p(src_shape_id)) { + rb_shape_copy_complex_ivars(dest, obj, src_shape_id, ROBJECT_FIELDS_HASH(obj)); return; } - rb_shape_t *shape_to_set_on_dest = src_shape; - rb_shape_t *initial_shape = rb_obj_shape(dest); - - if (initial_shape->heap_index != src_shape->heap_index || !rb_shape_canonical_p(src_shape)) { - RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT); + shape_id_t initial_shape_id = RBASIC_SHAPE_ID(dest); + RUBY_ASSERT(RSHAPE_TYPE_P(initial_shape_id, SHAPE_ROOT)); - shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape); - if (UNLIKELY(rb_shape_too_complex_p(shape_to_set_on_dest))) { - st_table *table = rb_st_init_numtable_with_size(src_num_ivs); - rb_obj_copy_ivs_to_hash_table(obj, table); - rb_obj_init_too_complex(dest, table); + shape_id_t dest_shape_id = rb_shape_rebuild(initial_shape_id, src_shape_id); + if (UNLIKELY(rb_shape_too_complex_p(dest_shape_id))) { + st_table *table = rb_st_init_numtable_with_size(src_num_ivs); + rb_obj_copy_ivs_to_hash_table(obj, table); + rb_obj_init_too_complex(dest, table); - return; - } + return; } VALUE *src_buf = ROBJECT_FIELDS(obj); VALUE *dest_buf = ROBJECT_FIELDS(dest); - RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity); - if (initial_shape->capacity < shape_to_set_on_dest->capacity) { - rb_ensure_iv_list_size(dest, initial_shape->capacity, shape_to_set_on_dest->capacity); - dest_buf = ROBJECT_FIELDS(dest); - } - - if (src_shape->next_field_index == shape_to_set_on_dest->next_field_index) { - // Happy path, we can just memcpy the fields content - MEMCPY(dest_buf, src_buf, VALUE, src_num_ivs); + attr_index_t initial_capa = RSHAPE_CAPACITY(initial_shape_id); + attr_index_t dest_capa = RSHAPE_CAPACITY(dest_shape_id); - // Fire write barriers - for (uint32_t i = 0; i < src_num_ivs; i++) { - RB_OBJ_WRITTEN(dest, Qundef, dest_buf[i]); - } - } - else { - rb_shape_t *dest_shape = shape_to_set_on_dest; - while (src_shape->parent_id != INVALID_SHAPE_ID) { - if (src_shape->type == SHAPE_IVAR) { - while (dest_shape->edge_name != src_shape->edge_name) { - dest_shape = RSHAPE(dest_shape->parent_id); - } - - RB_OBJ_WRITE(dest, &dest_buf[dest_shape->next_field_index - 1], src_buf[src_shape->next_field_index - 1]); - } - src_shape = RSHAPE(src_shape->parent_id); - } + RUBY_ASSERT(src_num_ivs <= dest_capa); + if (initial_capa < dest_capa) { + rb_ensure_iv_list_size(dest, 0, dest_capa); + dest_buf = ROBJECT_FIELDS(dest); } - rb_shape_set_shape(dest, shape_to_set_on_dest); + rb_shape_copy_fields(dest, dest_buf, dest_shape_id, src_buf, src_shape_id); + RBASIC_SET_SHAPE_ID(dest, dest_shape_id); } static void @@ -406,14 +406,23 @@ init_copy(VALUE dest, VALUE obj) if (OBJ_FROZEN(dest)) { rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest)); } - RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR); + RBASIC(dest)->flags &= ~T_MASK; // Copies the shape id from obj to dest - RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR); - if (RB_TYPE_P(obj, T_OBJECT)) { + RBASIC(dest)->flags |= RBASIC(obj)->flags & T_MASK; + switch (BUILTIN_TYPE(obj)) { + case T_IMEMO: + rb_bug("Unreachable"); + break; + case T_CLASS: + case T_MODULE: + rb_mod_init_copy(dest, obj); + break; + case T_OBJECT: rb_obj_copy_ivar(dest, obj); - } - else { + break; + default: rb_copy_generic_ivar(dest, obj); + break; } rb_gc_copy_attributes(dest, obj); } @@ -522,12 +531,7 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze) if (RB_OBJ_FROZEN(obj)) { shape_id_t next_shape_id = rb_shape_transition_frozen(clone); - if (!rb_shape_obj_too_complex_p(clone) && rb_shape_id_too_complex_p(next_shape_id)) { - rb_evict_ivars_to_hash(clone); - } - else { - rb_shape_set_shape_id(clone, next_shape_id); - } + RBASIC_SET_SHAPE_ID(clone, next_shape_id); } break; case Qtrue: { @@ -542,16 +546,7 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze) argv[0] = obj; argv[1] = freeze_true_hash; rb_funcallv_kw(clone, id_init_clone, 2, argv, RB_PASS_KEYWORDS); - RBASIC(clone)->flags |= FL_FREEZE; - shape_id_t next_shape_id = rb_shape_transition_frozen(clone); - // If we're out of shapes, but we want to freeze, then we need to - // evacuate this clone to a hash - if (!rb_shape_obj_too_complex_p(clone) && rb_shape_id_too_complex_p(next_shape_id)) { - rb_evict_ivars_to_hash(clone); - } - else { - rb_shape_set_shape_id(clone, next_shape_id); - } + OBJ_FREEZE(clone); break; } case Qfalse: { @@ -770,11 +765,17 @@ rb_inspect(VALUE obj) static int inspect_i(ID id, VALUE value, st_data_t a) { - VALUE str = (VALUE)a; + VALUE *args = (VALUE *)a, str = args[0], ivars = args[1]; /* need not to show internal data */ if (CLASS_OF(value) == 0) return ST_CONTINUE; if (!rb_is_instance_id(id)) return ST_CONTINUE; + if (!NIL_P(ivars)) { + VALUE name = ID2SYM(id); + for (long i = 0; RARRAY_AREF(ivars, i) != name; ) { + if (++i >= RARRAY_LEN(ivars)) return ST_CONTINUE; + } + } if (RSTRING_PTR(str)[0] == '-') { /* first element */ RSTRING_PTR(str)[0] = '#'; rb_str_cat2(str, " "); @@ -789,13 +790,15 @@ inspect_i(ID id, VALUE value, st_data_t a) } static VALUE -inspect_obj(VALUE obj, VALUE str, int recur) +inspect_obj(VALUE obj, VALUE a, int recur) { + VALUE *args = (VALUE *)a, str = args[0]; + if (recur) { rb_str_cat2(str, " ..."); } else { - rb_ivar_foreach(obj, inspect_i, str); + rb_ivar_foreach(obj, inspect_i, a); } rb_str_cat2(str, ">"); RSTRING_PTR(str)[0] = '#'; @@ -828,23 +831,67 @@ inspect_obj(VALUE obj, VALUE str, int recur) * end * end * Bar.new.inspect #=> "#<Bar:0x0300c868 @bar=1>" + * + * If _obj_ responds to +instance_variables_to_inspect+, then only + * the instance variables listed in the returned array will be included + * in the inspect string. + * + * + * class DatabaseConfig + * def initialize(host, user, password) + * @host = host + * @user = user + * @password = password + * end + * + * private + * def instance_variables_to_inspect = [:@host, :@user] + * end + * + * conf = DatabaseConfig.new("localhost", "root", "hunter2") + * conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root"> */ static VALUE rb_obj_inspect(VALUE obj) { - if (rb_ivar_count(obj) > 0) { - VALUE str; - VALUE c = rb_class_name(CLASS_OF(obj)); + VALUE ivars = rb_check_funcall(obj, id_instance_variables_to_inspect, 0, 0); + st_index_t n = 0; + if (UNDEF_P(ivars) || NIL_P(ivars)) { + n = rb_ivar_count(obj); + ivars = Qnil; + } + else if (RB_TYPE_P(ivars, T_ARRAY)) { + n = RARRAY_LEN(ivars); + } + else { + rb_raise( + rb_eTypeError, + "Expected #instance_variables_to_inspect to return an Array or nil, but it returned %"PRIsVALUE, + rb_obj_class(ivars) + ); + } - str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void*)obj); - return rb_exec_recursive(inspect_obj, obj, str); + if (n > 0) { + VALUE c = rb_class_name(CLASS_OF(obj)); + VALUE args[2] = { + rb_sprintf("-<%"PRIsVALUE":%p", c, (void*)obj), + ivars + }; + return rb_exec_recursive(inspect_obj, obj, (VALUE)args); } else { return rb_any_to_s(obj); } } +/* :nodoc: */ +static VALUE +rb_obj_instance_variables_to_inspect(VALUE obj) +{ + return Qnil; +} + static VALUE class_or_module_required(VALUE c) { @@ -1723,21 +1770,33 @@ rb_obj_not_match(VALUE obj1, VALUE obj2) /* * call-seq: - * obj <=> other -> 0 or nil + * self <=> other -> 0 or nil * - * Returns 0 if +obj+ and +other+ are the same object - * or <code>obj == other</code>, otherwise nil. + * Compares +self+ and +other+. * - * The #<=> is used by various methods to compare objects, for example - * Enumerable#sort, Enumerable#max etc. + * Returns: * - * Your implementation of #<=> should return one of the following values: -1, 0, - * 1 or nil. -1 means self is smaller than other. 0 means self is equal to other. - * 1 means self is bigger than other. Nil means the two values could not be - * compared. + * - +0+, if +self+ and +other+ are the same object, + * or if <tt>self == other</tt>. + * - +nil+, otherwise. + * + * Examples: + * + * o = Object.new + * o <=> o # => 0 + * o <=> o.dup # => nil + * + * A class that includes module Comparable + * should override this method by defining an instance method that: + * + * - Take one argument, +other+. + * - Returns: + * + * - +-1+, if +self+ is less than +other+. + * - +0+, if +self+ is equal to +other+. + * - +1+, if +self+ is greater than +other+. + * - +nil+, if the two values are incommensurate. * - * When you define #<=>, you can include Comparable to gain the - * methods #<=, #<, #==, #>=, #> and #between?. */ static VALUE rb_obj_cmp(VALUE obj1, VALUE obj2) @@ -1837,11 +1896,12 @@ rb_mod_freeze(VALUE mod) /* * call-seq: - * mod === obj -> true or false + * self === other -> true or false + * + * Returns whether +other+ is an instance of +self+, + * or is an instance of a subclass of +self+. * - * Case Equality---Returns <code>true</code> if <i>obj</i> is an - * instance of <i>mod</i> or an instance of one of <i>mod</i>'s descendants. - * Of limited use for modules, but can be used in <code>case</code> statements + * Of limited use for modules, but can be used in +case+ statements * to classify objects by class. */ @@ -1855,11 +1915,24 @@ rb_mod_eqq(VALUE mod, VALUE arg) * call-seq: * mod <= other -> true, false, or nil * - * Returns true if <i>mod</i> is a subclass of <i>other</i> or - * is the same as <i>other</i>. Returns - * <code>nil</code> if there's no relationship between the two. - * (Think of the relationship in terms of the class definition: - * "class A < B" implies "A < B".) + * Returns +true+ if +self+ is a descendant of +other+ + * (+self+ is a subclass of +other+ or +self+ includes +other+) or + * if +self+ is the same as +other+: + * + * Float <= Numeric # => true + * Array <= Enumerable # => true + * Float <= Float # => true + * + * Returns +false+ if +self+ is an ancestor of +other+ + * (+self+ is a superclass of +other+ or +self+ is included in +other+): + * + * Numeric <= Float # => false + * Enumerable <= Array # => false + * + * Returns +nil+ if there is no relationship between the two: + * + * Float <= Hash # => nil + * Enumerable <= String # => nil */ VALUE @@ -1905,14 +1978,26 @@ rb_class_inherited_p(VALUE mod, VALUE arg) /* * call-seq: - * mod < other -> true, false, or nil + * self < other -> true, false, or nil + * + * Returns +true+ if +self+ is a descendant of +other+ + * (+self+ is a subclass of +other+ or +self+ includes +other+): + * + * Float < Numeric # => true + * Array < Enumerable # => true + * + * Returns +false+ if +self+ is an ancestor of +other+ + * (+self+ is a superclass of +other+ or +self+ is included in +other+) or + * if +self+ is the same as +other+: + * + * Numeric < Float # => false + * Enumerable < Array # => false + * Float < Float # => false * - * Returns true if <i>mod</i> is a subclass of <i>other</i>. Returns - * <code>false</code> if <i>mod</i> is the same as <i>other</i> - * or <i>mod</i> is an ancestor of <i>other</i>. - * Returns <code>nil</code> if there's no relationship between the two. - * (Think of the relationship in terms of the class definition: - * "class A < B" implies "A < B".) + * Returns +nil+ if there is no relationship between the two: + * + * Float < Hash # => nil + * Enumerable < String # => nil * */ @@ -1928,11 +2013,24 @@ rb_mod_lt(VALUE mod, VALUE arg) * call-seq: * mod >= other -> true, false, or nil * - * Returns true if <i>mod</i> is an ancestor of <i>other</i>, or the - * two modules are the same. Returns - * <code>nil</code> if there's no relationship between the two. - * (Think of the relationship in terms of the class definition: - * "class A < B" implies "B > A".) + * Returns +true+ if +self+ is an ancestor of +other+ + * (+self+ is a superclass of +other+ or +self+ is included in +other+) or + * if +self+ is the same as +other+: + * + * Numeric >= Float # => true + * Enumerable >= Array # => true + * Float >= Float # => true + * + * Returns +false+ if +self+ is a descendant of +other+ + * (+self+ is a subclass of +other+ or +self+ includes +other+): + * + * Float >= Numeric # => false + * Array >= Enumerable # => false + * + * Returns +nil+ if there is no relationship between the two: + * + * Float >= Hash # => nil + * Enumerable >= String # => nil * */ @@ -1948,14 +2046,26 @@ rb_mod_ge(VALUE mod, VALUE arg) /* * call-seq: - * mod > other -> true, false, or nil + * self > other -> true, false, or nil + * + * Returns +true+ if +self+ is an ancestor of +other+ + * (+self+ is a superclass of +other+ or +self+ is included in +other+): * - * Returns true if <i>mod</i> is an ancestor of <i>other</i>. Returns - * <code>false</code> if <i>mod</i> is the same as <i>other</i> - * or <i>mod</i> is a descendant of <i>other</i>. - * Returns <code>nil</code> if there's no relationship between the two. - * (Think of the relationship in terms of the class definition: - * "class A < B" implies "B > A".) + * Numeric > Float # => true + * Enumerable > Array # => true + * + * Returns +false+ if +self+ is a descendant of +other+ + * (+self+ is a subclass of +other+ or +self+ includes +other+) or + * if +self+ is the same as +other+: + * + * Float > Numeric # => false + * Array > Enumerable # => false + * Float > Float # => false + * + * Returns +nil+ if there is no relationship between the two: + * + * Float > Hash # => nil + * Enumerable > String # => nil * */ @@ -1968,14 +2078,30 @@ rb_mod_gt(VALUE mod, VALUE arg) /* * call-seq: - * module <=> other_module -> -1, 0, +1, or nil + * self <=> other -> -1, 0, 1, or nil * - * Comparison---Returns -1, 0, +1 or nil depending on whether +module+ - * includes +other_module+, they are the same, or if +module+ is included by - * +other_module+. + * Compares +self+ and +other+. + * + * Returns: + * + * - +-1+, if +self+ includes +other+, if or +self+ is a subclass of +other+. + * - +0+, if +self+ and +other+ are the same. + * - +1+, if +other+ includes +self+, or if +other+ is a subclass of +self+. + * - +nil+, if none of the above is true. + * + * Examples: + * + * # Class Array includes module Enumerable. + * Array <=> Enumerable # => -1 + * Enumerable <=> Enumerable # => 0 + * Enumerable <=> Array # => 1 + * # Class File is a subclass of class IO. + * File <=> IO # => -1 + * File <=> File # => 0 + * IO <=> File # => 1 + * # Class File has no relationship to class String. + * File <=> String # => nil * - * Returns +nil+ if +module+ has no relationship with +other_module+, if - * +other_module+ is not a module, or if the two values are incomparable. */ static VALUE @@ -2095,7 +2221,7 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass) else { super = argv[0]; rb_check_inheritable(super); - if (super != rb_cBasicObject && !RCLASS_SUPER(super)) { + if (!RCLASS_INITIALIZED_P(super)) { rb_raise(rb_eTypeError, "can't inherit uninitialized class"); } } @@ -2152,7 +2278,7 @@ class_get_alloc_func(VALUE klass) { rb_alloc_func_t allocator; - if (RCLASS_SUPER(klass) == 0 && klass != rb_cBasicObject) { + if (!RCLASS_INITIALIZED_P(klass)) { rb_raise(rb_eTypeError, "can't instantiate uninitialized class"); } if (RCLASS_SINGLETON_P(klass)) { @@ -2165,6 +2291,15 @@ class_get_alloc_func(VALUE klass) return allocator; } +// Might return NULL. +rb_alloc_func_t +rb_zjit_class_get_alloc_func(VALUE klass) +{ + assert(RCLASS_INITIALIZED_P(klass)); + assert(!RCLASS_SINGLETON_P(klass)); + return rb_get_alloc_func(klass); +} + static VALUE class_call_alloc_func(rb_alloc_func_t allocator, VALUE klass) { @@ -2174,8 +2309,10 @@ class_call_alloc_func(rb_alloc_func_t allocator, VALUE klass) obj = (*allocator)(klass); - if (rb_obj_class(obj) != rb_class_real(klass)) { - rb_raise(rb_eTypeError, "wrong instance allocation"); + if (UNLIKELY(RBASIC_CLASS(obj) != klass)) { + if (rb_obj_class(obj) != rb_class_real(klass)) { + rb_raise(rb_eTypeError, "wrong instance allocation"); + } } return obj; } @@ -2259,23 +2396,22 @@ rb_class_superclass(VALUE klass) { RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS)); - VALUE super = RCLASS_SUPER(klass); - VALUE *superclasses; - size_t superclasses_depth; + VALUE *superclasses = RCLASS_SUPERCLASSES(klass); + size_t superclasses_depth = RCLASS_SUPERCLASS_DEPTH(klass); + + if (klass == rb_cBasicObject) return Qnil; - if (!super) { - if (klass == rb_cBasicObject) return Qnil; + if (!superclasses) { + RUBY_ASSERT(!RCLASS_SUPER(klass)); rb_raise(rb_eTypeError, "uninitialized class"); } - superclasses_depth = RCLASS_SUPERCLASS_DEPTH(klass); if (!superclasses_depth) { return Qnil; } else { - superclasses = RCLASS_SUPERCLASSES(klass); - super = superclasses[superclasses_depth - 1]; - RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS)); + VALUE super = superclasses[superclasses_depth - 1]; + RUBY_ASSERT(RB_TYPE_P(super, T_CLASS)); return super; } } @@ -4056,7 +4192,7 @@ rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound) * into +format_string+. * * For details on +format_string+, see - * {Format Specifications}[rdoc-ref:format_specifications.rdoc]. + * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc]. */ static VALUE @@ -4497,6 +4633,7 @@ InitVM_Object(void) rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0); rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0); + rb_define_private_method(rb_mKernel, "instance_variables_to_inspect", rb_obj_instance_variables_to_inspect, 0); rb_define_method(rb_mKernel, "methods", rb_obj_methods, -1); /* in class.c */ rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, -1); /* in class.c */ rb_define_method(rb_mKernel, "protected_methods", rb_obj_protected_methods, -1); /* in class.c */ @@ -4545,7 +4682,6 @@ InitVM_Object(void) rb_define_method(rb_cModule, "<=", rb_class_inherited_p, 1); rb_define_method(rb_cModule, ">", rb_mod_gt, 1); rb_define_method(rb_cModule, ">=", rb_mod_ge, 1); - rb_define_method(rb_cModule, "initialize_copy", rb_mod_init_copy, 1); /* in class.c */ rb_define_method(rb_cModule, "to_s", rb_mod_to_s, 0); rb_define_alias(rb_cModule, "inspect", "to_s"); rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); /* in class.c */ @@ -4638,6 +4774,7 @@ void Init_Object(void) { id_dig = rb_intern_const("dig"); + id_instance_variables_to_inspect = rb_intern_const("instance_variables_to_inspect"); InitVM(Object); } |
