[ruby/irb] Change debug test workaround only enabled when output is
[ruby.git] / shape.h
blob07eb2c979fc4eee4a6492aa225ddebd29881ef9b
1 #ifndef RUBY_SHAPE_H
2 #define RUBY_SHAPE_H
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
14 #else
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
22 #endif
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;
44 struct rb_shape {
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
49 uint8_t type;
50 uint8_t size_pool_index;
51 shape_id_t parent_id;
52 redblack_node_t * ancestor_index;
55 typedef struct rb_shape rb_shape_t;
57 struct redblack_node {
58 ID key;
59 rb_shape_t * value;
60 redblack_id_t l;
61 redblack_id_t r;
64 enum shape_type {
65 SHAPE_ROOT,
66 SHAPE_IVAR,
67 SHAPE_FROZEN,
68 SHAPE_T_OBJECT,
69 SHAPE_OBJ_TOO_COMPLEX,
72 typedef struct {
73 /* object shapes */
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;
80 } rb_shape_tree_t;
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));
97 static inline void
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);
114 static inline void
115 RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
117 set_shape_id_in_flags(obj, shape_id);
119 #endif
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);
128 static inline void
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);
142 static inline void
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);
168 rb_shape_t * rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape);
170 static inline uint32_t
171 ROBJECT_IV_CAPACITY(VALUE obj)
173 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
174 // Asking for capacity doesn't make sense when the object is using
175 // a hash table for storing instance variables
176 RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
177 return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->capacity;
180 static inline st_table *
181 ROBJECT_IV_HASH(VALUE obj)
183 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
184 RUBY_ASSERT(rb_shape_obj_too_complex(obj));
185 return (st_table *)ROBJECT(obj)->as.heap.ivptr;
188 static inline void
189 ROBJECT_SET_IV_HASH(VALUE obj, const st_table *tbl)
191 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
192 RUBY_ASSERT(rb_shape_obj_too_complex(obj));
193 ROBJECT(obj)->as.heap.ivptr = (VALUE *)tbl;
196 size_t rb_id_table_size(const struct rb_id_table *tbl);
198 static inline uint32_t
199 ROBJECT_IV_COUNT(VALUE obj)
201 if (rb_shape_obj_too_complex(obj)) {
202 return (uint32_t)rb_st_table_size(ROBJECT_IV_HASH(obj));
204 else {
205 RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
206 RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
207 return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->next_iv_index;
211 static inline uint32_t
212 RBASIC_IV_COUNT(VALUE obj)
214 return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj))->next_iv_index;
217 rb_shape_t *rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *orig_shape);
219 bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id);
221 VALUE rb_obj_debug_shape(VALUE self, VALUE obj);
223 // For ext/objspace
224 RUBY_SYMBOL_EXPORT_BEGIN
225 typedef void each_shape_callback(rb_shape_t * shape, void *data);
226 void rb_shape_each_shape(each_shape_callback callback, void *data);
227 size_t rb_shape_memsize(rb_shape_t *shape);
228 size_t rb_shape_edges_count(rb_shape_t *shape);
229 size_t rb_shape_depth(rb_shape_t *shape);
230 shape_id_t rb_shape_id(rb_shape_t * shape);
231 RUBY_SYMBOL_EXPORT_END
233 #endif