6#include "internal/class.h"
7#include "internal/error.h"
8#include "internal/gc.h"
9#include "internal/object.h"
10#include "internal/symbol.h"
11#include "internal/variable.h"
20#define SHAPE_DEBUG (VM_CHECK_MODE > 0)
23#if SIZEOF_SHAPE_T == 4
25#define SHAPE_BUFFER_SIZE 0x8000
27#define SHAPE_BUFFER_SIZE 0x80000
30#define SHAPE_BUFFER_SIZE 0x8000
33#define REDBLACK_CACHE_SIZE (SHAPE_BUFFER_SIZE * 32)
35#define SINGLE_CHILD_TAG 0x1
36#define TAG_SINGLE_CHILD(x) (struct rb_id_table *)((uintptr_t)x | SINGLE_CHILD_TAG)
37#define SINGLE_CHILD_MASK (~((uintptr_t)SINGLE_CHILD_TAG))
38#define SINGLE_CHILD_P(x) (((uintptr_t)x) & SINGLE_CHILD_TAG)
39#define SINGLE_CHILD(x) (rb_shape_t *)((uintptr_t)x & SINGLE_CHILD_MASK)
40#define ANCESTOR_CACHE_THRESHOLD 10
41#define MAX_SHAPE_ID (SHAPE_BUFFER_SIZE - 1)
42#define ANCESTOR_SEARCH_MAX_DEPTH 2
46static ID size_pool_edge_names[SIZE_POOL_COUNT];
55 if (node->l == LEAF) {
59 RUBY_ASSERT(node->l < GET_SHAPE_TREE()->cache_size);
68 if (node->r == LEAF) {
72 RUBY_ASSERT(node->r < GET_SHAPE_TREE()->cache_size);
85 RUBY_ASSERT(redblack_left(tree) == LEAF || redblack_left(tree)->key < tree->key);
86 RUBY_ASSERT(redblack_right(tree) == LEAF || redblack_right(tree)->key > tree->key);
88 if (tree->key == key) {
92 if (key < tree->key) {
93 return redblack_find(redblack_left(tree), key);
96 return redblack_find(redblack_right(tree), key);
105 return node && ((uintptr_t)node->value & RED);
111 return redblack_color(node) == RED;
119 return (
rb_shape_t *)((uintptr_t)node->value & (((uintptr_t)-1) - 1));
131 redblack_id_t
id = (redblack_id_t)(node - redblack_nodes);
139 if (GET_SHAPE_TREE()->cache_size + 1 >= REDBLACK_CACHE_SIZE) {
148 redblack_node_t * node = &redblack_nodes[(GET_SHAPE_TREE()->cache_size)++];
150 node->value = (
rb_shape_t *)((uintptr_t)value | color);
151 node->l = redblack_id_for(left);
152 node->r = redblack_id_for(right);
159 if (color == BLACK) {
160 ID new_key, new_left_key, new_right_key;
161 rb_shape_t *new_value, *new_left_value, *new_right_value;
162 redblack_node_t *new_left_left, *new_left_right, *new_right_left, *new_right_right;
164 if (redblack_red_p(left) && redblack_red_p(redblack_left(left))) {
166 new_right_value = value;
167 new_right_right = right;
170 new_value = redblack_value(left);
171 new_right_left = redblack_right(left);
173 new_left_key = redblack_left(left)->key;
174 new_left_value = redblack_value(redblack_left(left));
176 new_left_left = redblack_left(redblack_left(left));
177 new_left_right = redblack_right(redblack_left(left));
179 else if (redblack_red_p(left) && redblack_red_p(redblack_right(left))) {
181 new_right_value = value;
182 new_right_right = right;
184 new_left_key = left->key;
185 new_left_value = redblack_value(left);
186 new_left_left = redblack_left(left);
188 new_key = redblack_right(left)->key;
189 new_value = redblack_value(redblack_right(left));
190 new_left_right = redblack_left(redblack_right(left));
191 new_right_left = redblack_right(redblack_right(left));
193 else if (redblack_red_p(right) && redblack_red_p(redblack_left(right))) {
195 new_left_value = value;
196 new_left_left = left;
198 new_right_key = right->key;
199 new_right_value = redblack_value(right);
200 new_right_right = redblack_right(right);
202 new_key = redblack_left(right)->key;
203 new_value = redblack_value(redblack_left(right));
204 new_left_right = redblack_left(redblack_left(right));
205 new_right_left = redblack_right(redblack_left(right));
207 else if (redblack_red_p(right) && redblack_red_p(redblack_right(right))) {
209 new_left_value = value;
210 new_left_left = left;
212 new_key = right->key;
213 new_value = redblack_value(right);
214 new_left_right = redblack_left(right);
216 new_right_key = redblack_right(right)->key;
217 new_right_value = redblack_value(redblack_right(right));
218 new_right_left = redblack_left(redblack_right(right));
219 new_right_right = redblack_right(redblack_right(right));
222 return redblack_new(color, key, value, left, right);
227 RUBY_ASSERT(new_left_left == LEAF || new_left_left->key < new_left_key);
228 RUBY_ASSERT(new_left_right == LEAF || new_left_right->key > new_left_key);
229 RUBY_ASSERT(new_left_right == LEAF || new_left_right->key < new_key);
230 RUBY_ASSERT(new_right_left == LEAF || new_right_left->key < new_right_key);
231 RUBY_ASSERT(new_right_left == LEAF || new_right_left->key > new_key);
232 RUBY_ASSERT(new_right_right == LEAF || new_right_right->key > new_right_key);
235 RED, new_key, new_value,
236 redblack_new(BLACK, new_left_key, new_left_value, new_left_left, new_left_right),
237 redblack_new(BLACK, new_right_key, new_right_value, new_right_left, new_right_right));
240 return redblack_new(color, key, value, left, right);
247 return redblack_new(RED, key, value, LEAF, LEAF);
251 if (key < tree->key) {
252 left = redblack_insert_aux(redblack_left(tree), key, value);
254 right = redblack_right(tree);
255 RUBY_ASSERT(right == LEAF || right->key > tree->key);
257 else if (key > tree->key) {
258 left = redblack_left(tree);
259 RUBY_ASSERT(left == LEAF || left->key < tree->key);
260 right = redblack_insert_aux(redblack_right(tree), key, value);
267 return redblack_balance(
268 redblack_color(tree),
270 redblack_value(tree),
280 node->value = redblack_value(node);
289 if (redblack_red_p(root)) {
290 return redblack_force_black(root);
303rb_shape_get_root_shape(
void)
305 return GET_SHAPE_TREE()->root_shape;
311 return (shape_id_t)(shape - GET_SHAPE_TREE()->shape_list);
315rb_shape_each_shape(each_shape_callback callback,
void *data)
317 rb_shape_t *cursor = rb_shape_get_root_shape();
318 rb_shape_t *end = rb_shape_get_shape_by_id(GET_SHAPE_TREE()->next_shape_id);
319 while (cursor < end) {
320 callback(cursor, data);
326rb_shape_get_shape_by_id(shape_id_t shape_id)
330 rb_shape_t *shape = &GET_SHAPE_TREE()->shape_list[shape_id];
337 return rb_shape_get_shape_by_id(shape->parent_id);
340#if !SHAPE_IN_BASIC_FLAGS
341shape_id_t rb_generic_shape_id(
VALUE obj);
344RUBY_FUNC_EXPORTED shape_id_t
345rb_shape_get_shape_id(
VALUE obj)
348 return SPECIAL_CONST_SHAPE_ID;
351#if SHAPE_IN_BASIC_FLAGS
352 return RBASIC_SHAPE_ID(obj);
356 return ROBJECT_SHAPE_ID(obj);
360 return RCLASS_SHAPE_ID(obj);
362 return rb_generic_shape_id(obj);
372 while (shape->parent_id != INVALID_SHAPE_ID) {
374 shape = rb_shape_get_parent(shape);
381rb_shape_get_shape(
VALUE obj)
383 return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj));
389 shape_id_t shape_id = GET_SHAPE_TREE()->next_shape_id;
390 GET_SHAPE_TREE()->next_shape_id++;
392 if (shape_id == (MAX_SHAPE_ID + 1)) {
394 rb_bug(
"Out of shapes");
397 return &GET_SHAPE_TREE()->shape_list[shape_id];
401rb_shape_alloc_with_parent_id(
ID edge_name, shape_id_t parent_id)
405 shape->edge_name = edge_name;
406 shape->next_iv_index = 0;
407 shape->parent_id = parent_id;
416 rb_shape_t * shape = rb_shape_alloc_with_parent_id(edge_name, rb_shape_id(parent));
417 shape->type = (uint8_t)
type;
418 shape->size_pool_index = parent->size_pool_index;
419 shape->capacity = parent->capacity;
428 if (!(shape->ancestor_index || shape->parent_id == INVALID_SHAPE_ID)) {
431 parent_index = redblack_cache_ancestors(rb_shape_get_parent(shape));
433 if (shape->type == SHAPE_IVAR) {
434 shape->ancestor_index = redblack_insert(parent_index, shape->edge_name, shape);
437 if (shape->ancestor_index) {
438 redblack_node_t *inserted_node = redblack_find(shape->ancestor_index, shape->edge_name);
440 RUBY_ASSERT(redblack_value(inserted_node) == shape);
445 shape->ancestor_index = parent_index;
449 return shape->ancestor_index;
460rb_shape_alloc_new_child(
ID id,
rb_shape_t * shape,
enum shape_type shape_type)
462 rb_shape_t * new_shape = rb_shape_alloc(
id, shape, shape_type);
464 switch (shape_type) {
466 if (UNLIKELY(shape->next_iv_index >= shape->capacity)) {
467 RUBY_ASSERT(shape->next_iv_index == shape->capacity);
468 new_shape->capacity = (uint32_t)rb_malloc_grow_capa(shape->capacity,
sizeof(
VALUE));
470 RUBY_ASSERT(new_shape->capacity > shape->next_iv_index);
471 new_shape->next_iv_index = shape->next_iv_index + 1;
472 if (new_shape->next_iv_index > ANCESTOR_CACHE_THRESHOLD) {
473 redblack_cache_ancestors(new_shape);
478 new_shape->next_iv_index = shape->next_iv_index;
480 case SHAPE_OBJ_TOO_COMPLEX:
482 rb_bug(
"Unreachable");
490get_next_shape_internal(
rb_shape_t * shape,
ID id,
enum shape_type shape_type,
bool * variation_created,
bool new_variations_allowed)
495 RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
497 *variation_created =
false;
504 if (SINGLE_CHILD_P(shape->edges)) {
505 rb_shape_t * child = SINGLE_CHILD(shape->edges);
508 if (child->edge_name ==
id) {
515 if (rb_id_table_lookup(shape->edges,
id, &lookup_result)) {
525 if (!new_variations_allowed || GET_SHAPE_TREE()->next_shape_id > MAX_SHAPE_ID) {
526 res = rb_shape_get_shape_by_id(OBJ_TOO_COMPLEX_SHAPE_ID);
529 rb_shape_t * new_shape = rb_shape_alloc_new_child(
id, shape, shape_type);
533 shape->edges = TAG_SINGLE_CHILD(new_shape);
537 if (SINGLE_CHILD_P(shape->edges)) {
538 rb_shape_t * old_child = SINGLE_CHILD(shape->edges);
539 shape->edges = rb_id_table_create(2);
540 rb_id_table_insert(shape->edges, old_child->edge_name, (
VALUE)old_child);
543 rb_id_table_insert(shape->edges, new_shape->edge_name, (
VALUE)new_shape);
544 *variation_created =
true;
559 return SHAPE_FROZEN == (
enum shape_type)shape->type;
565 if (shape->parent_id == INVALID_SHAPE_ID) {
571 if (shape->type == SHAPE_IVAR && shape->edge_name ==
id) {
572 *removed_shape = shape;
574 return rb_shape_get_parent(shape);
578 rb_shape_t *new_parent = remove_shape_recursive(rb_shape_get_parent(shape),
id, removed_shape);
583 if (UNLIKELY(new_parent->type == SHAPE_OBJ_TOO_COMPLEX)) {
588 rb_shape_t *new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care,
true);
589 if (UNLIKELY(new_child->type == SHAPE_OBJ_TOO_COMPLEX)) {
593 RUBY_ASSERT(new_child->capacity <= shape->capacity);
609 if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
614 rb_shape_t *new_shape = remove_shape_recursive(shape,
id, &removed_shape);
618 if (UNLIKELY(new_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
622 RUBY_ASSERT(new_shape->next_iv_index == shape->next_iv_index - 1);
628 ivptr = RCLASS_IVPTR(obj);
635 rb_gen_ivtbl_get(obj,
id, &ivtbl);
636 ivptr = ivtbl->as.shape.ivptr;
641 *removed = ivptr[removed_shape->next_iv_index - 1];
643 memmove(&ivptr[removed_shape->next_iv_index - 1], &ivptr[removed_shape->next_iv_index],
644 ((new_shape->next_iv_index + 1) - removed_shape->next_iv_index) *
sizeof(
VALUE));
657 rb_shape_set_shape(obj, new_shape);
663rb_shape_transition_shape_frozen(
VALUE obj)
669 if (rb_shape_frozen_shape_p(shape) || rb_shape_obj_too_complex(obj)) {
675 if (shape == rb_shape_get_root_shape()) {
676 return rb_shape_get_shape_by_id(SPECIAL_CONST_SHAPE_ID);
680 next_shape = get_next_shape_internal(shape, (
ID)id_frozen, SHAPE_FROZEN, &dont_care,
true);
695 return get_next_shape_internal(shape,
id, SHAPE_IVAR, &dont_care,
true);
702 if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
708 if (rb_shape_get_iv_index(shape,
id, &index)) {
709 rb_bug(
"rb_shape_get_next: trying to create ivar that already exists at index %u", index);
713 bool allow_new_shape =
true;
717 allow_new_shape = RCLASS_EXT(klass)->variation_count < SHAPE_MAX_VARIATIONS;
720 bool variation_created =
false;
721 rb_shape_t *new_shape = get_next_shape_internal(shape,
id, SHAPE_IVAR, &variation_created, allow_new_shape);
726 if (new_shape->next_iv_index > RCLASS_EXT(klass)->max_iv_count) {
727 RCLASS_EXT(klass)->max_iv_count = new_shape->next_iv_index;
730 if (variation_created) {
731 RCLASS_EXT(klass)->variation_count++;
733 if (RCLASS_EXT(klass)->variation_count >= SHAPE_MAX_VARIATIONS) {
736 "The class %"PRIsVALUE
" reached %d shape variations, instance variables accesses will be slower and memory usage increased.\n"
737 "It is recommended to define instance variables in a consistent order, for instance by eagerly defining them all in the #initialize method.",
752 return shape_get_next(shape, obj,
id,
true);
758 return shape_get_next(shape, obj,
id,
false);
764rb_shape_get_iv_index_with_hint(shape_id_t shape_id,
ID id, attr_index_t *value, shape_id_t *shape_id_hint)
766 attr_index_t index_hint = *value;
767 rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id);
770 if (*shape_id_hint == INVALID_SHAPE_ID) {
771 *shape_id_hint = shape_id;
772 return rb_shape_get_iv_index(shape,
id, value);
775 rb_shape_t * shape_hint = rb_shape_get_shape_by_id(*shape_id_hint);
782 if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
783 depth = ANCESTOR_SEARCH_MAX_DEPTH;
786 while (depth > 0 && shape->next_iv_index > index_hint) {
787 while (shape_hint->next_iv_index > shape->next_iv_index) {
788 shape_hint = rb_shape_get_parent(shape_hint);
791 if (shape_hint == shape) {
794 *shape_id_hint = rb_shape_id(shape);
797 if (shape->edge_name ==
id) {
799 *value = shape->next_iv_index - 1;
800 *shape_id_hint = rb_shape_id(shape);
804 shape = rb_shape_get_parent(shape);
810 if (!shape->ancestor_index && initial_shape->ancestor_index) {
811 shape = initial_shape;
813 *shape_id_hint = shape_id;
814 return rb_shape_get_iv_index(shape,
id, value);
818shape_get_iv_index(
rb_shape_t *shape,
ID id, attr_index_t *value)
820 while (shape->parent_id != INVALID_SHAPE_ID) {
821 if (shape->edge_name ==
id) {
822 enum shape_type shape_type;
823 shape_type = (
enum shape_type)shape->type;
825 switch (shape_type) {
828 *value = shape->next_iv_index - 1;
833 case SHAPE_OBJ_TOO_COMPLEX:
835 rb_bug(
"Ivar should not exist on transition");
839 shape = rb_shape_get_parent(shape);
846shape_cache_get_iv_index(
rb_shape_t *shape,
ID id, attr_index_t *value)
848 if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
852 *value = shape->next_iv_index - 1;
855 attr_index_t shape_tree_index;
856 RUBY_ASSERT(shape_get_iv_index(shape,
id, &shape_tree_index));
865 RUBY_ASSERT(!shape_get_iv_index(shape,
id, value));
872rb_shape_get_iv_index(
rb_shape_t *shape,
ID id, attr_index_t *value)
876 RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
878 if (!shape_cache_get_iv_index(shape,
id, value)) {
879 return shape_get_iv_index(shape,
id, value);
888 rb_shape_set_shape_id(obj, rb_shape_id(shape));
892rb_shape_id_offset(
void)
894 return sizeof(uintptr_t) - SHAPE_ID_NUM_BITS /
sizeof(uintptr_t);
900 RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
903 if (dest_shape->type != initial_shape->type) {
904 next_shape = rb_shape_traverse_from_new_root(initial_shape, rb_shape_get_parent(dest_shape));
910 switch ((
enum shape_type)dest_shape->type) {
913 if (!next_shape->edges) {
918 if (SINGLE_CHILD_P(next_shape->edges)) {
919 rb_shape_t * child = SINGLE_CHILD(next_shape->edges);
920 if (child->edge_name == dest_shape->edge_name) {
928 if (rb_id_table_lookup(next_shape->edges, dest_shape->edge_name, &lookup_result)) {
939 case SHAPE_OBJ_TOO_COMPLEX:
940 rb_bug(
"Unreachable");
950 RUBY_ASSERT(rb_shape_id(initial_shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
951 RUBY_ASSERT(rb_shape_id(dest_shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
955 RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
957 if (dest_shape->type != initial_shape->type) {
958 midway_shape = rb_shape_rebuild_shape(initial_shape, rb_shape_get_parent(dest_shape));
959 if (UNLIKELY(rb_shape_id(midway_shape) == OBJ_TOO_COMPLEX_SHAPE_ID)) {
964 midway_shape = initial_shape;
967 switch ((
enum shape_type)dest_shape->type) {
969 midway_shape = rb_shape_get_next_iv_shape(midway_shape, dest_shape->edge_name);
975 case SHAPE_OBJ_TOO_COMPLEX:
976 rb_bug(
"Unreachable");
983RUBY_FUNC_EXPORTED
bool
984rb_shape_obj_too_complex(
VALUE obj)
986 return rb_shape_get_shape_id(obj) == OBJ_TOO_COMPLEX_SHAPE_ID;
993 if (SINGLE_CHILD_P(shape->edges)) {
997 return rb_id_table_size(shape->edges);
1007 if (shape->edges && !SINGLE_CHILD_P(shape->edges)) {
1008 memsize += rb_id_table_memsize(shape->edges);
1020rb_shape_too_complex(
VALUE self)
1024 if (rb_shape_id(shape) == OBJ_TOO_COMPLEX_SHAPE_ID) {
1035 if (is_instance_id(key)) {
1051 rb_shape_edge_name(shape),
1052 INT2NUM(shape->next_iv_index),
1053 INT2NUM(shape->size_pool_index),
1060static enum rb_id_table_iterator_result
1061rb_edges_to_hash(
ID key,
VALUE value,
void *ref)
1063 rb_hash_aset(*(
VALUE *)ref, parse_key(key), rb_shape_t_to_rb_cShape((
rb_shape_t*)value));
1064 return ID_TABLE_CONTINUE;
1069rb_shape_edges(
VALUE self)
1075 VALUE hash = rb_hash_new();
1078 if (SINGLE_CHILD_P(shape->edges)) {
1079 rb_shape_t * child = SINGLE_CHILD(shape->edges);
1080 rb_edges_to_hash(child->edge_name, (
VALUE)child, &hash);
1083 rb_id_table_foreach(shape->edges, rb_edges_to_hash, &hash);
1093 if (shape->edge_name) {
1094 if (is_instance_id(shape->edge_name)) {
1095 return ID2SYM(shape->edge_name);
1097 return INT2NUM(shape->capacity);
1104rb_shape_export_depth(
VALUE self)
1108 return SIZET2NUM(rb_shape_depth(shape));
1113rb_shape_parent(
VALUE self)
1117 if (shape->parent_id != INVALID_SHAPE_ID) {
1118 return rb_shape_t_to_rb_cShape(rb_shape_get_parent(shape));
1129 return rb_shape_t_to_rb_cShape(rb_shape_get_shape(obj));
1134rb_shape_root_shape(
VALUE self)
1136 return rb_shape_t_to_rb_cShape(rb_shape_get_root_shape());
1141rb_shape_shapes_available(
VALUE self)
1143 return INT2NUM(MAX_SHAPE_ID - (GET_SHAPE_TREE()->next_shape_id - 1));
1148rb_shape_exhaust(
int argc,
VALUE *argv,
VALUE self)
1151 int offset = argc == 1 ?
NUM2INT(argv[0]) : 0;
1152 GET_SHAPE_TREE()->next_shape_id = MAX_SHAPE_ID - offset + 1;
1158static enum rb_id_table_iterator_result collect_keys_and_values(
ID key,
VALUE value,
void *ref)
1160 rb_hash_aset(*(
VALUE *)ref, parse_key(key), rb_obj_shape((
rb_shape_t*)value));
1161 return ID_TABLE_CONTINUE;
1166 VALUE hash = rb_hash_new();
1167 if (SINGLE_CHILD_P(edges)) {
1169 collect_keys_and_values(child->edge_name, (
VALUE)child, &hash);
1172 rb_id_table_foreach(edges, collect_keys_and_values, &hash);
1184 rb_hash_aset(
rb_shape,
ID2SYM(rb_intern(
"edges")), edges(shape->edges));
1186 if (shape == rb_shape_get_root_shape()) {
1193 rb_hash_aset(
rb_shape,
ID2SYM(rb_intern(
"edge_name")), rb_id2str(shape->edge_name));
1199shape_transition_tree(
VALUE self)
1201 return rb_obj_shape(rb_shape_get_root_shape());
1208 shape_id_t shape_id =
NUM2UINT(
id);
1209 if (shape_id >= GET_SHAPE_TREE()->next_shape_id) {
1210 rb_raise(rb_eArgError,
"Shape ID %d is out of bounds\n", shape_id);
1212 return rb_shape_t_to_rb_cShape(rb_shape_get_shape_by_id(shape_id));
1217#include <sys/mman.h>
1221Init_default_shapes(
void)
1225 rb_shape_tree_ptr = st;
1229 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1230 if (GET_SHAPE_TREE()->shape_list == MAP_FAILED) {
1231 GET_SHAPE_TREE()->shape_list = 0;
1237 if (!GET_SHAPE_TREE()->shape_list) {
1241 id_frozen = rb_make_internal_id();
1242 id_t_object = rb_make_internal_id();
1246 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1247 rb_shape_tree_ptr->cache_size = 0;
1252 if (GET_SHAPE_TREE()->shape_cache == MAP_FAILED) {
1253 GET_SHAPE_TREE()->shape_cache = 0;
1254 GET_SHAPE_TREE()->cache_size = REDBLACK_CACHE_SIZE;
1259 for (
int i = 0; i < SIZE_POOL_COUNT; i++) {
1260 size_pool_edge_names[i] = rb_make_internal_id();
1264 rb_shape_t *root = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
1266 root->type = SHAPE_ROOT;
1267 root->size_pool_index = 0;
1268 GET_SHAPE_TREE()->root_shape = root;
1269 RUBY_ASSERT(rb_shape_id(GET_SHAPE_TREE()->root_shape) == ROOT_SHAPE_ID);
1272 for (
int i = 1; i < SIZE_POOL_COUNT; i++) {
1273 rb_shape_t *new_shape = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
1274 new_shape->type = SHAPE_ROOT;
1275 new_shape->size_pool_index = i;
1276 new_shape->ancestor_index = LEAF;
1277 RUBY_ASSERT(rb_shape_id(new_shape) == (shape_id_t)i);
1281 for (
int i = 0; i < SIZE_POOL_COUNT; i++) {
1282 rb_shape_t * shape = rb_shape_get_shape_by_id(i);
1285 get_next_shape_internal(shape, id_t_object, SHAPE_T_OBJECT, &dont_care,
true);
1286 t_object_shape->capacity = (uint32_t)((rb_size_pool_slot_size(i) - offsetof(
struct RObject, as.ary)) /
sizeof(
VALUE));
1287 t_object_shape->edges = rb_id_table_create(0);
1288 t_object_shape->ancestor_index = LEAF;
1289 RUBY_ASSERT(rb_shape_id(t_object_shape) == (shape_id_t)(i + SIZE_POOL_COUNT));
1297 get_next_shape_internal(root, (
ID)id_frozen, SHAPE_FROZEN, &dont_care,
true);
1298 RUBY_ASSERT(rb_shape_id(special_const_shape) == SPECIAL_CONST_SHAPE_ID);
1299 RUBY_ASSERT(SPECIAL_CONST_SHAPE_ID == (GET_SHAPE_TREE()->next_shape_id - 1));
1300 RUBY_ASSERT(rb_shape_frozen_shape_p(special_const_shape));
1302 rb_shape_t * hash_fallback_shape = rb_shape_alloc_with_parent_id(0, ROOT_SHAPE_ID);
1303 hash_fallback_shape->type = SHAPE_OBJ_TOO_COMPLEX;
1304 hash_fallback_shape->size_pool_index = 0;
1305 RUBY_ASSERT(OBJ_TOO_COMPLEX_SHAPE_ID == (GET_SHAPE_TREE()->next_shape_id - 1));
1306 RUBY_ASSERT(rb_shape_id(hash_fallback_shape) == OBJ_TOO_COMPLEX_SHAPE_ID);
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
static VALUE RB_FL_TEST_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_TEST().
static void RB_FL_SET_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_SET().
#define xfree
Old name of ruby_xfree.
#define ID2SYM
Old name of RB_ID2SYM.
#define SIZET2NUM
Old name of RB_SIZE2NUM.
#define T_MODULE
Old name of RUBY_T_MODULE.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define T_OBJECT
Old name of RUBY_T_OBJECT.
#define T_CLASS
Old name of RUBY_T_CLASS.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
#define xcalloc
Old name of ruby_xcalloc.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eRuntimeError
RuntimeError exception.
@ RB_WARN_CATEGORY_PERFORMANCE
Warning is for performance issues (not enabled by -w).
size_t rb_obj_embedded_size(uint32_t numiv)
Internal header for Object.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_struct_define_under(VALUE space, const char *name,...)
Identical to rb_struct_define(), except it defines the class under the specified namespace instead of...
VALUE rb_struct_new(VALUE klass,...)
Creates an instance of the given struct.
VALUE rb_struct_getmember(VALUE self, ID key)
Identical to rb_struct_aref(), except it takes ID instead of VALUE.
VALUE rb_const_get(VALUE space, ID name)
Identical to rb_const_defined(), except it returns the actual defined value.
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
VALUE type(ANYARGS)
ANYARGS-ed function type.
static VALUE * ROBJECT_IVPTR(VALUE obj)
Queries the instance variables.
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.