Skip to content

Commit 2b810ac

Browse files
committed
shape.c: match capacity growth with T_OBJECT embedded sizes
This helps with getting with of `SHAPE_T_OBJECT`, by ensuring that transitions will have capacities that match the next embed size.
1 parent dde9fca commit 2b810ac

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

shape.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ static ID id_frozen;
3737
static ID id_t_object;
3838
ID ruby_internal_object_id; // extern
3939

40+
static const attr_index_t *shape_capacities = NULL;
41+
4042
#define LEAF 0
4143
#define BLACK 0x0
4244
#define RED 0x1
@@ -496,6 +498,23 @@ redblack_cache_ancestors(rb_shape_t *shape)
496498
}
497499
#endif
498500

501+
static attr_index_t
502+
shape_grow_capa(attr_index_t current_capa)
503+
{
504+
const attr_index_t *capacities = shape_capacities;
505+
506+
// First try to use the next size that will be embeddable in a larger object slot.
507+
attr_index_t capa;
508+
while ((capa = *capacities)) {
509+
if (capa > current_capa) {
510+
return capa;
511+
}
512+
capacities++;
513+
}
514+
515+
return (attr_index_t)rb_malloc_grow_capa(current_capa, sizeof(VALUE));
516+
}
517+
499518
static rb_shape_t *
500519
rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
501520
{
@@ -506,7 +525,7 @@ rb_shape_alloc_new_child(ID id, rb_shape_t *shape, enum shape_type shape_type)
506525
case SHAPE_IVAR:
507526
if (UNLIKELY(shape->next_field_index >= shape->capacity)) {
508527
RUBY_ASSERT(shape->next_field_index == shape->capacity);
509-
new_shape->capacity = (uint32_t)rb_malloc_grow_capa(shape->capacity, sizeof(VALUE));
528+
new_shape->capacity = shape_grow_capa(shape->capacity);
510529
}
511530
RUBY_ASSERT(new_shape->capacity > shape->next_field_index);
512531
new_shape->next_field_index = shape->next_field_index + 1;
@@ -1431,6 +1450,19 @@ Init_default_shapes(void)
14311450
{
14321451
rb_shape_tree_ptr = xcalloc(1, sizeof(rb_shape_tree_t));
14331452

1453+
size_t *heap_sizes = rb_gc_heap_sizes();
1454+
size_t heaps_count = 0;
1455+
while (heap_sizes[heaps_count]) {
1456+
heaps_count++;
1457+
}
1458+
attr_index_t *capacities = ALLOC_N(attr_index_t, heaps_count + 1);
1459+
capacities[heaps_count] = 0;
1460+
size_t index;
1461+
for (index = 0; index < heaps_count; index++) {
1462+
capacities[index] = (heap_sizes[index] - sizeof(struct RBasic)) / sizeof(VALUE);
1463+
}
1464+
shape_capacities = capacities;
1465+
14341466
#ifdef HAVE_MMAP
14351467
size_t shape_list_mmap_size = rb_size_mul_or_raise(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t), rb_eRuntimeError);
14361468
rb_shape_tree_ptr->shape_list = (rb_shape_t *)mmap(NULL, shape_list_mmap_size,
@@ -1505,6 +1537,8 @@ Init_default_shapes(void)
15051537
void
15061538
rb_shape_free_all(void)
15071539
{
1540+
xfree((void *)shape_capacities);
1541+
shape_capacities = NULL;
15081542
xfree(GET_SHAPE_TREE());
15091543
}
15101544

test/ruby/test_object_id.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ def setup
131131

132132
class TestObjectIdTooComplex < TestObjectId
133133
class TooComplex
134+
def initialize
135+
@too_complex_obj_id_test = 1
136+
end
134137
end
135138

136139
def setup

0 commit comments

Comments
 (0)