4 #include "internal/gc.h"
6 #if (SIZEOF_UINT64_T <= SIZEOF_VALUE)
8 #define SIZEOF_SHAPE_T 4
9 #define SHAPE_IN_BASIC_FLAGS 1
10 typedef uint32_t attr_index_t
;
11 typedef uint32_t shape_id_t
;
12 # define SHAPE_ID_NUM_BITS 32
16 #define SIZEOF_SHAPE_T 2
17 #define SHAPE_IN_BASIC_FLAGS 0
18 typedef uint16_t attr_index_t
;
19 typedef uint16_t shape_id_t
;
20 # define SHAPE_ID_NUM_BITS 16
24 typedef uint32_t redblack_id_t
;
26 #define MAX_IVARS (attr_index_t)(-1)
28 # define SHAPE_MASK (((uintptr_t)1 << SHAPE_ID_NUM_BITS) - 1)
29 # define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
31 # define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - SHAPE_ID_NUM_BITS)
33 # define SHAPE_MAX_VARIATIONS 8
35 # define INVALID_SHAPE_ID SHAPE_MASK
36 # define ROOT_SHAPE_ID 0x0
38 # define SPECIAL_CONST_SHAPE_ID (ROOT_SHAPE_ID + 1)
39 # define OBJ_TOO_COMPLEX_SHAPE_ID (SPECIAL_CONST_SHAPE_ID + 1)
40 # define FIRST_T_OBJECT_SHAPE_ID (OBJ_TOO_COMPLEX_SHAPE_ID + 1)
42 typedef struct redblack_node redblack_node_t
;
45 struct rb_id_table
*edges
; // id_table from ID (ivar) to next shape
46 ID edge_name
; // ID (ivar) for transition from parent to rb_shape
47 attr_index_t next_iv_index
;
48 uint32_t capacity
; // Total capacity of the object with this shape
52 redblack_node_t
*ancestor_index
;
55 typedef struct rb_shape rb_shape_t
;
57 struct redblack_node
{
69 SHAPE_OBJ_TOO_COMPLEX
,
74 rb_shape_t
*shape_list
;
75 rb_shape_t
*root_shape
;
76 shape_id_t next_shape_id
;
78 redblack_node_t
*shape_cache
;
79 unsigned int cache_size
;
81 RUBY_EXTERN rb_shape_tree_t
*rb_shape_tree_ptr
;
83 static inline rb_shape_tree_t
*
84 rb_current_shape_tree(void)
86 return rb_shape_tree_ptr
;
88 #define GET_SHAPE_TREE() rb_current_shape_tree()
90 static inline shape_id_t
91 get_shape_id_from_flags(VALUE obj
)
93 RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj
));
94 return (shape_id_t
)(SHAPE_MASK
& ((RBASIC(obj
)->flags
) >> SHAPE_FLAG_SHIFT
));
98 set_shape_id_in_flags(VALUE obj
, shape_id_t shape_id
)
100 // Ractors are occupying the upper 32 bits of flags, but only in debug mode
101 // Object shapes are occupying top bits
102 RBASIC(obj
)->flags
&= SHAPE_FLAG_MASK
;
103 RBASIC(obj
)->flags
|= ((VALUE
)(shape_id
) << SHAPE_FLAG_SHIFT
);
107 #if SHAPE_IN_BASIC_FLAGS
108 static inline shape_id_t
109 RBASIC_SHAPE_ID(VALUE obj
)
111 return get_shape_id_from_flags(obj
);
115 RBASIC_SET_SHAPE_ID(VALUE obj
, shape_id_t shape_id
)
117 set_shape_id_in_flags(obj
, shape_id
);
121 static inline shape_id_t
122 ROBJECT_SHAPE_ID(VALUE obj
)
124 RBIMPL_ASSERT_TYPE(obj
, RUBY_T_OBJECT
);
125 return get_shape_id_from_flags(obj
);
129 ROBJECT_SET_SHAPE_ID(VALUE obj
, shape_id_t shape_id
)
131 RBIMPL_ASSERT_TYPE(obj
, RUBY_T_OBJECT
);
132 set_shape_id_in_flags(obj
, shape_id
);
135 static inline shape_id_t
136 RCLASS_SHAPE_ID(VALUE obj
)
138 RUBY_ASSERT(RB_TYPE_P(obj
, T_CLASS
) || RB_TYPE_P(obj
, T_MODULE
));
139 return get_shape_id_from_flags(obj
);
143 RCLASS_SET_SHAPE_ID(VALUE obj
, shape_id_t shape_id
)
145 RUBY_ASSERT(RB_TYPE_P(obj
, T_CLASS
) || RB_TYPE_P(obj
, T_MODULE
));
146 set_shape_id_in_flags(obj
, shape_id
);
149 rb_shape_t
*rb_shape_get_root_shape(void);
150 int32_t rb_shape_id_offset(void);
152 rb_shape_t
*rb_shape_get_parent(rb_shape_t
*shape
);
154 RUBY_FUNC_EXPORTED rb_shape_t
*rb_shape_get_shape_by_id(shape_id_t shape_id
);
155 RUBY_FUNC_EXPORTED shape_id_t
rb_shape_get_shape_id(VALUE obj
);
156 rb_shape_t
*rb_shape_get_next_iv_shape(rb_shape_t
*shape
, ID id
);
157 bool rb_shape_get_iv_index(rb_shape_t
*shape
, ID id
, attr_index_t
*value
);
158 bool rb_shape_get_iv_index_with_hint(shape_id_t shape_id
, ID id
, attr_index_t
*value
, shape_id_t
*shape_id_hint
);
159 RUBY_FUNC_EXPORTED
bool rb_shape_obj_too_complex(VALUE obj
);
161 void rb_shape_set_shape(VALUE obj
, rb_shape_t
*shape
);
162 rb_shape_t
*rb_shape_get_shape(VALUE obj
);
163 int rb_shape_frozen_shape_p(rb_shape_t
*shape
);
164 rb_shape_t
*rb_shape_transition_shape_frozen(VALUE obj
);
165 bool rb_shape_transition_shape_remove_ivar(VALUE obj
, ID id
, rb_shape_t
*shape
, VALUE
*removed
);
166 rb_shape_t
*rb_shape_get_next(rb_shape_t
*shape
, VALUE obj
, ID id
);
167 rb_shape_t
*rb_shape_get_next_no_warnings(rb_shape_t
*shape
, VALUE obj
, ID id
);
169 rb_shape_t
*rb_shape_rebuild_shape(rb_shape_t
*initial_shape
, rb_shape_t
*dest_shape
);
171 static inline uint32_t
172 ROBJECT_IV_CAPACITY(VALUE obj
)
174 RBIMPL_ASSERT_TYPE(obj
, RUBY_T_OBJECT
);
175 // Asking for capacity doesn't make sense when the object is using
176 // a hash table for storing instance variables
177 RUBY_ASSERT(!rb_shape_obj_too_complex(obj
));
178 return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj
))->capacity
;
181 static inline st_table
*
182 ROBJECT_IV_HASH(VALUE obj
)
184 RBIMPL_ASSERT_TYPE(obj
, RUBY_T_OBJECT
);
185 RUBY_ASSERT(rb_shape_obj_too_complex(obj
));
186 return (st_table
*)ROBJECT(obj
)->as
.heap
.ivptr
;
190 ROBJECT_SET_IV_HASH(VALUE obj
, const st_table
*tbl
)
192 RBIMPL_ASSERT_TYPE(obj
, RUBY_T_OBJECT
);
193 RUBY_ASSERT(rb_shape_obj_too_complex(obj
));
194 ROBJECT(obj
)->as
.heap
.ivptr
= (VALUE
*)tbl
;
197 size_t rb_id_table_size(const struct rb_id_table
*tbl
);
199 static inline uint32_t
200 ROBJECT_IV_COUNT(VALUE obj
)
202 if (rb_shape_obj_too_complex(obj
)) {
203 return (uint32_t)rb_st_table_size(ROBJECT_IV_HASH(obj
));
206 RBIMPL_ASSERT_TYPE(obj
, RUBY_T_OBJECT
);
207 RUBY_ASSERT(!rb_shape_obj_too_complex(obj
));
208 return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj
))->next_iv_index
;
212 static inline uint32_t
213 RBASIC_IV_COUNT(VALUE obj
)
215 return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj
))->next_iv_index
;
218 rb_shape_t
*rb_shape_traverse_from_new_root(rb_shape_t
*initial_shape
, rb_shape_t
*orig_shape
);
220 bool rb_shape_set_shape_id(VALUE obj
, shape_id_t shape_id
);
222 VALUE
rb_obj_debug_shape(VALUE self
, VALUE obj
);
225 RUBY_SYMBOL_EXPORT_BEGIN
226 typedef void each_shape_callback(rb_shape_t
*shape
, void *data
);
227 void rb_shape_each_shape(each_shape_callback callback
, void *data
);
228 size_t rb_shape_memsize(rb_shape_t
*shape
);
229 size_t rb_shape_edges_count(rb_shape_t
*shape
);
230 size_t rb_shape_depth(rb_shape_t
*shape
);
231 shape_id_t
rb_shape_id(rb_shape_t
*shape
);
232 RUBY_SYMBOL_EXPORT_END