Ruby 3.2.3p157 (2024-01-18 revision 52bb2ac0a6971d0391efa2275f7a66bff319087c)
shape.h
1#ifndef RUBY_SHAPE_H
2#define RUBY_SHAPE_H
3
4#include "internal/gc.h"
5
6#if (SIZEOF_UINT64_T == SIZEOF_VALUE)
7#define SIZEOF_SHAPE_T 4
8#define SHAPE_IN_BASIC_FLAGS 1
9typedef uint32_t attr_index_t;
10#else
11#define SIZEOF_SHAPE_T 2
12#define SHAPE_IN_BASIC_FLAGS 0
13typedef uint16_t attr_index_t;
14#endif
15
16#define MAX_IVARS (attr_index_t)(-1)
17
18#if SIZEOF_SHAPE_T == 4
19typedef uint32_t shape_id_t;
20# define SHAPE_ID_NUM_BITS 32
21#else
22typedef uint16_t shape_id_t;
23# define SHAPE_ID_NUM_BITS 16
24#endif
25
26# define SHAPE_MASK (((uintptr_t)1 << SHAPE_ID_NUM_BITS) - 1)
27# define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
28
29# define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - SHAPE_ID_NUM_BITS)
30
31# define SHAPE_BITMAP_SIZE 16384
32
33# define SHAPE_MAX_VARIATIONS 8
34
35# define MAX_SHAPE_ID (SHAPE_MASK - 1)
36# define INVALID_SHAPE_ID SHAPE_MASK
37# define ROOT_SHAPE_ID 0x0
38
39# define SPECIAL_CONST_SHAPE_ID (SIZE_POOL_COUNT * 2)
40# define OBJ_TOO_COMPLEX_SHAPE_ID (SPECIAL_CONST_SHAPE_ID + 1)
41
42struct rb_shape {
43 struct rb_id_table * edges; // id_table from ID (ivar) to next shape
44 ID edge_name; // ID (ivar) for transition from parent to rb_shape
45 attr_index_t next_iv_index;
46 uint32_t capacity; // Total capacity of the object with this shape
47 uint8_t type;
48 uint8_t size_pool_index;
49 shape_id_t parent_id;
50};
51
52typedef struct rb_shape rb_shape_t;
53
54enum shape_type {
55 SHAPE_ROOT,
56 SHAPE_IVAR,
57 SHAPE_FROZEN,
58 SHAPE_CAPACITY_CHANGE,
59 SHAPE_INITIAL_CAPACITY,
60 SHAPE_T_OBJECT,
61 SHAPE_OBJ_TOO_COMPLEX,
62};
63
64#if SHAPE_IN_BASIC_FLAGS
65static inline shape_id_t
66RBASIC_SHAPE_ID(VALUE obj)
67{
69 return (shape_id_t)(SHAPE_MASK & ((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT));
70}
71
72static inline void
73RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
74{
75 // Ractors are occupying the upper 32 bits of flags, but only in debug mode
76 // Object shapes are occupying top bits
77 RBASIC(obj)->flags &= SHAPE_FLAG_MASK;
78 RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
79}
80
81static inline shape_id_t
82ROBJECT_SHAPE_ID(VALUE obj)
83{
84 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
85 return RBASIC_SHAPE_ID(obj);
86}
87
88static inline void
89ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
90{
91 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
92 RBASIC_SET_SHAPE_ID(obj, shape_id);
93}
94
95static inline shape_id_t
96RCLASS_SHAPE_ID(VALUE obj)
97{
99 return RBASIC_SHAPE_ID(obj);
100}
101
102#else
103
104static inline shape_id_t
105ROBJECT_SHAPE_ID(VALUE obj)
106{
107 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
108 return (shape_id_t)(SHAPE_MASK & (RBASIC(obj)->flags >> SHAPE_FLAG_SHIFT));
109}
110
111static inline void
112ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
113{
114 RBASIC(obj)->flags &= SHAPE_FLAG_MASK;
115 RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
116}
117
118MJIT_SYMBOL_EXPORT_BEGIN
119shape_id_t rb_rclass_shape_id(VALUE obj);
120MJIT_SYMBOL_EXPORT_END
121
122static inline shape_id_t RCLASS_SHAPE_ID(VALUE obj)
123{
124 return rb_rclass_shape_id(obj);
125}
126
127#endif
128
129bool rb_shape_root_shape_p(rb_shape_t* shape);
130rb_shape_t * rb_shape_get_root_shape(void);
131uint8_t rb_shape_id_num_bits(void);
132int32_t rb_shape_id_offset(void);
133
134rb_shape_t* rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id);
135rb_shape_t * rb_shape_get_parent(rb_shape_t * shape);
136
137MJIT_SYMBOL_EXPORT_BEGIN
138rb_shape_t* rb_shape_get_shape_by_id(shape_id_t shape_id);
139shape_id_t rb_shape_get_shape_id(VALUE obj);
140rb_shape_t * rb_shape_get_next_iv_shape(rb_shape_t * shape, ID id);
141bool rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t * value);
142bool rb_shape_obj_too_complex(VALUE obj);
143MJIT_SYMBOL_EXPORT_END
144
145void rb_shape_set_shape(VALUE obj, rb_shape_t* shape);
146rb_shape_t* rb_shape_get_shape(VALUE obj);
147int rb_shape_frozen_shape_p(rb_shape_t* shape);
148void rb_shape_transition_shape_frozen(VALUE obj);
149void rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE * removed);
150rb_shape_t * rb_shape_transition_shape_capa(rb_shape_t * shape, uint32_t new_capacity);
151rb_shape_t* rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id);
152
153rb_shape_t * rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape);
154
155static inline uint32_t
156ROBJECT_IV_CAPACITY(VALUE obj)
157{
158 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
159 // Asking for capacity doesn't make sense when the object is using
160 // a hash table for storing instance variables
161 RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) != OBJ_TOO_COMPLEX_SHAPE_ID);
162 return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->capacity;
163}
164
165static inline st_table *
166ROBJECT_IV_HASH(VALUE obj)
167{
168 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
169 RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID);
170 return (st_table *)ROBJECT(obj)->as.heap.ivptr;
171}
172
173static inline void
174ROBJECT_SET_IV_HASH(VALUE obj, const struct rb_id_table *tbl)
175{
176 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
177 RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID);
178 ROBJECT(obj)->as.heap.ivptr = (VALUE *)tbl;
179}
180
181size_t rb_id_table_size(const struct rb_id_table *tbl);
182
183static inline uint32_t
184ROBJECT_IV_COUNT(VALUE obj)
185{
186 if (ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID) {
187 return (uint32_t)rb_st_table_size(ROBJECT_IV_HASH(obj));
188 }
189 else {
190 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
191 RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) != OBJ_TOO_COMPLEX_SHAPE_ID);
192 return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->next_iv_index;
193 }
194}
195
196static inline uint32_t
197RBASIC_IV_COUNT(VALUE obj)
198{
199 return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj))->next_iv_index;
200}
201
202static inline uint32_t
203RCLASS_IV_COUNT(VALUE obj)
204{
206 uint32_t ivc = rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))->next_iv_index;
207 return ivc;
208}
209
210rb_shape_t * rb_shape_alloc(ID edge_name, rb_shape_t * parent);
211rb_shape_t * rb_shape_alloc_with_size_pool_index(ID edge_name, rb_shape_t * parent, uint8_t size_pool_index);
212rb_shape_t * rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id);
213
214rb_shape_t *rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *orig_shape);
215
216bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id);
217
218VALUE rb_obj_debug_shape(VALUE self, VALUE obj);
219VALUE rb_shape_flags_mask(void);
220void rb_shape_set_too_complex(VALUE obj);
221
222// For ext/objspace
223RUBY_SYMBOL_EXPORT_BEGIN
224typedef void each_shape_callback(rb_shape_t * shape, void *data);
225void rb_shape_each_shape(each_shape_callback callback, void *data);
226size_t rb_shape_memsize(rb_shape_t *shape);
227size_t rb_shape_edges_count(rb_shape_t *shape);
228size_t rb_shape_depth(rb_shape_t *shape);
229shape_id_t rb_shape_id(rb_shape_t * shape);
230RUBY_SYMBOL_EXPORT_END
231
232#endif
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:177
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition value_type.h:70
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
#define ROBJECT(obj)
Convenient casting macro.
Definition robject.h:43
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
Definition st.h:79
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:375
@ RUBY_T_MODULE
Definition value_type.h:117
@ RUBY_T_OBJECT
Definition value_type.h:115
@ RUBY_T_CLASS
Definition value_type.h:116