diff options
| author | Aaron Patterson <tenderlove@ruby-lang.org> | 2026-05-29 16:41:31 -0700 |
|---|---|---|
| committer | Aaron Patterson <tenderlove@ruby-lang.org> | 2026-05-29 16:41:31 -0700 |
| commit | ddb5055d961d970aded287cfebd07b78efee3ca7 (patch) | |
| tree | 0293266d352f9d0809fe17fdb6ab3ff833908e26 | |
| parent | 63d9f090b5d9461cf0b9446e0039d9c56156b826 (diff) | |
This reverts commit 63d9f090b5d9461cf0b9446e0039d9c56156b826.
| -rw-r--r-- | array.c | 2 | ||||
| -rw-r--r-- | class.c | 10 | ||||
| -rw-r--r-- | depend | 1 | ||||
| -rw-r--r-- | gc.c | 24 | ||||
| -rw-r--r-- | imemo.c | 18 | ||||
| -rw-r--r-- | internal/gc.h | 2 | ||||
| -rw-r--r-- | ractor.c | 2 | ||||
| -rw-r--r-- | shape.c | 78 | ||||
| -rw-r--r-- | shape.h | 54 | ||||
| -rw-r--r-- | string.c | 2 | ||||
| -rw-r--r-- | test/ruby/test_shapes.rb | 31 | ||||
| -rw-r--r-- | variable.c | 22 | ||||
| -rw-r--r-- | vm_insnhelper.c | 7 | ||||
| -rw-r--r-- | zjit/src/cruby_bindings.inc.rs | 7 |
14 files changed, 44 insertions, 216 deletions
@@ -30,7 +30,6 @@ #include "ruby/thread.h" #include "ruby/util.h" #include "ruby/ractor.h" -#include "shape.h" #include "vm_core.h" #include "builtin.h" @@ -910,7 +909,6 @@ init_fake_ary_flags(void) struct RArray fake_ary = {0}; fake_ary.basic.flags = T_ARRAY; VALUE ary = (VALUE)&fake_ary; - RBASIC_SET_SHAPE_ID(ary, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER); rb_ary_freeze(ary); return fake_ary.basic.flags; } @@ -585,15 +585,7 @@ class_alloc0(enum ruby_value_type type, VALUE klass, bool boxable) VALUE flags = type | FL_SHAREABLE; if (boxable) flags |= RCLASS_BOXABLE; - shape_id_t shape_id = ROOT_SHAPE_ID; - if (boxable) { - shape_id |= SHAPE_ID_LAYOUT_OTHER; - } - else { - shape_id |= SHAPE_ID_LAYOUT_RCLASS; - } - - struct RClass *obj = (struct RClass *)rb_newobj(GET_EC(), klass, flags, shape_id, true, alloc_size); + NEWOBJ_OF(obj, struct RClass, klass, flags, alloc_size); obj->object_id = 0; @@ -80,7 +80,6 @@ array.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h array.$(OBJEXT): $(top_srcdir)/internal/serial.h array.$(OBJEXT): $(top_srcdir)/internal/set_table.h array.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -array.$(OBJEXT): $(top_srcdir)/internal/struct.h array.$(OBJEXT): $(top_srcdir)/internal/variable.h array.$(OBJEXT): $(top_srcdir)/internal/vm.h array.$(OBJEXT): $(top_srcdir)/internal/warnings.h @@ -1056,15 +1056,7 @@ rb_newobj(rb_execution_context_t *ec, VALUE klass, VALUE flags, shape_id_t shape VALUE rb_ec_newobj_of(rb_execution_context_t *ec, VALUE klass, VALUE flags, size_t size) { - VALUE type = flags & T_MASK; - RUBY_ASSERT(type != T_OBJECT); - RUBY_ASSERT(type != T_DATA); - RUBY_ASSERT(type != T_CLASS); - RUBY_ASSERT(type != T_MODULE); - RUBY_ASSERT(type != T_ICLASS); - (void)type; - - return rb_newobj(ec, klass, flags, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, true, size); + return rb_newobj(ec, klass, flags, ROOT_SHAPE_ID, true, size); } VALUE @@ -1076,13 +1068,13 @@ rb_newobj_of_with_shape(VALUE klass, VALUE flags, shape_id_t shape_id, size_t si VALUE rb_newobj_of(VALUE klass, VALUE flags, size_t size) { - return rb_newobj(GET_EC(), klass, flags, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, true, size); + return rb_newobj(GET_EC(), klass, flags, ROOT_SHAPE_ID, true, size); } static VALUE class_allocate_complex_instance(VALUE klass, uint32_t capacity) { - shape_id_t initial_shape_id = rb_shape_id_with_robject_layout(rb_shape_root(rb_gc_heap_id_for_size(sizeof(struct RObject)))); + shape_id_t initial_shape_id = rb_shape_root(rb_gc_heap_id_for_size(sizeof(struct RObject))); VALUE obj = rb_newobj_of_with_shape(klass, T_OBJECT, initial_shape_id, sizeof(struct RObject)); rb_obj_init_complex(obj, rb_st_init_numtable_with_size(capacity)); return obj; @@ -1107,7 +1099,7 @@ rb_class_allocate_instance(VALUE klass) // There might be a NEWOBJ tracepoint callback, and it may set fields. // So the shape must be passed to `NEWOBJ_OF`. - obj = rb_newobj_of_with_shape(klass, T_OBJECT, rb_shape_id_with_robject_layout(rb_shape_root(rb_gc_heap_id_for_size(size))), size); + obj = rb_newobj_of_with_shape(klass, T_OBJECT, rb_shape_root(rb_gc_heap_id_for_size(size)), size); #if RUBY_DEBUG VALUE *ptr = ROBJECT_FIELDS(obj); @@ -1157,7 +1149,7 @@ typed_data_alloc(VALUE klass, VALUE typed_flag, void *datap, const rb_data_type_ RBIMPL_NONNULL_ARG(type); if (klass) rb_data_object_check(klass); bool wb_protected = (type->flags & RUBY_FL_WB_PROTECTED) || !type->function.dmark; - VALUE obj = rb_newobj(GET_EC(), klass, T_DATA, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_RDATA, wb_protected, size); + VALUE obj = rb_newobj(GET_EC(), klass, T_DATA, ROOT_SHAPE_ID, wb_protected, size); rb_gc_register_pinning_obj(obj); @@ -4197,11 +4189,7 @@ vm_weak_table_gen_fields_foreach(st_data_t key, st_data_t value, st_data_t data) break; case ST_DELETE: - // When we're removing an object from the weak ref table, we need to - // set the shape on it so that the GC finalizer won't try to remove - // it again. A "root shape" indicates to the GC that this object - // has no fields on it, hence it won't be in the gen fields table. - RBASIC_SET_SHAPE_ID((VALUE)key, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER); + RBASIC_SET_SHAPE_ID((VALUE)key, ROOT_SHAPE_ID); return ST_DELETE; case ST_REPLACE: { @@ -141,11 +141,7 @@ rb_imemo_fields_new(VALUE owner, shape_id_t shape_id, bool shareable) size_t embedded_size = offsetof(struct rb_fields, as.embed) + capa * sizeof(VALUE); RUBY_ASSERT(rb_gc_size_allocatable_p(embedded_size)); VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size, shareable); - // imemo fields objects should always have "RObject" layout. The - // layout in the shape describes the layout of the thing on which it is set. - // Imemo fields have the same layout as robject, therefore the layout - // should reflect that fact. - RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id)); + RBASIC_SET_SHAPE_ID(fields, shape_id); RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields)); return fields; } @@ -156,11 +152,7 @@ rb_imemo_fields_new_complex(VALUE owner, shape_id_t shape_id, size_t capa, bool VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable); IMEMO_OBJ_FIELDS(fields)->as.complex.table = st_init_numtable_with_size(capa); FL_SET_RAW(fields, OBJ_FIELD_HEAP); - // imemo fields objects should always have "RObject" layout. The - // layout in the shape describes the layout of the thing on which it is set. - // Imemo fields have the same layout as robject, therefore the layout - // should reflect that fact. - RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id)); + RBASIC_SET_SHAPE_ID(fields, shape_id); return fields; } @@ -185,11 +177,7 @@ rb_imemo_fields_new_complex_tbl(VALUE owner, shape_id_t shape_id, st_table *tbl, VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable); IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl; FL_SET_RAW(fields, OBJ_FIELD_HEAP); - // imemo fields objects should always have "RObject" layout. The - // layout in the shape describes the layout of the thing on which it is set. - // Imemo fields have the same layout as robject, therefore the layout - // should reflect that fact. - RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id)); + RBASIC_SET_SHAPE_ID(fields, shape_id); st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields); return fields; } diff --git a/internal/gc.h b/internal/gc.h index b78808370c..41675810c7 100644 --- a/internal/gc.h +++ b/internal/gc.h @@ -124,7 +124,7 @@ struct rb_objspace; /* in vm_core.h */ T *(var) = (T *)rb_ec_newobj_of((ec), (c), (f), s) #define NEWOBJ_OF(var, T, c, f, s) EC_NEWOBJ_OF(var, T, c, f, s, GET_EC()) #define UNPROTECTED_NEWOBJ_OF(var, T, c, f, s) \ - T *(var) = (T *)rb_newobj((GET_EC()), (c), (f), ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, false, s) + T *(var) = (T *)rb_newobj((GET_EC()), (c), (f), 0 /* ROOT_SHAPE_ID */, false, s) #ifndef RB_GC_OBJECT_METADATA_ENTRY_DEFINED # define RB_GC_OBJECT_METADATA_ENTRY_DEFINED @@ -2015,7 +2015,7 @@ move_enter(VALUE obj, struct obj_traverse_replace_data *data) else { VALUE type = RB_BUILTIN_TYPE(obj); size_t slot_size = rb_gc_obj_slot_size(obj); - VALUE moved = rb_newobj(GET_EC(), 0, type, RBASIC_SHAPE_ID(obj), wb_protected_types[type], slot_size); + VALUE moved = rb_newobj(GET_EC(), 0, type, 0, wb_protected_types[type], slot_size); MEMZERO(((struct RBasic *)moved) + 1, char, slot_size - sizeof(struct RBasic)); data->replacement = (VALUE)moved; return traverse_cont; @@ -409,14 +409,10 @@ rb_obj_shape_id(VALUE obj) if (BUILTIN_TYPE(obj) == T_CLASS || BUILTIN_TYPE(obj) == T_MODULE) { VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj); - shape_id_t base = ROOT_SHAPE_ID; if (fields_obj) { - // Remove the layout from the fields object. We want to - // combine the shape of the fields object with the layout of the - // class / module object. - base = RBASIC_SHAPE_ID(fields_obj) & ~SHAPE_ID_LAYOUT_MASK; + return RBASIC_SHAPE_ID(fields_obj); } - return rb_shape_layout(RBASIC_SHAPE_ID(obj)) | base; + return ROOT_SHAPE_ID; } return RBASIC_SHAPE_ID(obj); } @@ -701,7 +697,7 @@ rb_shape_transition_object_id(shape_id_t original_shape_id) bool dont_care; rb_shape_t *shape = get_next_shape_internal(RSHAPE(original_shape_id), id_object_id, SHAPE_OBJ_ID, &dont_care, true); if (!shape) { - return rb_shape_layout(original_shape_id) | ROOT_COMPLEX_WITH_OBJ_ID | RSHAPE_FLAGS(original_shape_id); + return ROOT_COMPLEX_WITH_OBJ_ID | RSHAPE_FLAGS(original_shape_id); } RUBY_ASSERT(shape); @@ -1229,55 +1225,17 @@ rb_shape_foreach_field(shape_id_t initial_shape_id, rb_shape_foreach_transition_ } #if RUBY_DEBUG -/* - * Get the layout of this object. The "layout" indicates what strategy - * we should use for fetching instance variables from `obj`. It's based - * on the C struct layout for each particular object. - * - * TODO: make Struct have a similar layout to RDATA - */ -static shape_id_t -rb_shape_expected_layout(VALUE obj) -{ - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - return SHAPE_ID_LAYOUT_ROBJECT; - case T_CLASS: - case T_MODULE: - if (FL_TEST_RAW(obj, RCLASS_BOXABLE)) { - return SHAPE_ID_LAYOUT_OTHER; - } - return SHAPE_ID_LAYOUT_RCLASS; - case T_DATA: - return SHAPE_ID_LAYOUT_RDATA; - case T_IMEMO: - if (IMEMO_TYPE_P(obj, imemo_fields)) { - return SHAPE_ID_LAYOUT_ROBJECT; - } - return SHAPE_ID_LAYOUT_OTHER; - default: - return SHAPE_ID_LAYOUT_OTHER; - } -} - bool rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id) { - if (shape_id == INVALID_SHAPE_ID) { - rb_bug("Can't set INVALID_SHAPE_ID on an object"); - } - - shape_id_t actual_layout = rb_shape_layout(rb_obj_shape_id(obj)); - shape_id_t expected_layout = rb_shape_expected_layout(obj); - if (actual_layout != expected_layout) { - rb_bug("shape_id layout mismatch: expected=%x actual=%x shape_id=%u obj=%s", - expected_layout, actual_layout, shape_id, rb_obj_info(obj)); - } - if (shape_id == ROOT_SHAPE_ID) { return true; } + if (shape_id == INVALID_SHAPE_ID) { + rb_bug("Can't set INVALID_SHAPE_ID on an object"); + } + rb_shape_t *shape = RSHAPE(shape_id); bool has_object_id = false; @@ -1291,11 +1249,13 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id) if (rb_shape_has_object_id(shape_id)) { if (!has_object_id) { + rb_p(obj); rb_bug("shape_id claim having obj_id but doesn't shape_id=%u, obj=%s", shape_id, rb_obj_info(obj)); } } else { if (has_object_id) { + rb_p(obj); rb_bug("shape_id claim not having obj_id but it does shape_id=%u, obj=%s", shape_id, rb_obj_info(obj)); } } @@ -1370,25 +1330,6 @@ shape_has_object_id_p(VALUE self) } static VALUE -shape_layout(VALUE self) -{ - shape_id_t shape_id = NUM2UINT(rb_struct_getmember(self, rb_intern("id"))); - - switch (rb_shape_layout(shape_id)) { - case SHAPE_ID_LAYOUT_ROBJECT: - return ID2SYM(rb_intern("robject")); - case SHAPE_ID_LAYOUT_RCLASS: - return ID2SYM(rb_intern("rclass")); - case SHAPE_ID_LAYOUT_RDATA: - return ID2SYM(rb_intern("rdata")); - case SHAPE_ID_LAYOUT_OTHER: - return ID2SYM(rb_intern("other")); - default: - rb_bug("unknown shape layout: %u", rb_shape_layout(shape_id)); - } -} - -static VALUE parse_key(ID key) { if (is_instance_id(key)) { @@ -1687,7 +1628,6 @@ Init_shape(void) rb_define_method(rb_cShape, "complex?", shape_complex, 0); rb_define_method(rb_cShape, "shape_frozen?", shape_frozen, 0); rb_define_method(rb_cShape, "has_object_id?", shape_has_object_id_p, 0); - rb_define_method(rb_cShape, "layout", shape_layout, 0); rb_define_const(rb_cShape, "SHAPE_ROOT", INT2NUM(SHAPE_ROOT)); rb_define_const(rb_cShape, "SHAPE_IVAR", INT2NUM(SHAPE_IVAR)); @@ -27,14 +27,12 @@ STATIC_ASSERT(shape_id_num_bits, SHAPE_ID_NUM_BITS == sizeof(shape_id_t) * CHAR_ // 19-22 SHAPE_ID_HEAP_INDEX_MASK // index in rb_shape_tree.capacities. Allow to access slot size. // Currently always 0 except for T_OBJECT. -// 23 SHAPE_ID_FL_COMPLEX -// The object is backed by a `st_table`. -// 24 SHAPE_ID_FL_FROZEN +// 23 SHAPE_ID_FL_FROZEN // Whether the object is frozen or not. -// 25 SHAPE_ID_FL_HAS_OBJECT_ID +// 24 SHAPE_ID_FL_HAS_OBJECT_ID // Whether the object has an `SHAPE_OBJ_ID` transition. -// 26-27 SHAPE_ID_LAYOUT_MASK -// The object's physical field layout. +// 25 SHAPE_ID_FL_COMPLEX +// The object is backed by a `st_table`. enum shape_id_fl_type { #define RBIMPL_SHAPE_ID_FL(n) (1<<(SHAPE_ID_FL_USHIFT+n)) @@ -45,26 +43,8 @@ enum shape_id_fl_type { SHAPE_ID_FL_FROZEN = RBIMPL_SHAPE_ID_FL(1), SHAPE_ID_FL_HAS_OBJECT_ID = RBIMPL_SHAPE_ID_FL(2), - // Means IVs are found at an offset from the object's addr, or in a - // malloc allocated side table - SHAPE_ID_LAYOUT_ROBJECT = 0, - - // Means this object is a class/module that is NOT RCLASS_BOXABLE, and IV's - // are found in the fields_obj found on the rclass struct - SHAPE_ID_LAYOUT_RCLASS = RBIMPL_SHAPE_ID_FL(3), - - // Means this object is an RData or RTypedData and IVs are found in the - // fields_obj found on the RData/RTypedData struct - SHAPE_ID_LAYOUT_RDATA = RBIMPL_SHAPE_ID_FL(4), - - // Means this is a complicated object: boxable classes, structs, objects - // that store IVs on the geniv table - SHAPE_ID_LAYOUT_OTHER = SHAPE_ID_LAYOUT_RCLASS | SHAPE_ID_LAYOUT_RDATA, - - SHAPE_ID_LAYOUT_MASK = SHAPE_ID_LAYOUT_OTHER, - SHAPE_ID_FL_NON_CANONICAL_MASK = SHAPE_ID_FL_FROZEN | SHAPE_ID_FL_HAS_OBJECT_ID, - SHAPE_ID_FLAGS_MASK = SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_NON_CANONICAL_MASK | SHAPE_ID_FL_COMPLEX | SHAPE_ID_LAYOUT_MASK, + SHAPE_ID_FLAGS_MASK = SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_NON_CANONICAL_MASK | SHAPE_ID_FL_COMPLEX, #undef RBIMPL_SHAPE_ID_FL }; @@ -75,13 +55,12 @@ enum shape_id_mask { SHAPE_ID_HAS_IVAR_MASK = SHAPE_ID_FL_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1), }; -// The interpreter doesn't care about frozen status, slot size, or object id, and -// has its own checks for physical field layout when reading ivars. +// The interpreter doesn't care about frozen status, slot size or object id when reading ivars. // So we normalize shape_id by clearing these bits to improve cache hits. // JITs however might care about some of it. -#define SHAPE_ID_READ_ONLY_MASK (~(SHAPE_ID_FL_FROZEN | SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_HAS_OBJECT_ID | SHAPE_ID_LAYOUT_MASK)) +#define SHAPE_ID_READ_ONLY_MASK (~(SHAPE_ID_FL_FROZEN | SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_HAS_OBJECT_ID)) // For write it's the same idea, but here we do care about frozen status. -#define SHAPE_ID_WRITE_MASK (~(SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_HAS_OBJECT_ID | SHAPE_ID_LAYOUT_MASK)) +#define SHAPE_ID_WRITE_MASK (~(SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_HAS_OBJECT_ID)) typedef uint32_t redblack_id_t; @@ -174,18 +153,11 @@ RBASIC_SET_SHAPE_ID_NO_CHECKS(VALUE obj, shape_id_t shape_id) #endif } -static inline shape_id_t -rb_shape_layout(shape_id_t shape_id) -{ - return shape_id & SHAPE_ID_LAYOUT_MASK; -} - static inline void RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id) { RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj)); RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_fields)); - RUBY_ASSERT(!IMEMO_TYPE_P(obj, imemo_fields) || rb_shape_layout(shape_id) == SHAPE_ID_LAYOUT_ROBJECT); RBASIC_SET_SHAPE_ID_NO_CHECKS(obj, shape_id); @@ -260,12 +232,6 @@ rb_shape_canonical_p(shape_id_t shape_id) return !(shape_id & SHAPE_ID_FL_NON_CANONICAL_MASK); } -static inline shape_id_t -rb_shape_id_with_robject_layout(shape_id_t shape_id) -{ - return (shape_id & ~SHAPE_ID_LAYOUT_MASK) | SHAPE_ID_LAYOUT_ROBJECT; -} - static inline uint8_t rb_shape_heap_index(shape_id_t shape_id) { @@ -484,10 +450,10 @@ rb_shape_transition_frozen(shape_id_t shape_id) static inline shape_id_t rb_shape_transition_complex(shape_id_t shape_id) { - shape_id_t next_shape_id = rb_shape_layout(shape_id) | ROOT_COMPLEX_SHAPE_ID; + shape_id_t next_shape_id = ROOT_COMPLEX_SHAPE_ID; if (rb_shape_has_object_id(shape_id)) { - next_shape_id = rb_shape_layout(shape_id) | ROOT_COMPLEX_WITH_OBJ_ID; + next_shape_id = ROOT_COMPLEX_WITH_OBJ_ID; } uint8_t heap_index = rb_shape_heap_index(shape_id); @@ -630,7 +630,7 @@ static VALUE setup_fake_str(struct RString *fake_str, const char *name, long len, int encidx) { fake_str->basic.flags = T_STRING|RSTRING_NOEMBED|STR_NOFREE|STR_FAKESTR; - RBASIC_SET_SHAPE_ID((VALUE)fake_str, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER); + RBASIC_SET_SHAPE_ID((VALUE)fake_str, ROOT_SHAPE_ID); if (!name) { RUBY_ASSERT_ALWAYS(len == 0); diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb index bace69658a..ef5dbd9fb1 100644 --- a/test/ruby/test_shapes.rb +++ b/test/ruby/test_shapes.rb @@ -1067,37 +1067,6 @@ class TestShapes < Test::Unit::TestCase assert_nil shape.parent end - def test_shape_layout - assert_equal :robject, RubyVM::Shape.of(TestObject.new).layout - - if ENV["RUBY_BOX"] - assert_equal :other, RubyVM::Shape.of(Kernel).layout - assert_equal :other, RubyVM::Shape.of(String).layout - else - assert_equal :rclass, RubyVM::Shape.of(Kernel).layout - assert_equal :rclass, RubyVM::Shape.of(String).layout - end - - assert_equal :rclass, RubyVM::Shape.of(Class.new).layout - assert_equal :rclass, RubyVM::Shape.of(Module.new).layout - - klass = Class.new - assert_equal :rclass, RubyVM::Shape.of(klass).layout - klass.instance_variable_set(:@a, 123) - assert_equal :rclass, RubyVM::Shape.of(klass).layout - - assert_equal :rdata, RubyVM::Shape.of(Thread.current).layout - assert_equal :rdata, RubyVM::Shape.of(lambda {}).layout - - assert_equal :other, RubyVM::Shape.of(Struct.new(:x).new(1)).layout - assert_equal :other, RubyVM::Shape.of([]).layout - assert_equal :other, RubyVM::Shape.of("hello").layout - assert_equal :other, RubyVM::Shape.of(/foo/).layout - assert_equal :other, RubyVM::Shape.of(2..3).layout - assert_equal :other, RubyVM::Shape.of(2**67).layout - assert_equal :other, RubyVM::Shape.of(:"aaroniscool#{123}").layout - end - def test_str_has_root_shape assert_shape_equal(RubyVM::Shape.root_shape, RubyVM::Shape.of("")) end diff --git a/variable.c b/variable.c index 687fa03631..857d870413 100644 --- a/variable.c +++ b/variable.c @@ -1343,7 +1343,7 @@ rb_free_generic_ivar(VALUE obj) } } } - RBASIC_SET_SHAPE_ID(obj, rb_shape_layout(RBASIC_SHAPE_ID(obj)) | ROOT_SHAPE_ID); + RBASIC_SET_SHAPE_ID(obj, ROOT_SHAPE_ID); } } @@ -1395,7 +1395,7 @@ rb_obj_set_fields(VALUE obj, VALUE fields_obj, ID field_name, VALUE original_fie } } - RBASIC_SET_SHAPE_ID(obj, rb_shape_layout(RBASIC_SHAPE_ID(obj)) | RBASIC_SHAPE_ID(fields_obj)); + RBASIC_SET_SHAPE_ID(obj, RBASIC_SHAPE_ID(fields_obj)); } void @@ -1710,7 +1710,6 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef) size_t trailing_fields = new_fields_count - removed_index; MEMMOVE(&fields[removed_index], &fields[removed_index + 1], VALUE, trailing_fields); - RUBY_ASSERT(rb_shape_layout(next_shape_id) == SHAPE_ID_LAYOUT_ROBJECT); RBASIC_SET_SHAPE_ID(fields_obj, next_shape_id); if (FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP)) { @@ -1733,7 +1732,7 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef) } } - RBASIC_SET_SHAPE_ID(obj, rb_shape_layout(RBASIC_SHAPE_ID(obj)) | next_shape_id); + RBASIC_SET_SHAPE_ID(obj, next_shape_id); if (fields_obj != original_fields_obj) { switch (type) { case T_OBJECT: @@ -1844,7 +1843,7 @@ imemo_fields_set(VALUE owner, VALUE fields_obj, shape_id_t target_shape_id, ID f RUBY_ASSERT(field_name); st_insert(table, (st_data_t)field_name, (st_data_t)val); RB_OBJ_WRITTEN(fields_obj, Qundef, val); - RBASIC_SET_SHAPE_ID(fields_obj, rb_shape_id_with_robject_layout(target_shape_id)); + RBASIC_SET_SHAPE_ID(fields_obj, target_shape_id); } else { attr_index_t index = RSHAPE_INDEX(target_shape_id); @@ -1856,7 +1855,7 @@ imemo_fields_set(VALUE owner, VALUE fields_obj, shape_id_t target_shape_id, ID f RB_OBJ_WRITE(fields_obj, &table[index], val); if (index >= RSHAPE_LEN(current_shape_id)) { - RBASIC_SET_SHAPE_ID(fields_obj, rb_shape_id_with_robject_layout(target_shape_id)); + RBASIC_SET_SHAPE_ID(fields_obj, target_shape_id); } } @@ -2011,12 +2010,11 @@ rb_obj_freeze_inline(VALUE x) RB_FL_UNSET_RAW(x, FL_USER2 | FL_USER3); // STR_CHILLED } - // rb_obj_freeze_inline(String) shape_id_t shape_id = rb_obj_shape_transition_frozen(x); switch (BUILTIN_TYPE(x)) { case T_CLASS: case T_MODULE: - rb_obj_freeze_inline(RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(x)); + RBASIC_SET_SHAPE_ID(RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(x), shape_id); // FIXME: How to do multi-shape? RBASIC_SET_SHAPE_ID(x, shape_id); break; @@ -2305,7 +2303,7 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj) } if (!RSHAPE_LEN(dest_shape_id)) { - RBASIC_SET_SHAPE_ID(dest, rb_shape_layout(RBASIC_SHAPE_ID(dest)) | dest_shape_id); + RBASIC_SET_SHAPE_ID(dest, dest_shape_id); return; } @@ -4638,7 +4636,6 @@ class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool conc } if (new_ivar) { - RUBY_ASSERT(rb_shape_layout(next_shape_id) == SHAPE_ID_LAYOUT_ROBJECT); RBASIC_SET_SHAPE_ID(fields_obj, next_shape_id); } } @@ -4661,7 +4658,6 @@ complex: RB_OBJ_WRITTEN(fields_obj, Qundef, val); if (fields_obj != original_fields_obj) { - RUBY_ASSERT(rb_shape_layout(next_shape_id) == SHAPE_ID_LAYOUT_ROBJECT); RBASIC_SET_SHAPE_ID(fields_obj, next_shape_id); } } @@ -4688,7 +4684,7 @@ class_ivar_set(VALUE obj, ID id, VALUE val, bool *new_ivar) // TODO: What should we set as the T_CLASS shape_id? // In most case we can replicate the single `fields_obj` shape // but in namespaced case? Perhaps INVALID_SHAPE_ID? - RBASIC_SET_SHAPE_ID(obj, rb_shape_layout(RBASIC_SHAPE_ID(obj)) | RBASIC_SHAPE_ID(new_fields_obj)); + RBASIC_SET_SHAPE_ID(obj, RBASIC_SHAPE_ID(new_fields_obj)); return index; } @@ -4713,7 +4709,7 @@ rb_fields_tbl_copy(VALUE dst, VALUE src) VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(src); if (fields_obj) { RCLASS_WRITABLE_SET_FIELDS_OBJ(dst, rb_imemo_fields_clone(fields_obj)); - RBASIC_SET_SHAPE_ID(dst, rb_shape_layout(RBASIC_SHAPE_ID(dst)) | RBASIC_SHAPE_ID(src)); + RBASIC_SET_SHAPE_ID(dst, RBASIC_SHAPE_ID(src)); } } diff --git a/vm_insnhelper.c b/vm_insnhelper.c index f515662bf0..ac0d81092d 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1412,8 +1412,7 @@ vm_setivar_class(VALUE obj, VALUE val, rb_setivar_cache cache) RB_OBJ_WRITE(fields_obj, &rb_imemo_fields_ptr(fields_obj)[cache.index], val); if (shape_id != dest_shape_id) { - // The dest_shape_id comes from the fields_obj - RBASIC_SET_SHAPE_ID(obj, SHAPE_ID_LAYOUT_RCLASS | (dest_shape_id & ~SHAPE_ID_LAYOUT_MASK)); + RBASIC_SET_SHAPE_ID(obj, dest_shape_id); RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id); } @@ -1438,9 +1437,7 @@ vm_setivar_default(VALUE obj, ID id, VALUE val, rb_setivar_cache cache) if (shape_id != dest_shape_id) { RBASIC_SET_SHAPE_ID(obj, dest_shape_id); - // The dest_shape_id comes from the owner, but fields_obj must always - // have layout RObject, so give the fields_object the right layout. - RBASIC_SET_SHAPE_ID(fields_obj, rb_shape_id_with_robject_layout(dest_shape_id)); + RBASIC_SET_SHAPE_ID(fields_obj, dest_shape_id); } RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index 08c502b0d8..bd832acc96 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -1491,13 +1491,8 @@ pub const SHAPE_ID_HEAP_INDEX_MASK: shape_id_fl_type = 7864320; pub const SHAPE_ID_FL_COMPLEX: shape_id_fl_type = 8388608; pub const SHAPE_ID_FL_FROZEN: shape_id_fl_type = 16777216; pub const SHAPE_ID_FL_HAS_OBJECT_ID: shape_id_fl_type = 33554432; -pub const SHAPE_ID_LAYOUT_ROBJECT: shape_id_fl_type = 0; -pub const SHAPE_ID_LAYOUT_RCLASS: shape_id_fl_type = 67108864; -pub const SHAPE_ID_LAYOUT_RDATA: shape_id_fl_type = 134217728; -pub const SHAPE_ID_LAYOUT_OTHER: shape_id_fl_type = 201326592; -pub const SHAPE_ID_LAYOUT_MASK: shape_id_fl_type = 201326592; pub const SHAPE_ID_FL_NON_CANONICAL_MASK: shape_id_fl_type = 50331648; -pub const SHAPE_ID_FLAGS_MASK: shape_id_fl_type = 267911168; +pub const SHAPE_ID_FLAGS_MASK: shape_id_fl_type = 66584576; pub type shape_id_fl_type = u32; pub const CONST_DEPRECATED: rb_const_flag_t = 256; pub const CONST_VISIBILITY_MASK: rb_const_flag_t = 255; |
