diff options
author | Jean Boussier <[email protected]> | 2025-06-04 13:35:43 +0200 |
---|---|---|
committer | Jean Boussier <[email protected]> | 2025-06-05 22:06:15 +0200 |
commit | 4e39580992064a4e91e9b8626a1a220f262a7011 () | |
tree | 283baa3f6d9bdac213a6f6b44a12580d7a2f6b84 | |
parent | 0b07d2a1e32a456fc302c8d970fa85782bdb98ce (diff) |
Refactor raw accesses to rb_shape_t.capacity
Notes: Merged: https://.com/ruby/ruby/pull/13524
-rw-r--r-- | internal/variable.h | 2 | ||||
-rw-r--r-- | object.c | 9 | ||||
-rw-r--r-- | shape.c | 7 | ||||
-rw-r--r-- | shape.h | 2 | ||||
-rw-r--r-- | test/ruby/test_shapes.rb | 21 | ||||
-rw-r--r-- | variable.c | 12 | ||||
-rw-r--r-- | vm_insnhelper.c | 10 | ||||
-rw-r--r-- | yjit.c | 6 | ||||
-rw-r--r-- | yjit/bindgen/src/main.rs | 1 | ||||
-rw-r--r-- | yjit/src/codegen.rs | 12 | ||||
-rw-r--r-- | yjit/src/cruby_bindings.inc.rs | 3 | ||||
-rw-r--r-- | zjit/src/cruby_bindings.inc.rs | 2 |
12 files changed, 53 insertions, 34 deletions
@@ -70,7 +70,7 @@ VALUE rb_gvar_get(ID); VALUE rb_gvar_set(ID, VALUE); VALUE rb_gvar_defined(ID); void rb_const_warn_if_deprecated(const rb_const_entry_t *, VALUE, ID); -void rb_ensure_iv_list_size(VALUE obj, uint32_t len, uint32_t newsize); attr_index_t rb_obj_ivar_set(VALUE obj, ID id, VALUE val); #endif /* INTERNAL_VARIABLE_H */ @@ -355,9 +355,12 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj) VALUE *src_buf = ROBJECT_FIELDS(obj); VALUE *dest_buf = ROBJECT_FIELDS(dest); - RUBY_ASSERT(src_num_ivs <= RSHAPE(dest_shape_id)->capacity); - if (RSHAPE(initial_shape_id)->capacity < RSHAPE(dest_shape_id)->capacity) { - rb_ensure_iv_list_size(dest, RSHAPE(initial_shape_id)->capacity, RSHAPE(dest_shape_id)->capacity); dest_buf = ROBJECT_FIELDS(dest); } @@ -321,7 +321,7 @@ static void shape_tree_compact(void *data) { rb_shape_t *cursor = rb_shape_get_root_shape(); - rb_shape_t *end = RSHAPE(GET_SHAPE_TREE()->next_shape_id); while (cursor < end) { if (cursor->edges && !SINGLE_CHILD_P(cursor->edges)) { cursor->edges = rb_gc_location(cursor->edges); @@ -1107,6 +1107,8 @@ shape_rebuild(rb_shape_t *initial_shape, rb_shape_t *dest_shape) return midway_shape; } shape_id_t rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id) { @@ -1135,6 +1137,9 @@ rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALU 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); } @@ -232,7 +232,7 @@ ROBJECT_FIELDS_CAPACITY(VALUE obj) // Asking for capacity doesn't make sense when the object is using // a hash table for storing instance variables RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); - return RSHAPE(RBASIC_SHAPE_ID(obj))->capacity; } static inline st_table * @@ -92,15 +92,18 @@ class TestShapes < Test::Unit::TestCase # RubyVM::Shape.of returns new instances of shape objects for # each call. This helper method allows us to define equality for # shapes - def assert_shape_equal(shape1, shape2) - assert_equal(shape1.id, shape2.id) - assert_equal(shape1.parent_id, shape2.parent_id) - assert_equal(shape1.depth, shape2.depth) - assert_equal(shape1.type, shape2.type) - end - - def refute_shape_equal(shape1, shape2) - refute_equal(shape1.id, shape2.id) end def test_iv_order_correct_on_complex_objects @@ -1825,13 +1825,13 @@ generic_fields_lookup_ensure_size(st_data_t *k, st_data_t *v, st_data_t u, int e if (!existing || fields_lookup->resize) { if (existing) { RUBY_ASSERT(RSHAPE(fields_lookup->shape_id)->type == SHAPE_IVAR || RSHAPE(fields_lookup->shape_id)->type == SHAPE_OBJ_ID); - RUBY_ASSERT(RSHAPE(RSHAPE(fields_lookup->shape_id)->parent_id)->capacity < RSHAPE(fields_lookup->shape_id)->capacity); } else { FL_SET_RAW((VALUE)*k, FL_EXIVAR); } - fields_tbl = gen_fields_tbl_resize(fields_tbl, RSHAPE(fields_lookup->shape_id)->capacity); *v = (st_data_t)fields_tbl; } @@ -1940,14 +1940,14 @@ generic_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val) } void -rb_ensure_iv_list_size(VALUE obj, uint32_t current_capacity, uint32_t new_capacity) { RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); if (RBASIC(obj)->flags & ROBJECT_EMBED) { VALUE *ptr = ROBJECT_FIELDS(obj); VALUE *newptr = ALLOC_N(VALUE, new_capacity); - MEMCPY(newptr, ptr, VALUE, current_capacity); RB_FL_UNSET_RAW(obj, ROBJECT_EMBED); ROBJECT(obj)->as.heap.fields = newptr; } @@ -2370,13 +2370,13 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj) } } - if (!RSHAPE(dest_shape_id)->capacity) { rb_obj_set_shape_id(dest, dest_shape_id); FL_UNSET(dest, FL_EXIVAR); return; } - new_fields_tbl = gen_fields_tbl_resize(0, RSHAPE(dest_shape_id)->capacity); VALUE *src_buf = obj_fields_tbl->as.shape.fields; VALUE *dest_buf = new_fields_tbl->as.shape.fields; @@ -1455,11 +1455,10 @@ vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_i RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); } else if (dest_shape_id != INVALID_SHAPE_ID) { - rb_shape_t *shape = RSHAPE(shape_id); rb_shape_t *dest_shape = RSHAPE(dest_shape_id); - if (shape_id == dest_shape->parent_id && dest_shape->edge_name == id && shape->capacity == dest_shape->capacity) { - RUBY_ASSERT(index < dest_shape->capacity); } else { return Qundef; @@ -1499,17 +1498,16 @@ vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t i VM_ASSERT(!rb_ractor_shareable_p(obj)); } else if (dest_shape_id != INVALID_SHAPE_ID) { - rb_shape_t *shape = RSHAPE(shape_id); rb_shape_t *dest_shape = RSHAPE(dest_shape_id); shape_id_t source_shape_id = dest_shape->parent_id; - if (shape_id == source_shape_id && dest_shape->edge_name == id && shape->capacity == dest_shape->capacity) { RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); RBASIC_SET_SHAPE_ID(obj, dest_shape_id); RUBY_ASSERT(rb_shape_get_next_iv_shape(source_shape_id, id) == dest_shape_id); - RUBY_ASSERT(index < dest_shape->capacity); } else { break; @@ -793,6 +793,12 @@ rb_yjit_shape_obj_too_complex_p(VALUE obj) return rb_shape_obj_too_complex_p(obj); } // Assert that we have the VM lock. Relevant mostly for multi ractor situations. // The GC takes the lock before calling us, and this asserts that it indeed happens. void @@ -101,6 +101,7 @@ fn main() { .allowlist_function("rb_shape_transition_add_ivar_no_warnings") .allowlist_function("rb_yjit_shape_obj_too_complex_p") .allowlist_function("rb_yjit_shape_too_complex_p") .allowlist_var("SHAPE_ID_NUM_BITS") // From ruby/internal/intern/object.h @@ -3119,7 +3119,7 @@ fn gen_set_ivar( // The current shape doesn't contain this iv, we need to transition to another shape. let mut new_shape_too_complex = false; let new_shape = if !shape_too_complex && receiver_t_object && ivar_index.is_none() { - let current_shape = comptime_receiver.shape_of(); let next_shape_id = unsafe { rb_shape_transition_add_ivar_no_warnings(comptime_receiver, ivar_name) }; // If the VM ran out of shapes, or this class generated too many leaf, @@ -3128,18 +3128,20 @@ fn gen_set_ivar( if new_shape_too_complex { Some((next_shape_id, None, 0_usize)) } else { - let next_shape = unsafe { rb_shape_lookup(next_shape_id) }; - let current_capacity = unsafe { (*current_shape).capacity }; // If the new shape has a different capacity, or is TOO_COMPLEX, we'll have to // reallocate it. - let needs_extension = unsafe { (*current_shape).capacity != (*next_shape).capacity }; // We can write to the object, but we need to transition the shape let ivar_index = unsafe { (*current_shape).next_field_index } as usize; let needs_extension = if needs_extension { - Some((current_capacity, unsafe { (*next_shape).capacity })) } else { None }; @@ -1139,7 +1139,7 @@ extern "C" { pub fn rb_shape_transition_add_ivar_no_warnings(obj: VALUE, id: ID) -> shape_id_t; pub fn rb_gvar_get(arg1: ID) -> VALUE; pub fn rb_gvar_set(arg1: ID, arg2: VALUE) -> VALUE; - pub fn rb_ensure_iv_list_size(obj: VALUE, len: u32, newsize: u32); pub fn rb_vm_barrier(); pub fn rb_str_byte_substr(str_: VALUE, beg: VALUE, len: VALUE) -> VALUE; pub fn rb_str_substr_two_fixnums( @@ -1264,6 +1264,7 @@ extern "C" { pub fn rb_object_shape_count() -> VALUE; pub fn rb_yjit_shape_too_complex_p(shape_id: shape_id_t) -> bool; pub fn rb_yjit_shape_obj_too_complex_p(obj: VALUE) -> bool; pub fn rb_yjit_assert_holding_vm_lock(); pub fn rb_yjit_sendish_sp_pops(ci: *const rb_callinfo) -> usize; pub fn rb_yjit_invokeblock_sp_pops(ci: *const rb_callinfo) -> usize; @@ -871,7 +871,7 @@ unsafe extern "C" { pub fn rb_shape_transition_add_ivar_no_warnings(obj: VALUE, id: ID) -> shape_id_t; pub fn rb_gvar_get(arg1: ID) -> VALUE; pub fn rb_gvar_set(arg1: ID, arg2: VALUE) -> VALUE; - pub fn rb_ensure_iv_list_size(obj: VALUE, len: u32, newsize: u32); pub fn rb_vm_barrier(); pub fn rb_str_byte_substr(str_: VALUE, beg: VALUE, len: VALUE) -> VALUE; pub fn rb_str_substr_two_fixnums( |