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)
37#define SINGLE_CHILD_TAG 0x1
38#define TAG_SINGLE_CHILD(x) (struct rb_id_table *)((uintptr_t)(x) | SINGLE_CHILD_TAG)
39#define SINGLE_CHILD_MASK (~((uintptr_t)SINGLE_CHILD_TAG))
40#define SINGLE_CHILD_P(x) ((uintptr_t)(x) & SINGLE_CHILD_TAG)
41#define SINGLE_CHILD(x) (rb_shape_t *)((uintptr_t)(x) & SINGLE_CHILD_MASK)
42#define ANCESTOR_CACHE_THRESHOLD 10
43#define MAX_SHAPE_ID (SHAPE_BUFFER_SIZE - 1)
44#define ANCESTOR_SEARCH_MAX_DEPTH 2
56 if (node->l == LEAF) {
60 RUBY_ASSERT(node->l < GET_SHAPE_TREE()->cache_size);
69 if (node->r == LEAF) {
73 RUBY_ASSERT(node->r < GET_SHAPE_TREE()->cache_size);
86 RUBY_ASSERT(redblack_left(tree) == LEAF || redblack_left(tree)->key < tree->key);
87 RUBY_ASSERT(redblack_right(tree) == LEAF || redblack_right(tree)->key > tree->key);
89 if (tree->key == key) {
93 if (key < tree->key) {
94 return redblack_find(redblack_left(tree), key);
97 return redblack_find(redblack_right(tree), key);
108 return (
rb_shape_t *)((uintptr_t)node->value & ~(uintptr_t)1);
115 return node && ((uintptr_t)node->value & RED);
121 return redblack_color(node) == RED;
133 redblack_id_t
id = (redblack_id_t)(node - redblack_nodes);
141 if (GET_SHAPE_TREE()->cache_size + 1 >= REDBLACK_CACHE_SIZE) {
150 redblack_node_t * node = &redblack_nodes[(GET_SHAPE_TREE()->cache_size)++];
152 node->value = (
rb_shape_t *)((uintptr_t)value | color);
153 node->l = redblack_id_for(left);
154 node->r = redblack_id_for(right);
161 if (color == BLACK) {
162 ID new_key, new_left_key, new_right_key;
163 rb_shape_t *new_value, *new_left_value, *new_right_value;
164 redblack_node_t *new_left_left, *new_left_right, *new_right_left, *new_right_right;
166 if (redblack_red_p(left) && redblack_red_p(redblack_left(left))) {
168 new_right_value = value;
169 new_right_right = right;
172 new_value = redblack_value(left);
173 new_right_left = redblack_right(left);
175 new_left_key = redblack_left(left)->key;
176 new_left_value = redblack_value(redblack_left(left));
178 new_left_left = redblack_left(redblack_left(left));
179 new_left_right = redblack_right(redblack_left(left));
181 else if (redblack_red_p(left) && redblack_red_p(redblack_right(left))) {
183 new_right_value = value;
184 new_right_right = right;
186 new_left_key = left->key;
187 new_left_value = redblack_value(left);
188 new_left_left = redblack_left(left);
190 new_key = redblack_right(left)->key;
191 new_value = redblack_value(redblack_right(left));
192 new_left_right = redblack_left(redblack_right(left));
193 new_right_left = redblack_right(redblack_right(left));
195 else if (redblack_red_p(right) && redblack_red_p(redblack_left(right))) {
197 new_left_value = value;
198 new_left_left = left;
200 new_right_key = right->key;
201 new_right_value = redblack_value(right);
202 new_right_right = redblack_right(right);
204 new_key = redblack_left(right)->key;
205 new_value = redblack_value(redblack_left(right));
206 new_left_right = redblack_left(redblack_left(right));
207 new_right_left = redblack_right(redblack_left(right));
209 else if (redblack_red_p(right) && redblack_red_p(redblack_right(right))) {
211 new_left_value = value;
212 new_left_left = left;
214 new_key = right->key;
215 new_value = redblack_value(right);
216 new_left_right = redblack_left(right);
218 new_right_key = redblack_right(right)->key;
219 new_right_value = redblack_value(redblack_right(right));
220 new_right_left = redblack_left(redblack_right(right));
221 new_right_right = redblack_right(redblack_right(right));
224 return redblack_new(color, key, value, left, right);
229 RUBY_ASSERT(new_left_left == LEAF || new_left_left->key < new_left_key);
230 RUBY_ASSERT(new_left_right == LEAF || new_left_right->key > new_left_key);
231 RUBY_ASSERT(new_left_right == LEAF || new_left_right->key < new_key);
232 RUBY_ASSERT(new_right_left == LEAF || new_right_left->key < new_right_key);
233 RUBY_ASSERT(new_right_left == LEAF || new_right_left->key > new_key);
234 RUBY_ASSERT(new_right_right == LEAF || new_right_right->key > new_right_key);
237 RED, new_key, new_value,
238 redblack_new(BLACK, new_left_key, new_left_value, new_left_left, new_left_right),
239 redblack_new(BLACK, new_right_key, new_right_value, new_right_left, new_right_right));
242 return redblack_new(color, key, value, left, right);
249 return redblack_new(RED, key, value, LEAF, LEAF);
253 if (key < tree->key) {
254 left = redblack_insert_aux(redblack_left(tree), key, value);
256 right = redblack_right(tree);
257 RUBY_ASSERT(right == LEAF || right->key > tree->key);
259 else if (key > tree->key) {
260 left = redblack_left(tree);
261 RUBY_ASSERT(left == LEAF || left->key < tree->key);
262 right = redblack_insert_aux(redblack_right(tree), key, value);
269 return redblack_balance(
270 redblack_color(tree),
272 redblack_value(tree),
282 node->value = redblack_value(node);
291 if (redblack_red_p(root)) {
292 return redblack_force_black(root);
306rb_shape_get_root_shape(
void)
308 return GET_SHAPE_TREE()->root_shape;
314 return (shape_id_t)(shape - GET_SHAPE_TREE()->shape_list);
318rb_shape_each_shape(each_shape_callback callback,
void *data)
320 rb_shape_t *cursor = rb_shape_get_root_shape();
321 rb_shape_t *end = rb_shape_get_shape_by_id(GET_SHAPE_TREE()->next_shape_id);
322 while (cursor < end) {
323 callback(cursor, data);
329rb_shape_get_shape_by_id(shape_id_t shape_id)
333 rb_shape_t *shape = &GET_SHAPE_TREE()->shape_list[shape_id];
340 return rb_shape_get_shape_by_id(shape->parent_id);
343#if !SHAPE_IN_BASIC_FLAGS
344shape_id_t rb_generic_shape_id(
VALUE obj);
347RUBY_FUNC_EXPORTED shape_id_t
348rb_shape_get_shape_id(
VALUE obj)
351 return SPECIAL_CONST_SHAPE_ID;
354#if SHAPE_IN_BASIC_FLAGS
355 return RBASIC_SHAPE_ID(obj);
359 return ROBJECT_SHAPE_ID(obj);
363 return RCLASS_SHAPE_ID(obj);
365 return rb_generic_shape_id(obj);
375 while (shape->parent_id != INVALID_SHAPE_ID) {
377 shape = rb_shape_get_parent(shape);
384rb_shape_get_shape(
VALUE obj)
386 return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj));
392 shape_id_t shape_id = GET_SHAPE_TREE()->next_shape_id;
393 GET_SHAPE_TREE()->next_shape_id++;
395 if (shape_id == (MAX_SHAPE_ID + 1)) {
397 rb_bug(
"Out of shapes");
400 return &GET_SHAPE_TREE()->shape_list[shape_id];
404rb_shape_alloc_with_parent_id(
ID edge_name, shape_id_t parent_id)
408 shape->edge_name = edge_name;
409 shape->next_iv_index = 0;
410 shape->parent_id = parent_id;
419 rb_shape_t * shape = rb_shape_alloc_with_parent_id(edge_name, rb_shape_id(parent));
420 shape->type = (uint8_t)
type;
421 shape->heap_index = parent->heap_index;
422 shape->capacity = parent->capacity;
431 if (!(shape->ancestor_index || shape->parent_id == INVALID_SHAPE_ID)) {
434 parent_index = redblack_cache_ancestors(rb_shape_get_parent(shape));
436 if (shape->type == SHAPE_IVAR) {
437 shape->ancestor_index = redblack_insert(parent_index, shape->edge_name, shape);
440 if (shape->ancestor_index) {
441 redblack_node_t *inserted_node = redblack_find(shape->ancestor_index, shape->edge_name);
443 RUBY_ASSERT(redblack_value(inserted_node) == shape);
448 shape->ancestor_index = parent_index;
452 return shape->ancestor_index;
463rb_shape_alloc_new_child(
ID id,
rb_shape_t * shape,
enum shape_type shape_type)
465 rb_shape_t * new_shape = rb_shape_alloc(
id, shape, shape_type);
467 switch (shape_type) {
469 if (UNLIKELY(shape->next_iv_index >= shape->capacity)) {
470 RUBY_ASSERT(shape->next_iv_index == shape->capacity);
471 new_shape->capacity = (uint32_t)rb_malloc_grow_capa(shape->capacity,
sizeof(
VALUE));
473 RUBY_ASSERT(new_shape->capacity > shape->next_iv_index);
474 new_shape->next_iv_index = shape->next_iv_index + 1;
475 if (new_shape->next_iv_index > ANCESTOR_CACHE_THRESHOLD) {
476 redblack_cache_ancestors(new_shape);
480 new_shape->next_iv_index = shape->next_iv_index;
482 case SHAPE_OBJ_TOO_COMPLEX:
485 rb_bug(
"Unreachable");
493get_next_shape_internal(
rb_shape_t * shape,
ID id,
enum shape_type shape_type,
bool * variation_created,
bool new_variations_allowed)
498 RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
500 *variation_created =
false;
507 if (SINGLE_CHILD_P(shape->edges)) {
508 rb_shape_t * child = SINGLE_CHILD(shape->edges);
511 if (child->edge_name ==
id) {
518 if (rb_id_table_lookup(shape->edges,
id, &lookup_result)) {
528 if (!new_variations_allowed || GET_SHAPE_TREE()->next_shape_id > MAX_SHAPE_ID) {
529 res = rb_shape_get_shape_by_id(OBJ_TOO_COMPLEX_SHAPE_ID);
532 rb_shape_t * new_shape = rb_shape_alloc_new_child(
id, shape, shape_type);
536 shape->edges = TAG_SINGLE_CHILD(new_shape);
540 if (SINGLE_CHILD_P(shape->edges)) {
541 rb_shape_t * old_child = SINGLE_CHILD(shape->edges);
542 shape->edges = rb_id_table_create(2);
543 rb_id_table_insert(shape->edges, old_child->edge_name, (
VALUE)old_child);
546 rb_id_table_insert(shape->edges, new_shape->edge_name, (
VALUE)new_shape);
547 *variation_created =
true;
562 return SHAPE_FROZEN == (
enum shape_type)shape->type;
568 if (shape->parent_id == INVALID_SHAPE_ID) {
574 if (shape->type == SHAPE_IVAR && shape->edge_name ==
id) {
575 *removed_shape = shape;
577 return rb_shape_get_parent(shape);
581 rb_shape_t *new_parent = remove_shape_recursive(rb_shape_get_parent(shape),
id, removed_shape);
586 if (UNLIKELY(new_parent->type == SHAPE_OBJ_TOO_COMPLEX)) {
591 rb_shape_t *new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care,
true);
592 if (UNLIKELY(new_child->type == SHAPE_OBJ_TOO_COMPLEX)) {
596 RUBY_ASSERT(new_child->capacity <= shape->capacity);
612 if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
617 rb_shape_t *new_shape = remove_shape_recursive(shape,
id, &removed_shape);
621 if (UNLIKELY(new_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
625 RUBY_ASSERT(new_shape->next_iv_index == shape->next_iv_index - 1);
631 ivptr = RCLASS_IVPTR(obj);
638 rb_gen_ivtbl_get(obj,
id, &ivtbl);
639 ivptr = ivtbl->as.shape.ivptr;
644 *removed = ivptr[removed_shape->next_iv_index - 1];
646 memmove(&ivptr[removed_shape->next_iv_index - 1], &ivptr[removed_shape->next_iv_index],
647 ((new_shape->next_iv_index + 1) - removed_shape->next_iv_index) *
sizeof(
VALUE));
660 rb_shape_set_shape(obj, new_shape);
666rb_shape_transition_shape_frozen(
VALUE obj)
672 if (rb_shape_frozen_shape_p(shape) || rb_shape_obj_too_complex(obj)) {
678 if (shape == rb_shape_get_root_shape()) {
679 return rb_shape_get_shape_by_id(SPECIAL_CONST_SHAPE_ID);
683 next_shape = get_next_shape_internal(shape, (
ID)id_frozen, SHAPE_FROZEN, &dont_care,
true);
698 return get_next_shape_internal(shape,
id, SHAPE_IVAR, &dont_care,
true);
705 if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
711 if (rb_shape_get_iv_index(shape,
id, &index)) {
712 rb_bug(
"rb_shape_get_next: trying to create ivar that already exists at index %u", index);
716 bool allow_new_shape =
true;
720 allow_new_shape = RCLASS_EXT(klass)->variation_count < SHAPE_MAX_VARIATIONS;
723 bool variation_created =
false;
724 rb_shape_t *new_shape = get_next_shape_internal(shape,
id, SHAPE_IVAR, &variation_created, allow_new_shape);
729 if (new_shape->next_iv_index > RCLASS_EXT(klass)->max_iv_count) {
730 RCLASS_EXT(klass)->max_iv_count = new_shape->next_iv_index;
733 if (variation_created) {
734 RCLASS_EXT(klass)->variation_count++;
736 if (RCLASS_EXT(klass)->variation_count >= SHAPE_MAX_VARIATIONS) {
739 "The class %"PRIsVALUE
" reached %d shape variations, instance variables accesses will be slower and memory usage increased.\n"
740 "It is recommended to define instance variables in a consistent order, for instance by eagerly defining them all in the #initialize method.",
755 return shape_get_next(shape, obj,
id,
true);
761 return shape_get_next(shape, obj,
id,
false);
767rb_shape_get_iv_index_with_hint(shape_id_t shape_id,
ID id, attr_index_t *value, shape_id_t *shape_id_hint)
769 attr_index_t index_hint = *value;
770 rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id);
773 if (*shape_id_hint == INVALID_SHAPE_ID) {
774 *shape_id_hint = shape_id;
775 return rb_shape_get_iv_index(shape,
id, value);
778 rb_shape_t * shape_hint = rb_shape_get_shape_by_id(*shape_id_hint);
785 if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
786 depth = ANCESTOR_SEARCH_MAX_DEPTH;
789 while (depth > 0 && shape->next_iv_index > index_hint) {
790 while (shape_hint->next_iv_index > shape->next_iv_index) {
791 shape_hint = rb_shape_get_parent(shape_hint);
794 if (shape_hint == shape) {
797 *shape_id_hint = rb_shape_id(shape);
800 if (shape->edge_name ==
id) {
802 *value = shape->next_iv_index - 1;
803 *shape_id_hint = rb_shape_id(shape);
807 shape = rb_shape_get_parent(shape);
813 if (!shape->ancestor_index && initial_shape->ancestor_index) {
814 shape = initial_shape;
816 *shape_id_hint = shape_id;
817 return rb_shape_get_iv_index(shape,
id, value);
821shape_get_iv_index(
rb_shape_t *shape,
ID id, attr_index_t *value)
823 while (shape->parent_id != INVALID_SHAPE_ID) {
824 if (shape->edge_name ==
id) {
825 enum shape_type shape_type;
826 shape_type = (
enum shape_type)shape->type;
828 switch (shape_type) {
831 *value = shape->next_iv_index - 1;
836 case SHAPE_OBJ_TOO_COMPLEX:
838 rb_bug(
"Ivar should not exist on transition");
842 shape = rb_shape_get_parent(shape);
849shape_cache_get_iv_index(
rb_shape_t *shape,
ID id, attr_index_t *value)
851 if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
855 *value = shape->next_iv_index - 1;
858 attr_index_t shape_tree_index;
859 RUBY_ASSERT(shape_get_iv_index(shape,
id, &shape_tree_index));
868 RUBY_ASSERT(!shape_get_iv_index(shape,
id, value));
875rb_shape_get_iv_index(
rb_shape_t *shape,
ID id, attr_index_t *value)
879 RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
881 if (!shape_cache_get_iv_index(shape,
id, value)) {
883 if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
887 return shape_get_iv_index(shape,
id, value);
897 rb_shape_set_shape_id(obj, rb_shape_id(shape));
901rb_shape_id_offset(
void)
903 return sizeof(uintptr_t) - SHAPE_ID_NUM_BITS /
sizeof(uintptr_t);
909 RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
912 if (dest_shape->type != initial_shape->type) {
913 next_shape = rb_shape_traverse_from_new_root(initial_shape, rb_shape_get_parent(dest_shape));
919 switch ((
enum shape_type)dest_shape->type) {
922 if (!next_shape->edges) {
927 if (SINGLE_CHILD_P(next_shape->edges)) {
928 rb_shape_t * child = SINGLE_CHILD(next_shape->edges);
929 if (child->edge_name == dest_shape->edge_name) {
937 if (rb_id_table_lookup(next_shape->edges, dest_shape->edge_name, &lookup_result)) {
948 case SHAPE_OBJ_TOO_COMPLEX:
949 rb_bug(
"Unreachable");
959 RUBY_ASSERT(rb_shape_id(initial_shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
960 RUBY_ASSERT(rb_shape_id(dest_shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
964 RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
966 if (dest_shape->type != initial_shape->type) {
967 midway_shape = rb_shape_rebuild_shape(initial_shape, rb_shape_get_parent(dest_shape));
968 if (UNLIKELY(rb_shape_id(midway_shape) == OBJ_TOO_COMPLEX_SHAPE_ID)) {
973 midway_shape = initial_shape;
976 switch ((
enum shape_type)dest_shape->type) {
978 midway_shape = rb_shape_get_next_iv_shape(midway_shape, dest_shape->edge_name);
984 case SHAPE_OBJ_TOO_COMPLEX:
985 rb_bug(
"Unreachable");
992RUBY_FUNC_EXPORTED
bool
993rb_shape_obj_too_complex(
VALUE obj)
995 return rb_shape_get_shape_id(obj) == OBJ_TOO_COMPLEX_SHAPE_ID;
1002 if (SINGLE_CHILD_P(shape->edges)) {
1006 return rb_id_table_size(shape->edges);
1016 if (shape->edges && !SINGLE_CHILD_P(shape->edges)) {
1017 memsize += rb_id_table_memsize(shape->edges);
1028rb_shape_too_complex(
VALUE self)
1032 if (rb_shape_id(shape) == OBJ_TOO_COMPLEX_SHAPE_ID) {
1043 if (is_instance_id(key)) {
1059 rb_shape_edge_name(shape),
1060 INT2NUM(shape->next_iv_index),
1068static enum rb_id_table_iterator_result
1069rb_edges_to_hash(
ID key,
VALUE value,
void *ref)
1071 rb_hash_aset(*(
VALUE *)ref, parse_key(key), rb_shape_t_to_rb_cShape((
rb_shape_t*)value));
1072 return ID_TABLE_CONTINUE;
1076rb_shape_edges(
VALUE self)
1082 VALUE hash = rb_hash_new();
1085 if (SINGLE_CHILD_P(shape->edges)) {
1086 rb_shape_t * child = SINGLE_CHILD(shape->edges);
1087 rb_edges_to_hash(child->edge_name, (
VALUE)child, &hash);
1090 rb_id_table_foreach(shape->edges, rb_edges_to_hash, &hash);
1100 if (shape->edge_name) {
1101 if (is_instance_id(shape->edge_name)) {
1102 return ID2SYM(shape->edge_name);
1104 return INT2NUM(shape->capacity);
1110rb_shape_export_depth(
VALUE self)
1114 return SIZET2NUM(rb_shape_depth(shape));
1118rb_shape_parent(
VALUE self)
1122 if (shape->parent_id != INVALID_SHAPE_ID) {
1123 return rb_shape_t_to_rb_cShape(rb_shape_get_parent(shape));
1133 return rb_shape_t_to_rb_cShape(rb_shape_get_shape(obj));
1137rb_shape_root_shape(
VALUE self)
1139 return rb_shape_t_to_rb_cShape(rb_shape_get_root_shape());
1143rb_shape_shapes_available(
VALUE self)
1145 return INT2NUM(MAX_SHAPE_ID - (GET_SHAPE_TREE()->next_shape_id - 1));
1149rb_shape_exhaust(
int argc,
VALUE *argv,
VALUE self)
1152 int offset = argc == 1 ?
NUM2INT(argv[0]) : 0;
1153 GET_SHAPE_TREE()->next_shape_id = MAX_SHAPE_ID - offset + 1;
1159static enum rb_id_table_iterator_result collect_keys_and_values(
ID key,
VALUE value,
void *ref)
1161 rb_hash_aset(*(
VALUE *)ref, parse_key(key), rb_obj_shape((
rb_shape_t*)value));
1162 return ID_TABLE_CONTINUE;
1167 VALUE hash = rb_hash_new();
1168 if (SINGLE_CHILD_P(edges)) {
1170 collect_keys_and_values(child->edge_name, (
VALUE)child, &hash);
1173 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));
1198shape_transition_tree(
VALUE self)
1200 return rb_obj_shape(rb_shape_get_root_shape());
1206 shape_id_t shape_id =
NUM2UINT(
id);
1207 if (shape_id >= GET_SHAPE_TREE()->next_shape_id) {
1208 rb_raise(rb_eArgError,
"Shape ID %d is out of bounds\n", shape_id);
1210 return rb_shape_t_to_rb_cShape(rb_shape_get_shape_by_id(shape_id));
1215#include <sys/mman.h>
1219Init_default_shapes(
void)
1225 rb_shape_tree_ptr->shape_list = (
rb_shape_t *)mmap(NULL, shape_list_mmap_size,
1226 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1227 if (GET_SHAPE_TREE()->shape_list == MAP_FAILED) {
1228 GET_SHAPE_TREE()->shape_list = 0;
1231 ruby_annotate_mmap(rb_shape_tree_ptr->shape_list, shape_list_mmap_size,
"Ruby:Init_default_shapes:shape_list");
1237 if (!GET_SHAPE_TREE()->shape_list) {
1241 id_frozen = rb_make_internal_id();
1242 id_t_object = rb_make_internal_id();
1246 rb_shape_tree_ptr->shape_cache = (
redblack_node_t *)mmap(NULL, shape_cache_mmap_size,
1247 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1248 rb_shape_tree_ptr->cache_size = 0;
1253 if (GET_SHAPE_TREE()->shape_cache == MAP_FAILED) {
1254 GET_SHAPE_TREE()->shape_cache = 0;
1255 GET_SHAPE_TREE()->cache_size = REDBLACK_CACHE_SIZE;
1258 ruby_annotate_mmap(rb_shape_tree_ptr->shape_cache, shape_cache_mmap_size,
"Ruby:Init_default_shapes:shape_cache");
1263 rb_shape_t *root = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
1265 root->type = SHAPE_ROOT;
1266 root->heap_index = 0;
1267 GET_SHAPE_TREE()->root_shape = root;
1268 RUBY_ASSERT(rb_shape_id(GET_SHAPE_TREE()->root_shape) == ROOT_SHAPE_ID);
1275 get_next_shape_internal(root, (
ID)id_frozen, SHAPE_FROZEN, &dont_care,
true);
1276 RUBY_ASSERT(rb_shape_id(special_const_shape) == SPECIAL_CONST_SHAPE_ID);
1277 RUBY_ASSERT(SPECIAL_CONST_SHAPE_ID == (GET_SHAPE_TREE()->next_shape_id - 1));
1278 RUBY_ASSERT(rb_shape_frozen_shape_p(special_const_shape));
1280 rb_shape_t *too_complex_shape = rb_shape_alloc_with_parent_id(0, ROOT_SHAPE_ID);
1281 too_complex_shape->type = SHAPE_OBJ_TOO_COMPLEX;
1282 too_complex_shape->heap_index = 0;
1283 RUBY_ASSERT(OBJ_TOO_COMPLEX_SHAPE_ID == (GET_SHAPE_TREE()->next_shape_id - 1));
1284 RUBY_ASSERT(rb_shape_id(too_complex_shape) == OBJ_TOO_COMPLEX_SHAPE_ID);
1287 size_t *sizes = rb_gc_heap_sizes();
1288 for (
int i = 0; sizes[i] > 0; i++) {
1289 rb_shape_t *t_object_shape = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
1290 t_object_shape->type = SHAPE_T_OBJECT;
1291 t_object_shape->heap_index = i;
1292 t_object_shape->capacity = (uint32_t)((sizes[i] - offsetof(
struct RObject, as.ary)) /
sizeof(
VALUE));
1293 t_object_shape->edges = rb_id_table_create(0);
1294 t_object_shape->ancestor_index = LEAF;
1295 RUBY_ASSERT(rb_shape_id(t_object_shape) == (shape_id_t)(i + FIRST_T_OBJECT_SHAPE_ID));
1319 rb_define_const(rb_cShape,
"SHAPE_ROOT",
INT2NUM(SHAPE_ROOT));
1320 rb_define_const(rb_cShape,
"SHAPE_IVAR",
INT2NUM(SHAPE_IVAR));
1321 rb_define_const(rb_cShape,
"SHAPE_T_OBJECT",
INT2NUM(SHAPE_T_OBJECT));
1322 rb_define_const(rb_cShape,
"SHAPE_FROZEN",
INT2NUM(SHAPE_FROZEN));
1323 rb_define_const(rb_cShape,
"SHAPE_ID_NUM_BITS",
INT2NUM(SHAPE_ID_NUM_BITS));
1324 rb_define_const(rb_cShape,
"SHAPE_FLAG_SHIFT",
INT2NUM(SHAPE_FLAG_SHIFT));
1325 rb_define_const(rb_cShape,
"SPECIAL_CONST_SHAPE_ID",
INT2NUM(SPECIAL_CONST_SHAPE_ID));
1326 rb_define_const(rb_cShape,
"OBJ_TOO_COMPLEX_SHAPE_ID",
INT2NUM(OBJ_TOO_COMPLEX_SHAPE_ID));
1327 rb_define_const(rb_cShape,
"FIRST_T_OBJECT_SHAPE_ID",
INT2NUM(FIRST_T_OBJECT_SHAPE_ID));
1328 rb_define_const(rb_cShape,
"SHAPE_MAX_VARIATIONS",
INT2NUM(SHAPE_MAX_VARIATIONS));
1331 rb_define_const(rb_cShape,
"SHAPE_BUFFER_SIZE",
INT2NUM(
sizeof(
rb_shape_t) * SHAPE_BUFFER_SIZE));
1332 rb_define_const(rb_cShape,
"REDBLACK_CACHE_SIZE",
INT2NUM(
sizeof(
redblack_node_t) * REDBLACK_CACHE_SIZE));
#define RUBY_ASSERT(...)
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().
static bool RB_OBJ_FROZEN(VALUE obj)
Checks if an object is frozen.
#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.
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
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 symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
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.