Ruby  3.4.0dev (2024-12-06 revision 892c46283a5ea4179500d951c9d4866c0051f27b)
shape.h (892c46283a5ea4179500d951c9d4866c0051f27b)
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 
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
13 
14 #else
15 
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
21 
22 #endif
23 
24 typedef uint32_t redblack_id_t;
25 
26 #define MAX_IVARS (attr_index_t)(-1)
27 
28 # define SHAPE_MASK (((uintptr_t)1 << SHAPE_ID_NUM_BITS) - 1)
29 # define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
30 
31 # define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - SHAPE_ID_NUM_BITS)
32 
33 # define SHAPE_MAX_VARIATIONS 8
34 
35 # define INVALID_SHAPE_ID SHAPE_MASK
36 # define ROOT_SHAPE_ID 0x0
37 
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)
41 
42 typedef struct redblack_node redblack_node_t;
43 
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 heap_index;
51  shape_id_t parent_id;
52  redblack_node_t * ancestor_index;
53 };
54 
55 typedef struct rb_shape rb_shape_t;
56 
57 struct redblack_node {
58  ID key;
59  rb_shape_t * value;
60  redblack_id_t l;
61  redblack_id_t r;
62 };
63 
64 enum shape_type {
65  SHAPE_ROOT,
66  SHAPE_IVAR,
67  SHAPE_FROZEN,
68  SHAPE_T_OBJECT,
69  SHAPE_OBJ_TOO_COMPLEX,
70 };
71 
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;
77 
78  redblack_node_t *shape_cache;
79  unsigned int cache_size;
81 RUBY_EXTERN rb_shape_tree_t *rb_shape_tree_ptr;
82 
83 static inline rb_shape_tree_t *
84 rb_current_shape_tree(void)
85 {
86  return rb_shape_tree_ptr;
87 }
88 #define GET_SHAPE_TREE() rb_current_shape_tree()
89 
90 static inline shape_id_t
91 get_shape_id_from_flags(VALUE obj)
92 {
94  return (shape_id_t)(SHAPE_MASK & ((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT));
95 }
96 
97 static inline void
98 set_shape_id_in_flags(VALUE obj, shape_id_t shape_id)
99 {
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);
104 }
105 
106 
107 #if SHAPE_IN_BASIC_FLAGS
108 static inline shape_id_t
109 RBASIC_SHAPE_ID(VALUE obj)
110 {
111  return get_shape_id_from_flags(obj);
112 }
113 
114 static inline void
115 RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
116 {
117  set_shape_id_in_flags(obj, shape_id);
118 }
119 #endif
120 
121 static inline shape_id_t
122 ROBJECT_SHAPE_ID(VALUE obj)
123 {
124  RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
125  return get_shape_id_from_flags(obj);
126 }
127 
128 static inline void
129 ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
130 {
131  RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
132  set_shape_id_in_flags(obj, shape_id);
133 }
134 
135 static inline shape_id_t
136 RCLASS_SHAPE_ID(VALUE obj)
137 {
139  return get_shape_id_from_flags(obj);
140 }
141 
142 static inline void
143 RCLASS_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
144 {
146  set_shape_id_in_flags(obj, shape_id);
147 }
148 
149 rb_shape_t * rb_shape_get_root_shape(void);
150 int32_t rb_shape_id_offset(void);
151 
152 rb_shape_t * rb_shape_get_parent(rb_shape_t * shape);
153 
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);
160 
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);
168 
169 rb_shape_t * rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape);
170 
171 static inline uint32_t
172 ROBJECT_IV_CAPACITY(VALUE obj)
173 {
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;
179 }
180 
181 static inline st_table *
182 ROBJECT_IV_HASH(VALUE obj)
183 {
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;
187 }
188 
189 static inline void
190 ROBJECT_SET_IV_HASH(VALUE obj, const st_table *tbl)
191 {
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;
195 }
196 
197 size_t rb_id_table_size(const struct rb_id_table *tbl);
198 
199 static inline uint32_t
200 ROBJECT_IV_COUNT(VALUE obj)
201 {
202  if (rb_shape_obj_too_complex(obj)) {
203  return (uint32_t)rb_st_table_size(ROBJECT_IV_HASH(obj));
204  }
205  else {
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;
209  }
210 }
211 
212 static inline uint32_t
213 RBASIC_IV_COUNT(VALUE obj)
214 {
215  return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj))->next_iv_index;
216 }
217 
218 rb_shape_t *rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *orig_shape);
219 
220 bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id);
221 
222 VALUE rb_obj_debug_shape(VALUE self, VALUE obj);
223 
224 // For ext/objspace
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
233 
234 #endif
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition: assert.h:219
#define RUBY_EXTERN
Declaration of externally visible global variables.
Definition: dllexport.h:45
#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.
Definition: cxxanyargs.hpp:56
#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: shape.h:44
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:376
@ RUBY_T_OBJECT
Definition: value_type.h:116