datadog-ruby_core_source 3.5.5 → 3.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -2
  3. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/ccan/build_assert/build_assert.h +40 -0
  4. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/ccan/check_type/check_type.h +63 -0
  5. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/ccan/container_of/container_of.h +142 -0
  6. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/ccan/list/list.h +791 -0
  7. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/ccan/str/str.h +17 -0
  8. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/constant.h +53 -0
  9. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/debug_counter.h +428 -0
  10. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/hrtime.h +237 -0
  11. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/id.h +365 -0
  12. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/id_table.h +74 -0
  13. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/array.h +158 -0
  14. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/basic_operators.h +67 -0
  15. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/bits.h +647 -0
  16. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/box.h +103 -0
  17. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/class.h +797 -0
  18. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/compilers.h +104 -0
  19. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/coverage.h +51 -0
  20. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/gc.h +411 -0
  21. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/imemo.h +302 -0
  22. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/sanitizers.h +346 -0
  23. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/serial.h +23 -0
  24. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/set_table.h +77 -0
  25. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/static_assert.h +16 -0
  26. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/time.h +34 -0
  27. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/variable.h +81 -0
  28. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/vm.h +144 -0
  29. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal/warnings.h +16 -0
  30. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/internal.h +106 -0
  31. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/iseq.h +439 -0
  32. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/method.h +279 -0
  33. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/node.h +122 -0
  34. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/parser_st.h +161 -0
  35. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/parser_value.h +116 -0
  36. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/arena.h +37 -0
  37. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/ast.h +10371 -0
  38. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/buffer.h +52 -0
  39. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/comments.h +43 -0
  40. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/compiler/align.h +36 -0
  41. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/compiler/exported.h +24 -0
  42. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/compiler/filesystem.h +32 -0
  43. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/compiler/nodiscard.h +22 -0
  44. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/compiler/nonnull.h +18 -0
  45. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/constant_pool.h +81 -0
  46. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/diagnostic.h +93 -0
  47. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/errors_format.h +53 -0
  48. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/excludes.h +29 -0
  49. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/integer.h +41 -0
  50. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/json.h +32 -0
  51. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/line_offset_list.h +61 -0
  52. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/magic_comments.h +35 -0
  53. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/node.h +94 -0
  54. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/options.h +335 -0
  55. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/parser.h +348 -0
  56. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/prettyprint.h +31 -0
  57. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/prism.h +131 -0
  58. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/serialize.h +115 -0
  59. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/source.h +155 -0
  60. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/stream.h +28 -0
  61. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/string_query.h +63 -0
  62. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/stringy.h +72 -0
  63. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism/version.h +38 -0
  64. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/prism_compile.h +204 -0
  65. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/ractor_core.h +421 -0
  66. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/ruby_assert.h +14 -0
  67. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/ruby_atomic.h +115 -0
  68. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/rubyparser.h +1389 -0
  69. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/shape.h +733 -0
  70. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/thread_none.h +25 -0
  71. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/thread_pthread.h +63 -0
  72. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/thread_sched.h +271 -0
  73. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/vm_core.h +2509 -0
  74. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/vm_debug.h +124 -0
  75. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/vm_opts.h +65 -0
  76. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/vm_sync.h +160 -0
  77. data/lib/datadog/ruby_core_source/ruby-4.1.0-preview1/zjit.h +221 -0
  78. data/lib/datadog/ruby_core_source/version.rb +1 -1
  79. metadata +77 -2
@@ -0,0 +1,733 @@
1
+ #ifndef RUBY_SHAPE_H
2
+ #define RUBY_SHAPE_H
3
+
4
+ #include "internal/gc.h"
5
+ #include "internal/imemo.h"
6
+
7
+ typedef uint8_t attr_index_t;
8
+ typedef uint32_t shape_id_t;
9
+ #define SHAPE_ID_NUM_BITS 32
10
+ #define SHAPE_ID_OFFSET_NUM_BITS 19
11
+
12
+ STATIC_ASSERT(shape_id_num_bits, SHAPE_ID_NUM_BITS == sizeof(shape_id_t) * CHAR_BIT);
13
+
14
+ #define SHAPE_BUFFER_SIZE (1 << SHAPE_ID_OFFSET_NUM_BITS)
15
+ #define SHAPE_ID_OFFSET_MASK (SHAPE_BUFFER_SIZE - 1)
16
+
17
+ #define SHAPE_ID_CAPACITY_BITS 7
18
+ #define SHAPE_ID_CAPACITY_MAX ((1U << SHAPE_ID_CAPACITY_BITS) - 1)
19
+
20
+ #define SHAPE_ID_CAPACITY_OFFSET SHAPE_ID_OFFSET_NUM_BITS
21
+ #define SHAPE_ID_FL_USHIFT (SHAPE_ID_OFFSET_NUM_BITS + SHAPE_ID_CAPACITY_BITS)
22
+
23
+ // shape_id_t bits:
24
+ // 0-18 SHAPE_ID_OFFSET_MASK
25
+ // index in rb_shape_tree.shape_list. Allow to access `rb_shape_t *`.
26
+ // This is the part that describe how fields are laid out in memory.
27
+ // 19-25 SHAPE_ID_CAPACITY_MASK
28
+ // Embedded field capacity for T_OBJECT objects.
29
+ // 26 SHAPE_ID_FL_COMPLEX
30
+ // The object is backed by a `st_table`.
31
+ // 27 SHAPE_ID_FL_FROZEN
32
+ // Whether field writes are refused: either the object is frozen, or it
33
+ // became shareable while unfrozen (see rb_obj_set_shareable in ractor.c).
34
+ // 28 SHAPE_ID_FL_HAS_OBJECT_ID
35
+ // Whether the object has an `SHAPE_OBJ_ID` transition.
36
+ // 29-30 SHAPE_ID_LAYOUT_MASK
37
+ // The object's physical field layout.
38
+
39
+ STATIC_ASSERT(robject_rdata_fields_offset, offsetof(struct RObject, as.extended) == offsetof(struct RTypedData, fields_obj));
40
+
41
+ enum shape_id_fl_type {
42
+ #define RBIMPL_SHAPE_ID_FL(n) (1<<(SHAPE_ID_FL_USHIFT+n))
43
+
44
+ SHAPE_ID_CAPACITY_MASK = ((1 << SHAPE_ID_CAPACITY_BITS) - 1) << SHAPE_ID_CAPACITY_OFFSET,
45
+
46
+ SHAPE_ID_FL_COMPLEX = RBIMPL_SHAPE_ID_FL(0),
47
+ SHAPE_ID_FL_FROZEN = RBIMPL_SHAPE_ID_FL(1),
48
+ SHAPE_ID_FL_HAS_OBJECT_ID = RBIMPL_SHAPE_ID_FL(2),
49
+
50
+ // Means IVs are found at an offset from the object's addr, or in a
51
+ // malloc allocated side table
52
+ SHAPE_ID_LAYOUT_ROBJECT = 0,
53
+
54
+ // Means this object is a class/module that is NOT RCLASS_BOXABLE, and IV's
55
+ // are found in the fields_obj found on the rclass struct
56
+ SHAPE_ID_LAYOUT_RCLASS = RBIMPL_SHAPE_ID_FL(3),
57
+
58
+ // Means this object is an extened RObject or a RTypedData and IVs are found in the
59
+ // fields_obj found on the RObject/RTypedData struct at offset `sizeof(VALUE) * 2`.
60
+ SHAPE_ID_LAYOUT_EXTENDED = RBIMPL_SHAPE_ID_FL(4),
61
+ SHAPE_ID_LAYOUT_RDATA = SHAPE_ID_LAYOUT_EXTENDED,
62
+
63
+ // Means this is a complicated object: boxable classes, structs, objects
64
+ // that store IVs on the geniv table
65
+ SHAPE_ID_LAYOUT_OTHER = SHAPE_ID_LAYOUT_RCLASS | SHAPE_ID_LAYOUT_EXTENDED,
66
+
67
+ SHAPE_ID_LAYOUT_MASK = SHAPE_ID_LAYOUT_OTHER,
68
+
69
+ SHAPE_ID_FL_NON_CANONICAL_MASK = SHAPE_ID_FL_FROZEN | SHAPE_ID_FL_HAS_OBJECT_ID,
70
+ SHAPE_ID_FLAGS_MASK = SHAPE_ID_CAPACITY_MASK | SHAPE_ID_FL_NON_CANONICAL_MASK | SHAPE_ID_FL_COMPLEX | SHAPE_ID_LAYOUT_MASK,
71
+
72
+ // These parts of the shape id are specific to the object.
73
+ // Typically, when replicating a shape transition from an object to
74
+ // its IMEMO/fields, these bits should be stripped.
75
+ // All other bits are shared between an IMEMO/fields and its owner.
76
+ SHAPE_ID_FL_PRIVATE_MASK = SHAPE_ID_LAYOUT_MASK|SHAPE_ID_CAPACITY_MASK,
77
+ #undef RBIMPL_SHAPE_ID_FL
78
+ };
79
+
80
+ // This mask allows to check if a shape_id contains any ivar.
81
+ // It relies on ROOT_SHAPE_WITH_OBJ_ID==1.
82
+ enum shape_id_mask {
83
+ SHAPE_ID_HAS_IVAR_MASK = SHAPE_ID_FL_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1),
84
+ };
85
+
86
+ // The interpreter doesn't care about frozen status, embedded capacity, or object id, and
87
+ // has its own checks for physical field layout when reading ivars.
88
+ // So we normalize shape_id by clearing these bits to improve cache hits.
89
+ // JITs however might care about some of it.
90
+ #define SHAPE_ID_READ_ONLY_MASK (~(SHAPE_ID_FL_FROZEN | SHAPE_ID_CAPACITY_MASK | SHAPE_ID_FL_HAS_OBJECT_ID | SHAPE_ID_LAYOUT_MASK))
91
+ // For write it's the same idea, but here we do care about frozen status.
92
+ #define SHAPE_ID_WRITE_MASK (~(SHAPE_ID_CAPACITY_MASK | SHAPE_ID_FL_HAS_OBJECT_ID | SHAPE_ID_LAYOUT_MASK))
93
+
94
+ typedef uint32_t redblack_id_t;
95
+
96
+ #define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * CHAR_BIT) - SHAPE_ID_NUM_BITS)
97
+ #define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
98
+
99
+ #define SHAPE_MAX_VARIATIONS 8
100
+
101
+ #define INVALID_SHAPE_ID (SHAPE_BUFFER_SIZE - 1)
102
+ #define ATTR_INDEX_NOT_SET ((attr_index_t)-1)
103
+
104
+ #define ROOT_SHAPE_ID 0x0
105
+ #define ROOT_SHAPE_WITH_OBJ_ID 0x1
106
+ #define ROOT_COMPLEX_SHAPE_ID (ROOT_SHAPE_ID | SHAPE_ID_FL_COMPLEX)
107
+ #define ROOT_COMPLEX_WITH_OBJ_ID (ROOT_SHAPE_WITH_OBJ_ID | SHAPE_ID_FL_COMPLEX | SHAPE_ID_FL_HAS_OBJECT_ID)
108
+
109
+ enum shape_type {
110
+ SHAPE_ROOT,
111
+ SHAPE_IVAR,
112
+ SHAPE_OBJ_ID
113
+ };
114
+
115
+ struct rb_shape {
116
+ VALUE edges; // id_table from ID (ivar) to next shape
117
+ ID edge_name; // ID (ivar) for transition from parent to rb_shape
118
+ redblack_id_t ancestor_index;
119
+ shape_id_t parent_offset;
120
+ attr_index_t next_field_index; // Fields are either ivars or internal properties like `object_id`
121
+ attr_index_t capacity; // Total capacity of the object with this shape
122
+ enum shape_type type : 8;
123
+ };
124
+
125
+ typedef struct rb_shape rb_shape_t;
126
+
127
+ enum shape_flags {
128
+ SHAPE_FL_FROZEN = 1 << 0,
129
+ SHAPE_FL_HAS_OBJECT_ID = 1 << 1,
130
+ SHAPE_FL_COMPLEX = 1 << 2,
131
+
132
+ SHAPE_FL_NON_CANONICAL_MASK = SHAPE_FL_FROZEN | SHAPE_FL_HAS_OBJECT_ID,
133
+ };
134
+
135
+ typedef struct {
136
+ rb_shape_t *shape_list;
137
+ attr_index_t max_capacity;
138
+ ID id_object_id;
139
+ } rb_shape_tree_t;
140
+
141
+ RUBY_SYMBOL_EXPORT_BEGIN
142
+ RUBY_EXTERN rb_shape_tree_t rb_shape_tree;
143
+ RUBY_SYMBOL_EXPORT_END
144
+
145
+ size_t rb_shapes_cache_size(void);
146
+ size_t rb_shapes_count(void);
147
+
148
+ static inline attr_index_t
149
+ rb_shape_max_capacity(void)
150
+ {
151
+ return rb_shape_tree.max_capacity;
152
+ }
153
+
154
+ static inline shape_id_t
155
+ RBASIC_SHAPE_ID(VALUE obj)
156
+ {
157
+ RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
158
+ RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_fields));
159
+ #if RBASIC_SHAPE_ID_FIELD
160
+ return (shape_id_t)((RBASIC(obj)->shape_id));
161
+ #else
162
+ return (shape_id_t)((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT);
163
+ #endif
164
+ }
165
+
166
+ // Same as RBASIC_SHAPE_ID but with flags that have no impact
167
+ // on reads removed. e.g. Remove FL_FROZEN.
168
+ static inline shape_id_t
169
+ RBASIC_SHAPE_ID_FOR_READ(VALUE obj)
170
+ {
171
+ return RBASIC_SHAPE_ID(obj) & SHAPE_ID_READ_ONLY_MASK;
172
+ }
173
+
174
+ #if RUBY_DEBUG
175
+ bool rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id);
176
+ #endif
177
+
178
+ static inline void
179
+ RBASIC_SET_FULL_SHAPE_ID_NO_CHECKS(VALUE obj, shape_id_t shape_id)
180
+ {
181
+ #if RBASIC_SHAPE_ID_FIELD
182
+ RBASIC(obj)->shape_id = (VALUE)shape_id;
183
+ #else
184
+ // Object shapes are occupying top bits
185
+ RBASIC(obj)->flags &= SHAPE_FLAG_MASK;
186
+ RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
187
+ #endif
188
+ }
189
+
190
+ static inline shape_id_t
191
+ rb_shape_layout(shape_id_t shape_id)
192
+ {
193
+ return shape_id & SHAPE_ID_LAYOUT_MASK;
194
+ }
195
+
196
+ static inline bool
197
+ rb_shape_embedded_p(shape_id_t shape_id)
198
+ {
199
+ return rb_shape_layout(shape_id) == SHAPE_ID_LAYOUT_ROBJECT;
200
+ }
201
+
202
+ static inline bool
203
+ rb_shape_extended_p(shape_id_t shape_id)
204
+ {
205
+ return rb_shape_layout(shape_id) == SHAPE_ID_LAYOUT_EXTENDED;
206
+ }
207
+
208
+ static inline bool
209
+ rb_obj_shape_embedded_p(VALUE obj)
210
+ {
211
+ return rb_shape_embedded_p(RBASIC_SHAPE_ID(obj));
212
+ }
213
+
214
+ static inline bool
215
+ rb_obj_shape_extended_p(VALUE obj)
216
+ {
217
+ return rb_shape_extended_p(RBASIC_SHAPE_ID(obj));
218
+ }
219
+
220
+ // Assigns the entire shape_id.
221
+ // shape_id_t is composed of two parts:
222
+ // - The layout and capacity part, which never changes except on GC compaction.
223
+ // - All the other bits that regularly change.
224
+ // In the overwhelming majority of cases, you want to use RBASIC_SET_SHAPE_ID
225
+ // which preserves the object's layout and capacity bits.
226
+ // In rare cases you may want to set all bits.
227
+ static inline void
228
+ RBASIC_SET_FULL_SHAPE_ID(VALUE obj, shape_id_t shape_id)
229
+ {
230
+ RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
231
+ RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_fields));
232
+
233
+ RBASIC_SET_FULL_SHAPE_ID_NO_CHECKS(obj, shape_id);
234
+
235
+ RUBY_ASSERT(rb_shape_verify_consistency(obj, shape_id));
236
+ }
237
+
238
+ static inline shape_id_t rb_shape_transition_layout(shape_id_t, shape_id_t);
239
+
240
+ static inline void
241
+ RBASIC_SET_SHAPE_ID_WITH_LAYOUT(VALUE obj, shape_id_t target_shape_id, shape_id_t layout)
242
+ {
243
+ RUBY_ASSERT((layout & SHAPE_ID_LAYOUT_MASK) == layout);
244
+ shape_id_t current_shape_id = RBASIC_SHAPE_ID(obj);
245
+ current_shape_id = rb_shape_transition_layout(current_shape_id, layout);
246
+ current_shape_id = (current_shape_id & SHAPE_ID_FL_PRIVATE_MASK) | (target_shape_id & ~SHAPE_ID_FL_PRIVATE_MASK);
247
+ RBASIC_SET_FULL_SHAPE_ID(obj, current_shape_id);
248
+ }
249
+
250
+ static inline void
251
+ RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
252
+ {
253
+ RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
254
+
255
+ RBASIC_SET_FULL_SHAPE_ID(obj, (
256
+ (shape_id & ~SHAPE_ID_FL_PRIVATE_MASK) |
257
+ (RBASIC_SHAPE_ID(obj) & SHAPE_ID_FL_PRIVATE_MASK)
258
+ ));
259
+ }
260
+
261
+ static inline shape_id_t
262
+ RSHAPE_FLAGS(shape_id_t shape_id)
263
+ {
264
+ return shape_id & SHAPE_ID_FLAGS_MASK;
265
+ }
266
+
267
+ static inline shape_id_t
268
+ RSHAPE_OFFSET(shape_id_t shape_id)
269
+ {
270
+ return shape_id & SHAPE_ID_OFFSET_MASK;
271
+ }
272
+
273
+ static inline rb_shape_t *
274
+ RSHAPE(shape_id_t shape_id)
275
+ {
276
+ shape_id_t offset = RSHAPE_OFFSET(shape_id);
277
+ RUBY_ASSERT(offset != INVALID_SHAPE_ID);
278
+ return &rb_shape_tree.shape_list[offset];
279
+ }
280
+
281
+ int32_t rb_shape_id_offset(void);
282
+
283
+ RUBY_FUNC_EXPORTED shape_id_t rb_obj_shape_id(VALUE obj);
284
+ bool rb_shape_get_iv_index(shape_id_t shape_id, ID id, attr_index_t *value);
285
+ 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);
286
+ bool rb_shape_find_ivar(shape_id_t shape_id, ID id, shape_id_t *ivar_shape);
287
+
288
+ typedef int rb_shape_foreach_transition_callback(shape_id_t shape_id, void *data);
289
+ bool rb_shape_foreach_field(shape_id_t shape_id, rb_shape_foreach_transition_callback func, void *data);
290
+
291
+ shape_id_t rb_shape_transition_add_ivar_no_warnings(shape_id_t shape_id, ID id, VALUE klass);
292
+
293
+ shape_id_t rb_shape_object_id(shape_id_t original_shape_id);
294
+ shape_id_t rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_id);
295
+ void rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALUE *src_buf, shape_id_t src_shape_id);
296
+
297
+ static inline bool
298
+ rb_shape_frozen_p(shape_id_t shape_id)
299
+ {
300
+ return shape_id & SHAPE_ID_FL_FROZEN;
301
+ }
302
+
303
+ static inline bool
304
+ rb_shape_complex_p(shape_id_t shape_id)
305
+ {
306
+ return shape_id & SHAPE_ID_FL_COMPLEX;
307
+ }
308
+
309
+ static inline bool
310
+ rb_obj_shape_complex_p(VALUE obj)
311
+ {
312
+ return !RB_SPECIAL_CONST_P(obj) && rb_shape_complex_p(RBASIC_SHAPE_ID(obj));
313
+ }
314
+
315
+ static inline bool
316
+ rb_shape_has_object_id(shape_id_t shape_id)
317
+ {
318
+ return shape_id & SHAPE_ID_FL_HAS_OBJECT_ID;
319
+ }
320
+
321
+ static inline bool
322
+ rb_shape_canonical_p(shape_id_t shape_id)
323
+ {
324
+ return !(shape_id & SHAPE_ID_FL_NON_CANONICAL_MASK);
325
+ }
326
+
327
+ static inline attr_index_t
328
+ rb_shape_embedded_capacity(shape_id_t shape_id)
329
+ {
330
+ return (attr_index_t)((shape_id & SHAPE_ID_CAPACITY_MASK) >> SHAPE_ID_CAPACITY_OFFSET);
331
+ }
332
+
333
+ static inline size_t
334
+ rb_shape_slot_size(shape_id_t shape_id)
335
+ {
336
+ return sizeof(struct RBasic) + (rb_shape_embedded_capacity(shape_id) * sizeof(VALUE));
337
+ }
338
+
339
+ static inline size_t
340
+ rb_obj_shape_slot_size(VALUE obj)
341
+ {
342
+ RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_fields));
343
+
344
+ shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
345
+ size_t slot_size = rb_shape_slot_size(shape_id);
346
+
347
+ if (rb_shape_embedded_capacity(shape_id) == SHAPE_ID_CAPACITY_MAX) {
348
+ size_t gc_slot_size = rb_gc_obj_slot_size(obj);
349
+ RUBY_ASSERT(gc_slot_size >= slot_size);
350
+ return gc_slot_size;
351
+ }
352
+
353
+ return slot_size;
354
+ }
355
+
356
+ static inline attr_index_t
357
+ rb_shape_capacity_for_slot_size(size_t slot_size)
358
+ {
359
+ size_t capacity = (slot_size - sizeof(struct RBasic)) / sizeof(VALUE);
360
+ if (capacity > SHAPE_ID_CAPACITY_MAX) {
361
+ capacity = SHAPE_ID_CAPACITY_MAX;
362
+ }
363
+ return (attr_index_t)capacity;
364
+ }
365
+
366
+ static inline shape_id_t
367
+ RSHAPE_PARENT_OFFSET(shape_id_t shape_id)
368
+ {
369
+ return RSHAPE(shape_id)->parent_offset;
370
+ }
371
+
372
+ static inline bool
373
+ RSHAPE_DIRECT_CHILD_P(shape_id_t parent_offset, shape_id_t child_id)
374
+ {
375
+ return RSHAPE_PARENT_OFFSET(child_id) == RSHAPE_OFFSET(parent_offset);
376
+ }
377
+
378
+ static inline enum shape_type
379
+ RSHAPE_TYPE(shape_id_t shape_id)
380
+ {
381
+ return RSHAPE(shape_id)->type;
382
+ }
383
+
384
+ static inline bool
385
+ RSHAPE_TYPE_P(shape_id_t shape_id, enum shape_type type)
386
+ {
387
+ return RSHAPE_TYPE(shape_id) == type;
388
+ }
389
+
390
+ static inline attr_index_t
391
+ RSHAPE_CAPACITY(shape_id_t shape_id)
392
+ {
393
+ attr_index_t embedded_capacity = rb_shape_embedded_capacity(shape_id);
394
+
395
+ if (embedded_capacity > RSHAPE(shape_id)->capacity) {
396
+ return embedded_capacity;
397
+ }
398
+ else {
399
+ return RSHAPE(shape_id)->capacity;
400
+ }
401
+ }
402
+
403
+ static inline attr_index_t
404
+ RSHAPE_LEN(shape_id_t shape_id)
405
+ {
406
+ return RSHAPE(shape_id)->next_field_index;
407
+ }
408
+
409
+ static inline attr_index_t
410
+ RSHAPE_INDEX(shape_id_t shape_id)
411
+ {
412
+ RUBY_ASSERT(RSHAPE_LEN(shape_id) > 0);
413
+ return RSHAPE_LEN(shape_id) - 1;
414
+ }
415
+
416
+ static inline ID
417
+ RSHAPE_EDGE_NAME(shape_id_t shape_id)
418
+ {
419
+ return RSHAPE(shape_id)->edge_name;
420
+ }
421
+
422
+ static inline VALUE *
423
+ rb_imemo_fields_ptr(VALUE fields_obj)
424
+ {
425
+ if (!fields_obj) {
426
+ return NULL;
427
+ }
428
+
429
+ RUBY_ASSERT(rb_obj_shape_embedded_p(fields_obj));
430
+ return IMEMO_OBJ_FIELDS(fields_obj)->as.embed.fields;
431
+ }
432
+
433
+ static inline uint32_t
434
+ RBASIC_FIELDS_COUNT(VALUE obj)
435
+ {
436
+ return RSHAPE(RBASIC_SHAPE_ID(obj))->next_field_index;
437
+ }
438
+
439
+ static inline bool
440
+ rb_obj_shape_has_id(VALUE obj)
441
+ {
442
+ return rb_shape_has_object_id(RBASIC_SHAPE_ID(obj));
443
+ }
444
+
445
+ static inline bool
446
+ rb_shape_has_ivars(shape_id_t shape_id)
447
+ {
448
+ return shape_id & SHAPE_ID_HAS_IVAR_MASK;
449
+ }
450
+
451
+ static inline bool
452
+ rb_obj_shape_has_ivars(VALUE obj)
453
+ {
454
+ return rb_shape_has_ivars(RBASIC_SHAPE_ID(obj));
455
+ }
456
+
457
+ static inline bool
458
+ rb_shape_has_fields(shape_id_t shape_id)
459
+ {
460
+ return shape_id & (SHAPE_ID_OFFSET_MASK | SHAPE_ID_FL_COMPLEX);
461
+ }
462
+
463
+ static inline bool
464
+ rb_obj_shape_has_fields(VALUE obj)
465
+ {
466
+ return rb_shape_has_fields(RBASIC_SHAPE_ID(obj));
467
+ }
468
+
469
+ static inline bool
470
+ rb_obj_gen_fields_p(VALUE obj)
471
+ {
472
+ switch (TYPE(obj)) {
473
+ case T_NONE:
474
+ case T_OBJECT:
475
+ case T_CLASS:
476
+ case T_MODULE:
477
+ case T_IMEMO:
478
+ return false;
479
+ default:
480
+ break;
481
+ }
482
+ return rb_obj_shape_has_fields(obj);
483
+ }
484
+
485
+ static inline shape_id_t
486
+ rb_shape_transition_layout(shape_id_t shape_id, shape_id_t layout)
487
+ {
488
+ return (shape_id & (~SHAPE_ID_LAYOUT_MASK)) | layout;
489
+ }
490
+
491
+ static inline shape_id_t
492
+ rb_shape_transition_robject(shape_id_t shape_id)
493
+ {
494
+ return rb_shape_transition_layout(shape_id, SHAPE_ID_LAYOUT_ROBJECT);
495
+ }
496
+
497
+ static inline shape_id_t
498
+ rb_shape_transition_extended(shape_id_t shape_id)
499
+ {
500
+ return rb_shape_transition_layout(shape_id, SHAPE_ID_LAYOUT_EXTENDED);
501
+ }
502
+
503
+ static inline shape_id_t
504
+ rb_shape_transition_frozen(shape_id_t shape_id)
505
+ {
506
+ return shape_id | SHAPE_ID_FL_FROZEN;
507
+ }
508
+
509
+ static inline shape_id_t
510
+ rb_shape_transition_complex(shape_id_t shape_id)
511
+ {
512
+ shape_id_t next_shape_id = rb_shape_layout(shape_id) | ROOT_COMPLEX_SHAPE_ID;
513
+
514
+ if (rb_shape_has_object_id(shape_id)) {
515
+ next_shape_id = rb_shape_layout(shape_id) | ROOT_COMPLEX_WITH_OBJ_ID;
516
+ }
517
+
518
+ next_shape_id |= shape_id & SHAPE_ID_CAPACITY_MASK;
519
+
520
+ RUBY_ASSERT(rb_shape_has_object_id(shape_id) == rb_shape_has_object_id(next_shape_id));
521
+
522
+ return next_shape_id;
523
+ }
524
+
525
+ static inline shape_id_t
526
+ rb_shape_transition_offset(shape_id_t shape_id, shape_id_t offset)
527
+ {
528
+ offset = RSHAPE_OFFSET(offset);
529
+ RUBY_ASSERT(RSHAPE_OFFSET(shape_id) == offset || RSHAPE_DIRECT_CHILD_P(shape_id, offset));
530
+ return RSHAPE_FLAGS(shape_id) | offset;
531
+ }
532
+
533
+ static inline shape_id_t
534
+ rb_shape_transition_capacity(shape_id_t shape_id, size_t capacity)
535
+ {
536
+ RUBY_ASSERT(capacity <= SHAPE_ID_CAPACITY_MAX);
537
+
538
+ shape_id_t capacity_flags = (shape_id_t)capacity << SHAPE_ID_CAPACITY_OFFSET;
539
+ return (shape_id & (~SHAPE_ID_CAPACITY_MASK)) | capacity_flags;
540
+ }
541
+
542
+ static inline shape_id_t
543
+ rb_shape_transition_slot_size(shape_id_t shape_id, size_t slot_size)
544
+ {
545
+ return rb_shape_transition_capacity(shape_id, rb_shape_capacity_for_slot_size(slot_size));
546
+ }
547
+
548
+ shape_id_t rb_shape_transition_object_id(shape_id_t shape_id);
549
+
550
+ static inline shape_id_t
551
+ rb_obj_shape_transition_frozen(VALUE obj)
552
+ {
553
+ RUBY_ASSERT(RB_OBJ_FROZEN(obj));
554
+ return rb_shape_transition_frozen(RBASIC_SHAPE_ID(obj));
555
+ }
556
+
557
+ static inline shape_id_t
558
+ rb_obj_shape_transition_complex(VALUE obj)
559
+ {
560
+ return rb_shape_transition_complex(RBASIC_SHAPE_ID(obj));
561
+ }
562
+
563
+ static inline shape_id_t
564
+ rb_obj_shape_transition_capacity(VALUE obj, size_t capacity)
565
+ {
566
+ return rb_shape_transition_capacity(RBASIC_SHAPE_ID(obj), capacity);
567
+ }
568
+
569
+ static inline shape_id_t
570
+ rb_obj_shape_transition_slot_size(VALUE obj, size_t slot_size)
571
+ {
572
+ return rb_shape_transition_slot_size(RBASIC_SHAPE_ID(obj), slot_size);
573
+ }
574
+
575
+ static inline shape_id_t
576
+ rb_obj_shape_transition_object_id(VALUE obj)
577
+ {
578
+ return rb_shape_transition_object_id(RBASIC_SHAPE_ID(obj));
579
+ }
580
+
581
+ shape_id_t rb_obj_shape_transition_remove_ivar(VALUE obj, ID id, shape_id_t *removed_shape_id);
582
+ shape_id_t rb_obj_shape_transition_add_ivar(VALUE obj, ID id);
583
+
584
+ // For ext/objspace
585
+ RUBY_SYMBOL_EXPORT_BEGIN
586
+ typedef void each_shape_callback(shape_id_t shape_id, void *data);
587
+ void rb_shape_each_shape_id(each_shape_callback callback, void *data);
588
+ size_t rb_shape_memsize(shape_id_t shape);
589
+ size_t rb_shape_edges_count(shape_id_t shape_id);
590
+ size_t rb_shape_depth(shape_id_t shape_id);
591
+ RUBY_SYMBOL_EXPORT_END
592
+
593
+ // Inline cache helpers
594
+
595
+ typedef struct {
596
+ attr_index_t index;
597
+ shape_id_t shape_offset;
598
+ } rb_getivar_cache;
599
+
600
+ union rb_getivar_cache {
601
+ uint64_t pack;
602
+ rb_getivar_cache unpack;
603
+ };
604
+ STATIC_ASSERT(rb_getivar_cache_size, sizeof(union rb_getivar_cache) <= sizeof(uint64_t));
605
+
606
+ #define IVAR_CACHE_INIT ((uint64_t)-1)
607
+ #define ATTR_INDEX_T_NUM_BITS (sizeof(attr_index_t) * CHAR_BIT)
608
+
609
+ static inline rb_getivar_cache
610
+ rb_getivar_cache_unpack(uint64_t packed)
611
+ {
612
+ union rb_getivar_cache cache = {
613
+ .pack = packed,
614
+ };
615
+
616
+ // Because caches may initialized with all bits set (IVAR_CACHE_INIT), and `shape_offset` if 32bits,
617
+ // we need to remove any potential extra bits set in the "padding".
618
+ cache.unpack.shape_offset &= SHAPE_ID_OFFSET_MASK;
619
+ return cache.unpack;
620
+ }
621
+
622
+ static inline uint64_t
623
+ rb_getivar_cache_pack(shape_id_t shape_offset, attr_index_t index)
624
+ {
625
+ RUBY_ASSERT(shape_offset == RSHAPE_OFFSET(shape_offset));
626
+ RUBY_ASSERT(shape_offset != INVALID_SHAPE_ID);
627
+
628
+ union rb_getivar_cache cache = {
629
+ .unpack = {
630
+ .shape_offset = shape_offset,
631
+ .index = index,
632
+ },
633
+ };
634
+ return cache.pack;
635
+ }
636
+
637
+ typedef struct {
638
+ attr_index_t index;
639
+ shape_id_t source_shape_offset;
640
+ shape_id_t dest_shape_offset;
641
+ } rb_setivar_cache;
642
+
643
+ static inline rb_setivar_cache
644
+ rb_setivar_cache_unpack(uint64_t packed)
645
+ {
646
+ rb_setivar_cache cache = {
647
+ .index = (attr_index_t)packed,
648
+ .source_shape_offset = RSHAPE_OFFSET((shape_id_t)(packed >> ATTR_INDEX_T_NUM_BITS)),
649
+ .dest_shape_offset = RSHAPE_OFFSET((shape_id_t)(packed >> (ATTR_INDEX_T_NUM_BITS + SHAPE_ID_OFFSET_NUM_BITS))),
650
+ };
651
+ return cache;
652
+ }
653
+
654
+ static inline uint64_t
655
+ rb_setivar_cache_pack(shape_id_t shape_offset, shape_id_t dest_shape_offset, attr_index_t index)
656
+ {
657
+ RUBY_ASSERT(shape_offset == RSHAPE_OFFSET(shape_offset));
658
+ RUBY_ASSERT(dest_shape_offset == RSHAPE_OFFSET(dest_shape_offset));
659
+ RUBY_ASSERT(shape_offset == dest_shape_offset || RSHAPE_DIRECT_CHILD_P(shape_offset, dest_shape_offset));
660
+
661
+ uint64_t packed_cache = (uint64_t)dest_shape_offset << (ATTR_INDEX_T_NUM_BITS + SHAPE_ID_OFFSET_NUM_BITS);
662
+ packed_cache |= (uint64_t)shape_offset << ATTR_INDEX_T_NUM_BITS;
663
+ packed_cache |= (uint64_t)index;
664
+ return packed_cache;
665
+ }
666
+
667
+ ALWAYS_INLINE(static shape_id_t rb_setivar_cache_revalidate(shape_id_t shape_id, shape_id_t fields_shape_id, rb_setivar_cache cache));
668
+ static shape_id_t
669
+ rb_setivar_cache_revalidate(shape_id_t shape_id, shape_id_t fields_shape_id, rb_setivar_cache cache)
670
+ {
671
+ RUBY_ASSERT(shape_id != INVALID_SHAPE_ID);
672
+ RUBY_ASSERT(cache.dest_shape_offset == INVALID_SHAPE_ID || cache.dest_shape_offset == RSHAPE_OFFSET(cache.dest_shape_offset));
673
+
674
+ shape_id_t normalized_shape_id = shape_id & SHAPE_ID_WRITE_MASK;
675
+ if (UNLIKELY(normalized_shape_id != cache.source_shape_offset)) {
676
+ return INVALID_SHAPE_ID;
677
+ }
678
+
679
+ if (UNLIKELY(cache.index >= RSHAPE_CAPACITY(fields_shape_id))) {
680
+ // That's still a hit in term of layout, but the object will need to be resized,
681
+ // so unfortunately we'll have to go through the slow path regardless...
682
+ return INVALID_SHAPE_ID;
683
+ }
684
+
685
+ // Cache hit case
686
+ RUBY_ASSERT(cache.source_shape_offset == cache.dest_shape_offset || RSHAPE_DIRECT_CHILD_P(shape_id, cache.dest_shape_offset));
687
+ RUBY_ASSERT(cache.index < RSHAPE_CAPACITY(shape_id));
688
+ RUBY_ASSERT(!rb_shape_frozen_p(shape_id));
689
+ RUBY_ASSERT(!rb_shape_complex_p(shape_id));
690
+
691
+ // We use the cached offset, but combined with the current shape flags.
692
+ return rb_shape_transition_offset(shape_id, cache.dest_shape_offset);
693
+ }
694
+
695
+ static inline st_table *
696
+ rb_imemo_fields_complex_tbl(VALUE fields_obj)
697
+ {
698
+ if (!fields_obj) {
699
+ return NULL;
700
+ }
701
+
702
+ RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields));
703
+
704
+ // Some codepaths unconditionally access the fields_ptr, and assume it can be used as st_table if the
705
+ // shape is complex.
706
+ RUBY_ASSERT((st_table *)rb_imemo_fields_ptr(fields_obj) == &IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table);
707
+
708
+ return &IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table;
709
+ }
710
+
711
+ static inline VALUE
712
+ ROBJECT_FIELDS_OBJ(VALUE obj)
713
+ {
714
+ RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
715
+
716
+ return rb_obj_shape_embedded_p(obj) ? obj : ROBJECT(obj)->as.extended;
717
+ }
718
+
719
+ static inline VALUE *
720
+ ROBJECT_EMBEDDED_FIELDS(VALUE obj)
721
+ {
722
+ return ROBJECT(obj)->as.ary;
723
+ }
724
+
725
+ static inline VALUE *
726
+ ROBJECT_FIELDS(VALUE obj)
727
+ {
728
+ RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
729
+
730
+ return ROBJECT_EMBEDDED_FIELDS(ROBJECT_FIELDS_OBJ(obj));
731
+ }
732
+
733
+ #endif