4#include "internal/gc.h"
6typedef uint16_t attr_index_t;
7typedef uint32_t shape_id_t;
8#define SHAPE_ID_NUM_BITS 32
9#define SHAPE_ID_OFFSET_NUM_BITS 19
11STATIC_ASSERT(shape_id_num_bits, SHAPE_ID_NUM_BITS ==
sizeof(shape_id_t) * CHAR_BIT);
13#define SHAPE_BUFFER_SIZE (1 << SHAPE_ID_OFFSET_NUM_BITS)
14#define SHAPE_ID_OFFSET_MASK (SHAPE_BUFFER_SIZE - 1)
16#define SHAPE_ID_HEAP_INDEX_BITS 3
17#define SHAPE_ID_HEAP_INDEX_MAX ((1 << SHAPE_ID_HEAP_INDEX_BITS) - 1)
19#define SHAPE_ID_FL_USHIFT (SHAPE_ID_OFFSET_NUM_BITS + SHAPE_ID_HEAP_INDEX_BITS)
20#define SHAPE_ID_HEAP_INDEX_OFFSET SHAPE_ID_FL_USHIFT
35enum shape_id_fl_type {
36#define RBIMPL_SHAPE_ID_FL(n) (1<<(SHAPE_ID_FL_USHIFT+n))
38 SHAPE_ID_HEAP_INDEX_MASK = RBIMPL_SHAPE_ID_FL(0) | RBIMPL_SHAPE_ID_FL(1) | RBIMPL_SHAPE_ID_FL(2),
40 SHAPE_ID_FL_FROZEN = RBIMPL_SHAPE_ID_FL(3),
41 SHAPE_ID_FL_HAS_OBJECT_ID = RBIMPL_SHAPE_ID_FL(4),
42 SHAPE_ID_FL_TOO_COMPLEX = RBIMPL_SHAPE_ID_FL(5),
44 SHAPE_ID_FL_NON_CANONICAL_MASK = SHAPE_ID_FL_FROZEN | SHAPE_ID_FL_HAS_OBJECT_ID,
45 SHAPE_ID_FLAGS_MASK = SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_NON_CANONICAL_MASK | SHAPE_ID_FL_TOO_COMPLEX,
47#undef RBIMPL_SHAPE_ID_FL
53 SHAPE_ID_HAS_IVAR_MASK = SHAPE_ID_FL_TOO_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1),
59#define SHAPE_ID_READ_ONLY_MASK (~(SHAPE_ID_FL_FROZEN | SHAPE_ID_HEAP_INDEX_MASK))
61typedef uint32_t redblack_id_t;
63#define SHAPE_MAX_FIELDS (attr_index_t)(-1)
64#define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * CHAR_BIT) - SHAPE_ID_NUM_BITS)
65#define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
67#define SHAPE_MAX_VARIATIONS 8
69#define INVALID_SHAPE_ID ((shape_id_t)-1)
70#define ATTR_INDEX_NOT_SET ((attr_index_t)-1)
72#define ROOT_SHAPE_ID 0x0
73#define ROOT_SHAPE_WITH_OBJ_ID 0x1
74#define ROOT_TOO_COMPLEX_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_TOO_COMPLEX)
75#define ROOT_TOO_COMPLEX_WITH_OBJ_ID (ROOT_SHAPE_WITH_OBJ_ID | SHAPE_ID_FL_TOO_COMPLEX | SHAPE_ID_FL_HAS_OBJECT_ID)
84 attr_index_t next_field_index;
85 attr_index_t capacity;
105 SHAPE_FL_FROZEN = 1 << 0,
106 SHAPE_FL_HAS_OBJECT_ID = 1 << 1,
107 SHAPE_FL_TOO_COMPLEX = 1 << 2,
109 SHAPE_FL_NON_CANONICAL_MASK = SHAPE_FL_FROZEN | SHAPE_FL_HAS_OBJECT_ID,
116 const attr_index_t *capacities;
120 unsigned int cache_size;
123RUBY_SYMBOL_EXPORT_BEGIN
125RUBY_SYMBOL_EXPORT_END
127static inline shape_id_t
141static inline shape_id_t
142RBASIC_SHAPE_ID(
VALUE obj)
146#if RBASIC_SHAPE_ID_FIELD
147 return (shape_id_t)((
RBASIC(obj)->shape_id));
149 return (shape_id_t)((
RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT);
155static inline shape_id_t
156RBASIC_SHAPE_ID_FOR_READ(
VALUE obj)
158 return RBASIC_SHAPE_ID(obj) & SHAPE_ID_READ_ONLY_MASK;
162bool rb_shape_verify_consistency(
VALUE obj, shape_id_t shape_id);
166RBASIC_SET_SHAPE_ID_NO_CHECKS(
VALUE obj, shape_id_t shape_id)
168#if RBASIC_SHAPE_ID_FIELD
172 RBASIC(obj)->flags &= SHAPE_FLAG_MASK;
173 RBASIC(obj)->flags |= ((
VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
178RBASIC_SET_SHAPE_ID(
VALUE obj, shape_id_t shape_id)
183 RBASIC_SET_SHAPE_ID_NO_CHECKS(obj, shape_id);
185 RUBY_ASSERT(rb_shape_verify_consistency(obj, shape_id));
188void rb_set_boxed_class_shape_id(
VALUE obj, shape_id_t shape_id);
191RB_SET_SHAPE_ID(
VALUE obj, shape_id_t shape_id)
196 rb_set_boxed_class_shape_id(obj, shape_id);
199 RBASIC_SET_SHAPE_ID(obj, shape_id);
205RSHAPE(shape_id_t shape_id)
207 uint32_t offset = (shape_id & SHAPE_ID_OFFSET_MASK);
210 return &rb_shape_tree.shape_list[offset];
213int32_t rb_shape_id_offset(
void);
215RUBY_FUNC_EXPORTED shape_id_t rb_obj_shape_id(
VALUE obj);
216shape_id_t rb_shape_get_next_iv_shape(shape_id_t shape_id,
ID id);
217bool rb_shape_get_iv_index(shape_id_t shape_id,
ID id, attr_index_t *value);
218bool rb_shape_get_iv_index_with_hint(shape_id_t shape_id,
ID id, attr_index_t *value, shape_id_t *shape_id_hint);
219bool rb_shape_find_ivar(shape_id_t shape_id,
ID id, shape_id_t *ivar_shape);
221typedef int rb_shape_foreach_transition_callback(shape_id_t shape_id,
void *data);
222bool rb_shape_foreach_field(shape_id_t shape_id, rb_shape_foreach_transition_callback func,
void *data);
224shape_id_t rb_shape_transition_frozen(
VALUE obj);
225shape_id_t rb_shape_transition_complex(
VALUE obj);
226shape_id_t rb_shape_transition_remove_ivar(
VALUE obj,
ID id, shape_id_t *removed_shape_id);
227shape_id_t rb_shape_transition_add_ivar(
VALUE obj,
ID id);
228shape_id_t rb_shape_transition_add_ivar_no_warnings(
VALUE klass, shape_id_t original_shape_id,
ID id);
229shape_id_t rb_shape_transition_object_id(
VALUE obj);
230shape_id_t rb_shape_transition_heap(
VALUE obj,
size_t heap_index);
231shape_id_t rb_shape_object_id(shape_id_t original_shape_id);
233void rb_shape_free_all(
void);
235shape_id_t rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id);
236void rb_shape_copy_fields(
VALUE dest,
VALUE *dest_buf, shape_id_t dest_shape_id,
VALUE *src_buf, shape_id_t src_shape_id);
237void rb_shape_copy_complex_ivars(
VALUE dest,
VALUE obj, shape_id_t src_shape_id,
st_table *fields_table);
240rb_shape_too_complex_p(shape_id_t shape_id)
242 return shape_id & SHAPE_ID_FL_TOO_COMPLEX;
246rb_shape_obj_too_complex_p(
VALUE obj)
252rb_shape_has_object_id(shape_id_t shape_id)
254 return shape_id & SHAPE_ID_FL_HAS_OBJECT_ID;
258rb_shape_canonical_p(shape_id_t shape_id)
260 return !(shape_id & SHAPE_ID_FL_NON_CANONICAL_MASK);
264rb_shape_heap_index(shape_id_t shape_id)
266 return (uint8_t)((shape_id & SHAPE_ID_HEAP_INDEX_MASK) >> SHAPE_ID_HEAP_INDEX_OFFSET);
269static inline shape_id_t
270rb_shape_root(
size_t heap_id)
272 shape_id_t heap_index = (shape_id_t)(heap_id + 1);
273 shape_id_t heap_flags = heap_index << SHAPE_ID_HEAP_INDEX_OFFSET;
275 RUBY_ASSERT((heap_flags & SHAPE_ID_HEAP_INDEX_MASK) == heap_flags);
276 RUBY_ASSERT(rb_shape_heap_index(heap_flags) == heap_index);
278 return ROOT_SHAPE_ID | heap_flags;
281static inline shape_id_t
282RSHAPE_PARENT_RAW_ID(shape_id_t shape_id)
284 return RSHAPE(shape_id)->parent_id;
288RSHAPE_DIRECT_CHILD_P(shape_id_t parent_id, shape_id_t child_id)
290 return (parent_id & SHAPE_ID_FLAGS_MASK) == (child_id & SHAPE_ID_FLAGS_MASK) &&
291 RSHAPE(child_id)->parent_id == (parent_id & SHAPE_ID_OFFSET_MASK);
294static inline enum shape_type
295RSHAPE_TYPE(shape_id_t shape_id)
297 return RSHAPE(shape_id)->type;
301RSHAPE_TYPE_P(shape_id_t shape_id,
enum shape_type
type)
303 return RSHAPE_TYPE(shape_id) ==
type;
306static inline attr_index_t
307RSHAPE_EMBEDDED_CAPACITY(shape_id_t shape_id)
309 uint8_t heap_index = rb_shape_heap_index(shape_id);
311 return rb_shape_tree.capacities[heap_index - 1];
316static inline attr_index_t
317RSHAPE_CAPACITY(shape_id_t shape_id)
319 attr_index_t embedded_capacity = RSHAPE_EMBEDDED_CAPACITY(shape_id);
321 if (embedded_capacity > RSHAPE(shape_id)->capacity) {
322 return embedded_capacity;
325 return RSHAPE(shape_id)->capacity;
329static inline attr_index_t
330RSHAPE_LEN(shape_id_t shape_id)
332 return RSHAPE(shape_id)->next_field_index;
335static inline attr_index_t
336RSHAPE_INDEX(shape_id_t shape_id)
339 return RSHAPE_LEN(shape_id) - 1;
343RSHAPE_EDGE_NAME(shape_id_t shape_id)
345 return RSHAPE(shape_id)->edge_name;
348static inline uint32_t
349ROBJECT_FIELDS_CAPACITY(
VALUE obj)
355 return RSHAPE_CAPACITY(RBASIC_SHAPE_ID(obj));
359ROBJECT_FIELDS_HASH(
VALUE obj)
378static inline uint32_t
379ROBJECT_FIELDS_COUNT_COMPLEX(
VALUE obj)
381 return (uint32_t)rb_st_table_size(ROBJECT_FIELDS_HASH(obj));
384static inline uint32_t
385ROBJECT_FIELDS_COUNT_NOT_COMPLEX(
VALUE obj)
389 return RSHAPE(RBASIC_SHAPE_ID(obj))->next_field_index;
392static inline uint32_t
393ROBJECT_FIELDS_COUNT(
VALUE obj)
395 if (rb_shape_obj_too_complex_p(obj)) {
396 return ROBJECT_FIELDS_COUNT_COMPLEX(obj);
399 return ROBJECT_FIELDS_COUNT_NOT_COMPLEX(obj);
403static inline uint32_t
404RBASIC_FIELDS_COUNT(
VALUE obj)
406 return RSHAPE(RBASIC_SHAPE_ID(obj))->next_field_index;
410rb_shape_obj_has_id(
VALUE obj)
412 return rb_shape_has_object_id(RBASIC_SHAPE_ID(obj));
416rb_shape_has_ivars(shape_id_t shape_id)
418 return shape_id & SHAPE_ID_HAS_IVAR_MASK;
422rb_shape_obj_has_ivars(
VALUE obj)
424 return rb_shape_has_ivars(RBASIC_SHAPE_ID(obj));
428rb_shape_has_fields(shape_id_t shape_id)
430 return shape_id & (SHAPE_ID_OFFSET_MASK | SHAPE_ID_FL_TOO_COMPLEX);
434rb_shape_obj_has_fields(
VALUE obj)
436 return rb_shape_has_fields(RBASIC_SHAPE_ID(obj));
440rb_obj_gen_fields_p(
VALUE obj)
452 return rb_shape_obj_has_fields(obj);
456RUBY_SYMBOL_EXPORT_BEGIN
457typedef void each_shape_callback(shape_id_t shape_id,
void *data);
458void rb_shape_each_shape_id(each_shape_callback callback,
void *data);
459size_t rb_shape_memsize(shape_id_t shape);
460size_t rb_shape_edges_count(shape_id_t shape_id);
461size_t rb_shape_depth(shape_id_t shape_id);
462RUBY_SYMBOL_EXPORT_END
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
#define RUBY_ATOMIC_LOAD(var)
Atomic load.
#define RUBY_EXTERN
Declaration of externally visible global variables.
#define TYPE(_)
Old name of rb_type.
#define T_IMEMO
Old name of RUBY_T_IMEMO.
#define T_NONE
Old name of RUBY_T_NONE.
#define T_MODULE
Old name of RUBY_T_MODULE.
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
#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.
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RBASIC(obj)
Convenient casting macro.
#define ROBJECT(obj)
Convenient casting macro.
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.