7#include "internal/class.h"
8#include "internal/symbol.h"
9#include "internal/variable.h"
14#define SHAPE_DEBUG (VM_CHECK_MODE > 0)
19static ID size_pool_edge_names[SIZE_POOL_COUNT];
25rb_shape_get_root_shape(
void)
27 return GET_VM()->root_shape;
33 return (shape_id_t)(shape - GET_VM()->shape_list);
39 return shape == rb_shape_get_root_shape();
43rb_shape_each_shape(each_shape_callback callback,
void *data)
45 rb_shape_t *cursor = rb_shape_get_root_shape();
46 rb_shape_t *end = rb_shape_get_shape_by_id(GET_VM()->next_shape_id);
47 while (cursor < end) {
48 callback(cursor, data);
54rb_shape_get_shape_by_id(shape_id_t shape_id)
64rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id)
76 return rb_shape_get_shape_by_id(shape->parent_id);
79#if !SHAPE_IN_BASIC_FLAGS
81rb_rclass_shape_id(
VALUE obj)
84 return RCLASS_EXT(obj)->shape_id;
87shape_id_t rb_generic_shape_id(
VALUE obj);
91rb_shape_get_shape_id(
VALUE obj)
93 if (RB_SPECIAL_CONST_P(obj)) {
94 return SPECIAL_CONST_SHAPE_ID;
97#if SHAPE_IN_BASIC_FLAGS
98 return RBASIC_SHAPE_ID(obj);
102 return ROBJECT_SHAPE_ID(obj);
106 return RCLASS_SHAPE_ID(obj);
108 return rb_generic_shape_id(obj);
118 while (shape->parent_id != INVALID_SHAPE_ID) {
120 shape = rb_shape_get_parent(shape);
127rb_shape_get_shape(
VALUE obj)
129 return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj));
133get_next_shape_internal(
rb_shape_t * shape,
ID id,
enum shape_type shape_type,
bool * variation_created,
bool new_shapes_allowed)
138 RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
140 *variation_created =
false;
142 if (new_shapes_allowed) {
145 bool had_edges = !!shape->edges;
148 shape->edges = rb_id_table_create(0);
154 if (rb_id_table_lookup(shape->edges,
id, &lookup_result)) {
158 *variation_created = had_edges;
160 rb_shape_t * new_shape = rb_shape_alloc(
id, shape);
162 new_shape->type = (uint8_t)shape_type;
163 new_shape->capacity = shape->capacity;
165 switch (shape_type) {
167 new_shape->next_iv_index = shape->next_iv_index + 1;
169 case SHAPE_CAPACITY_CHANGE:
172 new_shape->next_iv_index = shape->next_iv_index;
174 case SHAPE_OBJ_TOO_COMPLEX:
175 case SHAPE_INITIAL_CAPACITY:
181 rb_id_table_insert(shape->edges,
id, (
VALUE)new_shape);
191MJIT_FUNC_EXPORTED
int
194 return SHAPE_FROZEN == (
enum shape_type)shape->type;
198move_iv(
VALUE obj,
ID id, attr_index_t from, attr_index_t to)
203 RCLASS_IVPTR(obj)[to] = RCLASS_IVPTR(obj)[from];
207 ROBJECT_IVPTR(obj)[to] = ROBJECT_IVPTR(obj)[from];
211 rb_gen_ivtbl_get(obj,
id, &ivtbl);
212 ivtbl->ivptr[to] = ivtbl->ivptr[from];
221 if (shape->parent_id == INVALID_SHAPE_ID) {
227 if (shape->type == SHAPE_IVAR && shape->edge_name ==
id) {
230 attr_index_t index = shape->next_iv_index - 1;
235 *removed = RCLASS_IVPTR(obj)[index];
238 *removed = ROBJECT_IVPTR(obj)[index];
242 rb_gen_ivtbl_get(obj,
id, &ivtbl);
243 *removed = ivtbl->ivptr[index];
247 return rb_shape_get_parent(shape);
251 rb_shape_t * new_parent = remove_shape_recursive(obj,
id, rb_shape_get_parent(shape), removed);
257 rb_shape_t * new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care,
true);
258 new_child->capacity = shape->capacity;
259 if (new_child->type == SHAPE_IVAR) {
260 move_iv(obj,
id, shape->next_iv_index - 1, new_child->next_iv_index - 1);
277 rb_shape_t * new_shape = remove_shape_recursive(obj,
id, shape, removed);
279 rb_shape_set_shape(obj, new_shape);
284rb_shape_transition_shape_frozen(
VALUE obj)
290 if (rb_shape_frozen_shape_p(shape) || rb_shape_obj_too_complex(obj)) {
296 if (shape == rb_shape_get_root_shape()) {
297 rb_shape_set_shape_id(obj, SPECIAL_CONST_SHAPE_ID);
302 next_shape = get_next_shape_internal(shape, (
ID)id_frozen, SHAPE_FROZEN, &dont_care,
true);
305 rb_shape_set_shape(obj, next_shape);
317 return get_next_shape_internal(shape,
id, SHAPE_IVAR, &dont_care,
true);
325 bool allow_new_shape =
true;
329 allow_new_shape = RCLASS_EXT(klass)->variation_count < SHAPE_MAX_VARIATIONS;
332 bool variation_created =
false;
333 rb_shape_t * new_shape = get_next_shape_internal(shape,
id, SHAPE_IVAR, &variation_created, allow_new_shape);
337 new_shape = rb_shape_get_shape_by_id(OBJ_TOO_COMPLEX_SHAPE_ID);
343 if (new_shape->next_iv_index > RCLASS_EXT(klass)->max_iv_count) {
344 RCLASS_EXT(klass)->max_iv_count = new_shape->next_iv_index;
347 if (variation_created) {
348 RCLASS_EXT(klass)->variation_count++;
356rb_shape_transition_shape_capa(
rb_shape_t* shape, uint32_t new_capacity)
358 ID edge_name = rb_make_temporary_id(new_capacity);
360 rb_shape_t * new_shape = get_next_shape_internal(shape, edge_name, SHAPE_CAPACITY_CHANGE, &dont_care,
true);
361 new_shape->capacity = new_capacity;
366rb_shape_get_iv_index(
rb_shape_t * shape,
ID id, attr_index_t *value)
370 RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
372 while (shape->parent_id != INVALID_SHAPE_ID) {
373 if (shape->edge_name ==
id) {
374 enum shape_type shape_type;
375 shape_type = (
enum shape_type)shape->type;
377 switch (shape_type) {
380 *value = shape->next_iv_index - 1;
382 case SHAPE_CAPACITY_CHANGE:
384 case SHAPE_INITIAL_CAPACITY:
387 case SHAPE_OBJ_TOO_COMPLEX:
389 rb_bug(
"Ivar should not exist on transition\n");
392 shape = rb_shape_get_parent(shape);
401 shape_id_t shape_id = vm->next_shape_id;
404 if (shape_id == MAX_SHAPE_ID) {
406 rb_bug(
"Out of shapes\n");
409 return &GET_VM()->shape_list[shape_id];
413rb_shape_alloc_with_parent_id(
ID edge_name, shape_id_t parent_id)
417 shape->edge_name = edge_name;
418 shape->next_iv_index = 0;
419 shape->parent_id = parent_id;
425rb_shape_alloc_with_size_pool_index(
ID edge_name,
rb_shape_t * parent, uint8_t size_pool_index)
427 rb_shape_t * shape = rb_shape_alloc_with_parent_id(edge_name, rb_shape_id(parent));
428 shape->size_pool_index = size_pool_index;
436 return rb_shape_alloc_with_size_pool_index(edge_name, parent, parent->size_pool_index);
439MJIT_FUNC_EXPORTED
void
442 rb_shape_set_shape_id(obj, rb_shape_id(shape));
446rb_shape_id_offset(
void)
448 return sizeof(uintptr_t) - SHAPE_ID_NUM_BITS /
sizeof(uintptr_t);
454 RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
457 if (dest_shape->type != initial_shape->type) {
458 next_shape = rb_shape_traverse_from_new_root(initial_shape, rb_shape_get_parent(dest_shape));
464 switch ((
enum shape_type)dest_shape->type) {
467 if (!next_shape->edges) {
472 if (rb_id_table_lookup(next_shape->edges, dest_shape->edge_name, &lookup_result)) {
480 case SHAPE_CAPACITY_CHANGE:
481 case SHAPE_INITIAL_CAPACITY:
484 case SHAPE_OBJ_TOO_COMPLEX:
497 RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
499 if (dest_shape->type != initial_shape->type) {
500 midway_shape = rb_shape_rebuild_shape(initial_shape, rb_shape_get_parent(dest_shape));
503 midway_shape = initial_shape;
506 switch ((
enum shape_type)dest_shape->type) {
508 if (midway_shape->capacity <= midway_shape->next_iv_index) {
510 midway_shape = rb_shape_transition_shape_capa(midway_shape, midway_shape->capacity * 2);
513 midway_shape = rb_shape_get_next_iv_shape(midway_shape, dest_shape->edge_name);
517 case SHAPE_CAPACITY_CHANGE:
518 case SHAPE_INITIAL_CAPACITY:
521 case SHAPE_OBJ_TOO_COMPLEX:
530rb_shape_obj_too_complex(
VALUE obj)
532 return rb_shape_get_shape_id(obj) == OBJ_TOO_COMPLEX_SHAPE_ID;
536rb_shape_set_too_complex(
VALUE obj)
540 rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
547 return rb_id_table_size(shape->edges);
557 memsize += rb_id_table_memsize(shape->edges);
569rb_shape_too_complex(
VALUE self)
573 if (rb_shape_id(shape) == OBJ_TOO_COMPLEX_SHAPE_ID) {
584 if (is_instance_id(key)) {
600 rb_shape_edge_name(shape),
602 INT2NUM(shape->size_pool_index),
609static enum rb_id_table_iterator_result
610rb_edges_to_hash(
ID key,
VALUE value,
void *ref)
612 rb_hash_aset(*(
VALUE *)ref, parse_key(key), rb_shape_t_to_rb_cShape((
rb_shape_t*)value));
613 return ID_TABLE_CONTINUE;
618rb_shape_edges(
VALUE self)
624 VALUE hash = rb_hash_new();
627 rb_id_table_foreach(shape->edges, rb_edges_to_hash, &hash);
636 if (shape->edge_name) {
637 if (is_instance_id(shape->edge_name)) {
638 return ID2SYM(shape->edge_name);
640 return INT2NUM(shape->capacity);
647rb_shape_export_depth(
VALUE self)
656rb_shape_parent(
VALUE self)
660 if (shape->parent_id != INVALID_SHAPE_ID) {
661 return rb_shape_t_to_rb_cShape(rb_shape_get_parent(shape));
672 return rb_shape_t_to_rb_cShape(rb_shape_get_shape(obj));
677rb_shape_root_shape(
VALUE self)
679 return rb_shape_t_to_rb_cShape(rb_shape_get_root_shape());
684static enum rb_id_table_iterator_result collect_keys_and_values(
ID key,
VALUE value,
void *ref)
686 rb_hash_aset(*(
VALUE *)ref, parse_key(key), rb_obj_shape((
rb_shape_t*)value));
687 return ID_TABLE_CONTINUE;
692 VALUE hash = rb_hash_new();
694 rb_id_table_foreach(edges, collect_keys_and_values, &hash);
705 rb_hash_aset(
rb_shape,
ID2SYM(rb_intern(
"edges")), edges(shape->edges));
707 if (shape == rb_shape_get_root_shape()) {
714 rb_hash_aset(
rb_shape,
ID2SYM(rb_intern(
"edge_name")), rb_id2str(shape->edge_name));
720shape_transition_tree(
VALUE self)
722 return rb_obj_shape(rb_shape_get_root_shape());
730 if (shape_id >= GET_VM()->next_shape_id) {
733 return rb_shape_t_to_rb_cShape(rb_shape_get_shape_by_id(shape_id));
738Init_default_shapes(
void)
740 id_frozen = rb_make_internal_id();
741 id_t_object = rb_make_internal_id();
744 for (
int i = 0; i < SIZE_POOL_COUNT; i++) {
745 size_pool_edge_names[i] = rb_make_internal_id();
749 rb_shape_t * root = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
750 root->capacity = (uint32_t)((rb_size_pool_slot_size(0) - offsetof(
struct RObject, as.
ary)) /
sizeof(
VALUE));
751 root->type = SHAPE_ROOT;
752 root->size_pool_index = 0;
753 GET_VM()->root_shape = root;
754 RUBY_ASSERT(rb_shape_id(GET_VM()->root_shape) == ROOT_SHAPE_ID);
757 for (
int i = 1; i < SIZE_POOL_COUNT; i++) {
758 uint32_t capa = (uint32_t)((rb_size_pool_slot_size(i) - offsetof(
struct RObject, as.
ary)) /
sizeof(
VALUE));
759 rb_shape_t * new_shape = rb_shape_transition_shape_capa(root, capa);
760 new_shape->type = SHAPE_INITIAL_CAPACITY;
761 new_shape->size_pool_index = i;
762 RUBY_ASSERT(rb_shape_id(new_shape) == (shape_id_t)i);
766 for (
int i = 0; i < SIZE_POOL_COUNT; i++) {
767 rb_shape_t * shape = rb_shape_get_shape_by_id(i);
770 get_next_shape_internal(shape, id_t_object, SHAPE_T_OBJECT, &dont_care,
true);
771 t_object_shape->edges = rb_id_table_create(0);
772 RUBY_ASSERT(rb_shape_id(t_object_shape) == (shape_id_t)(i + SIZE_POOL_COUNT));
780 get_next_shape_internal(root, (
ID)id_frozen, SHAPE_FROZEN, &dont_care,
true);
781 RUBY_ASSERT(rb_shape_id(special_const_shape) == SPECIAL_CONST_SHAPE_ID);
782 RUBY_ASSERT(SPECIAL_CONST_SHAPE_ID == (GET_VM()->next_shape_id - 1));
783 RUBY_ASSERT(rb_shape_frozen_shape_p(special_const_shape));
785 rb_shape_t * hash_fallback_shape = rb_shape_alloc_with_parent_id(0, ROOT_SHAPE_ID);
786 hash_fallback_shape->type = SHAPE_OBJ_TOO_COMPLEX;
787 hash_fallback_shape->size_pool_index = 0;
788 RUBY_ASSERT(OBJ_TOO_COMPLEX_SHAPE_ID == (GET_VM()->next_shape_id - 1));
789 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.
#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.
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
void rb_bug(const char *fmt,...)
Interpreter panic switch.
VALUE rb_eArgError
ArgumentError exception.
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.
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_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.
#define RTEST
This is an old name of RB_TEST.
VALUE ary[ROBJECT_EMBED_LEN_MAX]
Embedded instance variables.
uintptr_t VALUE
Type that represents a Ruby object.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.