/home/travis/build/MoarVM/MoarVM/src/6model/reprs/P6opaque.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | #ifndef MAX |
4 | | #define MAX(x,y) ((x)>(y)?(x):(y)) |
5 | | #endif |
6 | | |
7 | 142k | #define P6OMAX(x, y) ((y) > (x) ? (y) : (x)) |
8 | | #define REFVAR_VM_HASH_STR_VAR 10 |
9 | 1.36k | #define MVM_P6OPAQUE_NO_UNBOX_SLOT 0xFFFF |
10 | | |
11 | | /* This representation's function pointer table. */ |
12 | | static const MVMREPROps P6opaque_this_repr; |
13 | | |
14 | | /* Helpers for reading/writing values. */ |
15 | 7.31M | MVM_STATIC_INLINE MVMObject * get_obj_at_offset(void *data, MVMint64 offset) { |
16 | 7.31M | void *location = (char *)data + offset; |
17 | 7.31M | return *((MVMObject **)location); |
18 | 7.31M | } |
19 | 5.52M | MVM_STATIC_INLINE void set_obj_at_offset(MVMThreadContext *tc, MVMObject *root, void *data, MVMint64 offset, MVMObject *value) { |
20 | 5.52M | void *location = (char *)data + offset; |
21 | 5.52M | MVM_ASSIGN_REF(tc, &(root->header), *((MVMObject **)location), value); |
22 | 5.52M | } |
23 | | |
24 | | /* Helper for finding a slot number. */ |
25 | 5.95M | static MVMint64 try_get_slot(MVMThreadContext *tc, MVMP6opaqueREPRData *repr_data, MVMObject *class_key, MVMString *name) { |
26 | 5.95M | if (repr_data->name_to_index_mapping) { |
27 | 5.95M | MVMP6opaqueNameMap *cur_map_entry = repr_data->name_to_index_mapping; |
28 | 17.8M | while (cur_map_entry->class_key != NULL) { |
29 | 17.7M | if (cur_map_entry->class_key == class_key) { |
30 | 5.95M | MVMint16 i; |
31 | 30.1M | for (i = 0; i < cur_map_entry->num_attrs; i++) { |
32 | 30.1M | if (MVM_string_equal(tc, cur_map_entry->names[i], name)) { |
33 | 5.94M | return cur_map_entry->slots[i]; |
34 | 5.94M | } |
35 | 30.1M | } |
36 | 5.95M | } |
37 | 11.8M | cur_map_entry++; |
38 | 11.8M | } |
39 | 5.95M | } |
40 | 5.56k | return -1; |
41 | 5.95M | } |
42 | | |
43 | | /* Creates a new type object of this representation, and associates it with |
44 | | * the given HOW. */ |
45 | 1.50k | static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) { |
46 | 1.50k | MVMSTable *st = MVM_gc_allocate_stable(tc, &P6opaque_this_repr, HOW); |
47 | 1.50k | |
48 | 1.50k | MVMROOT(tc, st, { |
49 | 1.50k | MVMObject *obj = MVM_gc_allocate_type_object(tc, st); |
50 | 1.50k | MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj); |
51 | 1.50k | st->size = 0; /* Is updated later. */ |
52 | 1.50k | }); |
53 | 1.50k | |
54 | 1.50k | return st->WHAT; |
55 | 1.50k | } |
56 | | |
57 | | /* Creates a new instance based on the type object. */ |
58 | 770k | static MVMObject * allocate(MVMThreadContext *tc, MVMSTable *st) { |
59 | 770k | if (st->size) |
60 | 770k | return MVM_gc_allocate_object(tc, st); |
61 | 770k | else |
62 | 0 | MVM_exception_throw_adhoc(tc, "P6opaque: must compose %s before allocating", MVM_6model_get_stable_debug_name(tc, st)); |
63 | 770k | } |
64 | | |
65 | | /* Initializes a new instance. */ |
66 | 552k | static void initialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) { |
67 | 552k | MVMP6opaqueREPRData * repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
68 | 552k | data = MVM_p6opaque_real_data(tc, data); |
69 | 552k | if (repr_data) { |
70 | 552k | MVMint64 i; |
71 | 552k | for (i = 0; repr_data->initialize_slots[i] >= 0; i++) { |
72 | 9 | MVMint64 offset = repr_data->attribute_offsets[repr_data->initialize_slots[i]]; |
73 | 9 | MVMSTable *st = repr_data->flattened_stables[repr_data->initialize_slots[i]]; |
74 | 9 | st->REPR->initialize(tc, st, root, (char *)data + offset); |
75 | 9 | } |
76 | 552k | } |
77 | 0 | else { |
78 | 0 | MVM_exception_throw_adhoc(tc, "P6opaque: must compose %s before using initialize", MVM_6model_get_stable_debug_name(tc, st)); |
79 | 0 | } |
80 | 552k | } |
81 | | |
82 | | /* Copies the body of one object to another. */ |
83 | 856 | static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) { |
84 | 856 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
85 | 856 | MVMuint16 i; |
86 | 856 | src = MVM_p6opaque_real_data(tc, src); |
87 | 856 | |
88 | 856 | /* Flattened in REPRs need a chance to copy 'emselves. */ |
89 | 6.76k | for (i = 0; i < repr_data->num_attributes; i++) { |
90 | 5.90k | MVMSTable *st_copy = repr_data->flattened_stables[i]; |
91 | 5.90k | MVMuint16 offset = repr_data->attribute_offsets[i]; |
92 | 5.90k | if (st_copy) { |
93 | 840 | st_copy->REPR->copy_to(tc, st_copy, (char*)src + offset, dest_root, (char*)dest + offset); |
94 | 840 | } |
95 | 5.06k | else { |
96 | 5.06k | MVMObject *ref = get_obj_at_offset(src, offset); |
97 | 5.06k | if (ref) |
98 | 1.70k | set_obj_at_offset(tc, dest_root, dest, offset, ref); |
99 | 5.06k | } |
100 | 5.90k | } |
101 | 856 | } |
102 | | |
103 | | /* Called by the VM to mark any GCable items. */ |
104 | 1.09M | static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) { |
105 | 1.09M | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
106 | 1.09M | MVMint64 i; |
107 | 1.09M | data = MVM_p6opaque_real_data(tc, data); |
108 | 1.09M | |
109 | 1.09M | /* Mark objects. */ |
110 | 9.59M | for (i = 0; i < repr_data->gc_obj_mark_offsets_count; i++) { |
111 | 8.50M | MVMuint16 offset = repr_data->gc_obj_mark_offsets[i]; |
112 | 8.50M | MVM_gc_worklist_add(tc, worklist, (char *)data + offset); |
113 | 8.50M | } |
114 | 1.09M | |
115 | 1.09M | /* Mark any nested reprs that need it. */ |
116 | 2.30M | for (i = 0; repr_data->gc_mark_slots[i] >= 0; i++) { |
117 | 1.21M | MVMuint16 offset = repr_data->attribute_offsets[repr_data->gc_mark_slots[i]]; |
118 | 1.21M | MVMSTable *st = repr_data->flattened_stables[repr_data->gc_mark_slots[i]]; |
119 | 1.21M | st->REPR->gc_mark(tc, st, (char *)data + offset, worklist); |
120 | 1.21M | } |
121 | 1.09M | } |
122 | | |
123 | | /* Called by the VM in order to free memory associated with this object. */ |
124 | 2.84M | static void gc_free(MVMThreadContext *tc, MVMObject *obj) { |
125 | 2.84M | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)STABLE(obj)->REPR_data; |
126 | 2.84M | MVMint64 i; |
127 | 2.84M | void *data = MVM_p6opaque_real_data(tc, OBJECT_BODY(obj)); |
128 | 2.84M | |
129 | 2.84M | /* Cleanup any nested reprs that need it. */ |
130 | 2.84M | for (i = 0; repr_data->gc_cleanup_slots[i] >= 0; i++) { |
131 | 0 | MVMuint16 offset = repr_data->attribute_offsets[repr_data->gc_cleanup_slots[i]]; |
132 | 0 | MVMSTable *st = repr_data->flattened_stables[repr_data->gc_cleanup_slots[i]]; |
133 | 0 | st->REPR->gc_cleanup(tc, st, (char *)data + offset); |
134 | 0 | } |
135 | 2.84M | |
136 | 2.84M | /* If we replaced the object body, free the replacement. */ |
137 | 2.84M | MVM_free(((MVMP6opaque *)obj)->body.replaced); |
138 | 2.84M | } |
139 | | |
140 | | /* Marks the representation data in an STable.*/ |
141 | 11.7k | static void gc_mark_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMGCWorklist *worklist) { |
142 | 11.7k | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
143 | 11.7k | |
144 | 11.7k | /* May not be composed yet. */ |
145 | 11.7k | if (repr_data == NULL) |
146 | 3 | return; |
147 | 11.7k | |
148 | 11.6k | if (repr_data->flattened_stables) { |
149 | 10.9k | int i; |
150 | 52.1k | for (i = 0; i < repr_data->num_attributes; i++) |
151 | 41.1k | if (repr_data->flattened_stables[i]) |
152 | 9.70k | MVM_gc_worklist_add(tc, worklist, &repr_data->flattened_stables[i]); |
153 | 10.9k | } |
154 | 11.6k | |
155 | 11.6k | if (repr_data->auto_viv_values) { |
156 | 6.10k | int i; |
157 | 47.2k | for (i = 0; i < repr_data->num_attributes; i++) |
158 | 41.1k | if (repr_data->auto_viv_values[i]) |
159 | 25.1k | MVM_gc_worklist_add(tc, worklist, &repr_data->auto_viv_values[i]); |
160 | 6.10k | } |
161 | 11.6k | |
162 | 11.6k | if (repr_data->name_to_index_mapping) { |
163 | 11.6k | MVMP6opaqueNameMap *cur_map_entry = repr_data->name_to_index_mapping; |
164 | 35.2k | while (cur_map_entry->class_key != NULL) { |
165 | 23.5k | MVMint16 i; |
166 | 64.7k | for (i = 0; i < cur_map_entry->num_attrs; i++) { |
167 | 41.1k | MVM_gc_worklist_add(tc, worklist, &cur_map_entry->names[i]); |
168 | 41.1k | } |
169 | 23.5k | MVM_gc_worklist_add(tc, worklist, &cur_map_entry->class_key); |
170 | 23.5k | cur_map_entry++; |
171 | 23.5k | } |
172 | 11.6k | } |
173 | 11.6k | } |
174 | | |
175 | | /* Marks the representation data in an STable.*/ |
176 | 1 | static void gc_free_repr_data(MVMThreadContext *tc, MVMSTable *st) { |
177 | 1 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
178 | 1 | |
179 | 1 | /* May not have survived to composition. */ |
180 | 1 | if (repr_data == NULL) |
181 | 0 | return; |
182 | 1 | |
183 | 1 | if (repr_data->name_to_index_mapping) { |
184 | 1 | MVMP6opaqueNameMap *cur_map_entry = repr_data->name_to_index_mapping; |
185 | 3 | while (cur_map_entry->class_key != NULL) { |
186 | 2 | MVM_free(cur_map_entry->names); |
187 | 2 | MVM_free(cur_map_entry->slots); |
188 | 2 | cur_map_entry++; |
189 | 2 | } |
190 | 1 | MVM_free(repr_data->name_to_index_mapping); |
191 | 1 | } |
192 | 1 | |
193 | 1 | MVM_free(repr_data->attribute_offsets); |
194 | 1 | MVM_free(repr_data->flattened_stables); |
195 | 1 | MVM_free(repr_data->auto_viv_values); |
196 | 1 | MVM_free(repr_data->unbox_slots); |
197 | 1 | MVM_free(repr_data->gc_obj_mark_offsets); |
198 | 1 | MVM_free(repr_data->initialize_slots); |
199 | 1 | MVM_free(repr_data->gc_mark_slots); |
200 | 1 | MVM_free(repr_data->gc_cleanup_slots); |
201 | 1 | |
202 | 1 | MVM_free(st->REPR_data); |
203 | 1 | } |
204 | | |
205 | | /* Helper for complaining about attribute access errors. */ |
206 | | MVM_NO_RETURN static void no_such_attribute(MVMThreadContext *tc, const char *action, MVMObject *class_handle, MVMString *name, MVMSTable *target_type) MVM_NO_RETURN_ATTRIBUTE; |
207 | 4 | MVM_NO_RETURN static void no_such_attribute(MVMThreadContext *tc, const char *action, MVMObject *class_handle, MVMString *name, MVMSTable *target_type) { |
208 | 4 | char *c_name = MVM_string_utf8_encode_C_string(tc, name); |
209 | 4 | char *waste[] = { c_name, NULL }; |
210 | 4 | MVM_exception_throw_adhoc_free(tc, waste, "P6opaque: no such attribute '%s' on type %s in a %s when trying to %s", c_name, MVM_6model_get_debug_name(tc, class_handle), MVM_6model_get_stable_debug_name(tc, target_type), action); |
211 | 4 | } |
212 | | |
213 | | MVM_NO_RETURN static void invalid_access_kind(MVMThreadContext *tc, const char *action, MVMObject *class_handle, MVMString *name, const char *kind_desc) MVM_NO_RETURN_ATTRIBUTE; |
214 | 0 | MVM_NO_RETURN static void invalid_access_kind(MVMThreadContext *tc, const char *action, MVMObject *class_handle, MVMString *name, const char *kind_desc) { |
215 | 0 | char *c_name = MVM_string_utf8_encode_C_string(tc, name); |
216 | 0 | char *waste[] = { c_name, NULL }; |
217 | 0 | MVM_exception_throw_adhoc_free(tc, waste, "P6opaque: invalid %s attribute '%s' in type %s for kind %s", action, c_name, MVM_6model_get_debug_name(tc, class_handle), kind_desc); |
218 | 0 | } |
219 | | |
220 | | /* Gets the current value for an attribute. */ |
221 | | static void get_attribute(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, |
222 | | void *data, MVMObject *class_handle, MVMString *name, MVMint64 hint, |
223 | 11.3M | MVMRegister *result_reg, MVMuint16 kind) { |
224 | 11.3M | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
225 | 11.3M | MVMint64 slot; |
226 | 11.3M | data = MVM_p6opaque_real_data(tc, data); |
227 | 11.3M | |
228 | 11.3M | if (!repr_data) |
229 | 0 | MVM_exception_throw_adhoc(tc, "P6opaque: must compose %s before using get_attribute", MVM_6model_get_stable_debug_name(tc, st)); |
230 | 11.3M | |
231 | 11.3M | /* Try the slot allocation first. */ |
232 | 8.43M | slot = hint >= 0 && hint < repr_data->num_attributes && !(repr_data->mi) ? hint : |
233 | 2.87M | try_get_slot(tc, repr_data, class_handle, name); |
234 | 11.3M | if (slot >= 0) { |
235 | 11.3M | MVMSTable *attr_st = repr_data->flattened_stables[slot]; |
236 | 11.3M | switch (kind) { |
237 | 6.26M | case MVM_reg_obj: |
238 | 6.26M | { |
239 | 6.26M | if (!attr_st) { |
240 | 6.21M | MVMObject *result = get_obj_at_offset(data, repr_data->attribute_offsets[slot]); |
241 | 6.21M | if (result) { |
242 | 5.89M | result_reg->o = result; |
243 | 5.89M | } |
244 | 329k | else { |
245 | 329k | /* Maybe we know how to auto-viv it to a container. */ |
246 | 329k | if (repr_data->auto_viv_values) { |
247 | 329k | MVMObject *value = repr_data->auto_viv_values[slot]; |
248 | 329k | if (value != NULL) { |
249 | 321k | if (IS_CONCRETE(value)) { |
250 | 2 | MVMROOT2(tc, value, root, { |
251 | 2 | MVMObject *cloned = REPR(value)->allocate(tc, STABLE(value)); |
252 | 2 | /* Ordering here matters. We write the object into the |
253 | 2 | * register before calling copy_to. This is because |
254 | 2 | * if copy_to allocates, obj may have moved after |
255 | 2 | * we called it. This saves us having to put things on |
256 | 2 | * the temporary stack. The GC will know to update it |
257 | 2 | * in the register if it moved. */ |
258 | 2 | result_reg->o = cloned; |
259 | 2 | REPR(value)->copy_to(tc, STABLE(value), OBJECT_BODY(value), |
260 | 2 | cloned, OBJECT_BODY(cloned)); |
261 | 2 | set_obj_at_offset(tc, root, MVM_p6opaque_real_data(tc, OBJECT_BODY(root)), |
262 | 2 | repr_data->attribute_offsets[slot], result_reg->o); |
263 | 2 | }); |
264 | 2 | } |
265 | 321k | else { |
266 | 321k | set_obj_at_offset(tc, root, data, repr_data->attribute_offsets[slot], value); |
267 | 321k | result_reg->o = value; |
268 | 321k | } |
269 | 321k | } |
270 | 8.05k | else { |
271 | 8.05k | result_reg->o = tc->instance->VMNull; |
272 | 8.05k | } |
273 | 329k | } |
274 | 1 | else { |
275 | 1 | result_reg->o = tc->instance->VMNull; |
276 | 1 | } |
277 | 329k | } |
278 | 6.21M | } |
279 | 48.1k | else { |
280 | 48.1k | MVMROOT2(tc, root, attr_st, { |
281 | 48.1k | /* Need to produce a boxed version of this attribute. */ |
282 | 48.1k | MVMObject *cloned = attr_st->REPR->allocate(tc, attr_st); |
283 | 48.1k | |
284 | 48.1k | /* Ordering here matters too. see comments above */ |
285 | 48.1k | result_reg->o = cloned; |
286 | 48.1k | attr_st->REPR->copy_to(tc, attr_st, |
287 | 48.1k | (char *)MVM_p6opaque_real_data(tc, OBJECT_BODY(root)) + repr_data->attribute_offsets[slot], |
288 | 48.1k | cloned, OBJECT_BODY(cloned)); |
289 | 48.1k | }); |
290 | 48.1k | } |
291 | 6.26M | break; |
292 | 6.26M | } |
293 | 3.45M | case MVM_reg_int64: { |
294 | 3.45M | if (attr_st) |
295 | 3.45M | result_reg->i64 = attr_st->REPR->box_funcs.get_int(tc, attr_st, root, |
296 | 3.45M | (char *)data + repr_data->attribute_offsets[slot]); |
297 | 3.45M | else |
298 | 0 | invalid_access_kind(tc, "native access", class_handle, name, "int64"); |
299 | 3.45M | break; |
300 | 6.26M | } |
301 | 511 | case MVM_reg_num64: { |
302 | 511 | if (attr_st) |
303 | 511 | result_reg->n64 = attr_st->REPR->box_funcs.get_num(tc, attr_st, root, |
304 | 511 | (char *)data + repr_data->attribute_offsets[slot]); |
305 | 511 | else |
306 | 0 | invalid_access_kind(tc, "native access", class_handle, name, "num64"); |
307 | 511 | break; |
308 | 6.26M | } |
309 | 1.57M | case MVM_reg_str: { |
310 | 1.57M | if (attr_st) |
311 | 1.57M | result_reg->s = attr_st->REPR->box_funcs.get_str(tc, attr_st, root, |
312 | 1.57M | (char *)data + repr_data->attribute_offsets[slot]); |
313 | 1.57M | else |
314 | 0 | invalid_access_kind(tc, "native access", class_handle, name, "str"); |
315 | 1.57M | break; |
316 | 6.26M | } |
317 | 0 | default: { |
318 | 0 | MVM_exception_throw_adhoc(tc, "P6opaque: invalid kind in attribute lookup in %s", MVM_6model_get_stable_debug_name(tc, st)); |
319 | 0 | } |
320 | 11.3M | } |
321 | 11.3M | } |
322 | 18.4E | else { |
323 | 18.4E | /* Otherwise, complain that the attribute doesn't exist. */ |
324 | 18.4E | no_such_attribute(tc, "get a value", class_handle, name, st); |
325 | 18.4E | } |
326 | 11.3M | } |
327 | | |
328 | | /* Binds the given value to the specified attribute. */ |
329 | | static void bind_attribute(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, |
330 | | void *data, MVMObject *class_handle, MVMString *name, MVMint64 hint, |
331 | 6.71M | MVMRegister value_reg, MVMuint16 kind) { |
332 | 6.71M | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
333 | 6.71M | MVMint64 slot; |
334 | 6.71M | data = MVM_p6opaque_real_data(tc, data); |
335 | 6.71M | |
336 | 6.71M | if (!repr_data) |
337 | 0 | MVM_exception_throw_adhoc(tc, "P6opaque: must compose %s before using bind_attribute_boxed", MVM_6model_get_stable_debug_name(tc, st)); |
338 | 6.71M | |
339 | 6.71M | /* Try the slot allocation first. */ |
340 | 3.67M | slot = hint >= 0 && hint < repr_data->num_attributes && !(repr_data->mi) ? hint : |
341 | 3.03M | try_get_slot(tc, repr_data, class_handle, name); |
342 | 6.71M | if (slot >= 0) { |
343 | 6.71M | MVMSTable *attr_st = repr_data->flattened_stables[slot]; |
344 | 6.71M | switch (kind) { |
345 | 3.82M | case MVM_reg_obj: { |
346 | 3.82M | MVMObject *value = value_reg.o; |
347 | 3.82M | if (attr_st) { |
348 | 0 | MVMSTable *value_st = STABLE(value); |
349 | 0 | if (attr_st == value_st) |
350 | 0 | value_st->REPR->copy_to(tc, attr_st, OBJECT_BODY(value), root, |
351 | 0 | (char *)data + repr_data->attribute_offsets[slot]); |
352 | 0 | else |
353 | 0 | MVM_exception_throw_adhoc(tc, |
354 | 0 | "P6opaque: representation mismatch when storing value (of type %s) to attribute (of type %s)", |
355 | 0 | MVM_6model_get_stable_debug_name(tc, value_st), MVM_6model_get_stable_debug_name(tc, attr_st)); |
356 | 0 | } |
357 | 3.82M | else { |
358 | 3.82M | set_obj_at_offset(tc, root, data, repr_data->attribute_offsets[slot], value); |
359 | 3.82M | } |
360 | 3.82M | break; |
361 | 3.82M | } |
362 | 2.57M | case MVM_reg_int64: { |
363 | 2.57M | if (attr_st) |
364 | 2.57M | attr_st->REPR->box_funcs.set_int(tc, attr_st, root, |
365 | 2.57M | (char *)data + repr_data->attribute_offsets[slot], |
366 | 2.57M | value_reg.i64); |
367 | 2.57M | else |
368 | 0 | invalid_access_kind(tc, "native bind to", class_handle, name, "int64"); |
369 | 2.57M | break; |
370 | 3.82M | } |
371 | 1.05k | case MVM_reg_num64: { |
372 | 1.05k | if (attr_st) |
373 | 1.05k | attr_st->REPR->box_funcs.set_num(tc, attr_st, root, |
374 | 1.05k | (char *)data + repr_data->attribute_offsets[slot], |
375 | 1.05k | value_reg.n64); |
376 | 1.05k | else |
377 | 0 | invalid_access_kind(tc, "native bind to", class_handle, name, "num64"); |
378 | 1.05k | break; |
379 | 3.82M | } |
380 | 313k | case MVM_reg_str: { |
381 | 313k | if (attr_st) |
382 | 313k | attr_st->REPR->box_funcs.set_str(tc, attr_st, root, |
383 | 313k | (char *)data + repr_data->attribute_offsets[slot], |
384 | 313k | value_reg.s); |
385 | 313k | else |
386 | 0 | invalid_access_kind(tc, "native bind to", class_handle, name, "str"); |
387 | 313k | break; |
388 | 3.82M | } |
389 | 0 | default: { |
390 | 0 | MVM_exception_throw_adhoc(tc, "P6opaque: invalid kind in attribute bind in %s", MVM_6model_get_stable_debug_name(tc, st)); |
391 | 0 | } |
392 | 6.71M | } |
393 | 6.71M | } |
394 | 2 | else { |
395 | 2 | /* Otherwise, complain that the attribute doesn't exist. */ |
396 | 2 | no_such_attribute(tc, "bind a value", class_handle, name, st); |
397 | 2 | } |
398 | 6.71M | } |
399 | | |
400 | | /* Checks if an attribute has been initialized. */ |
401 | 9 | static MVMint64 is_attribute_initialized(MVMThreadContext *tc, MVMSTable *st, void *data, MVMObject *class_handle, MVMString *name, MVMint64 hint) { |
402 | 9 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
403 | 9 | MVMint64 slot; |
404 | 9 | |
405 | 9 | if (!repr_data) |
406 | 0 | MVM_exception_throw_adhoc(tc, "P6opaque: must compose %s before using bind_attribute_boxed", MVM_6model_get_stable_debug_name(tc, st)); |
407 | 9 | |
408 | 9 | data = MVM_p6opaque_real_data(tc, data); |
409 | 9 | /* This can stay commented out until we actually pass something other than NO_HINT |
410 | 9 | slot = hint >= 0 && hint < repr_data->num_attributes && !(repr_data->mi) ? hint : |
411 | 9 | try_get_slot(tc, repr_data, class_handle, name); |
412 | 9 | */ |
413 | 9 | slot = try_get_slot(tc, repr_data, class_handle, name); |
414 | 9 | if (slot >= 0) |
415 | 9 | return NULL != get_obj_at_offset(data, repr_data->attribute_offsets[slot]); |
416 | 9 | else |
417 | 0 | no_such_attribute(tc, "check if it's initialized", class_handle, name, st); |
418 | 0 | return 0; |
419 | 9 | } |
420 | | |
421 | | /* Gets the hint for the given attribute ID. */ |
422 | 10.2k | static MVMint64 hint_for(MVMThreadContext *tc, MVMSTable *st, MVMObject *class_key, MVMString *name) { |
423 | 10.2k | MVMint64 slot; |
424 | 10.2k | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
425 | 10.2k | if (!repr_data) |
426 | 0 | return MVM_NO_HINT; |
427 | 10.2k | slot = try_get_slot(tc, repr_data, class_key, name); |
428 | 5.60k | return slot >= 0 ? slot : MVM_NO_HINT; |
429 | 10.2k | } |
430 | | |
431 | | /* Gets an architecture atomic sized native integer attribute as an atomic |
432 | | * reference. */ |
433 | | static AO_t * attribute_as_atomic(MVMThreadContext *tc, MVMSTable *st, void *data, |
434 | | MVMObject *class_handle, MVMString *name, |
435 | 0 | MVMuint16 kind) { |
436 | 0 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
437 | 0 | MVMint64 slot; |
438 | 0 | data = MVM_p6opaque_real_data(tc, data); |
439 | 0 | if (!repr_data) |
440 | 0 | MVM_exception_throw_adhoc(tc, |
441 | 0 | "P6opaque: must compose %s before using get_attribute", MVM_6model_get_stable_debug_name(tc, st)); |
442 | 0 | slot = try_get_slot(tc, repr_data, class_handle, name); |
443 | 0 | if (slot >= 0) { |
444 | 0 | if (kind == MVM_reg_int64) { |
445 | 0 | MVMSTable *attr_st = repr_data->flattened_stables[slot]; |
446 | 0 | if (attr_st) { |
447 | 0 | const MVMStorageSpec *ss = attr_st->REPR->get_storage_spec(tc, attr_st); |
448 | 0 | if (ss->inlineable && ss->boxed_primitive == MVM_STORAGE_SPEC_BP_INT && |
449 | 0 | ss->bits / 8 == sizeof(AO_t)) |
450 | 0 | return (AO_t *)((char *)data + repr_data->attribute_offsets[slot]); |
451 | 0 | } |
452 | 0 | MVM_exception_throw_adhoc(tc, |
453 | 0 | "Can only do an atomic integer operation on an atomicint attribute"); |
454 | 0 | } |
455 | 0 | else if (kind == MVM_reg_obj) { |
456 | 0 | return (AO_t *)((char *)data + repr_data->attribute_offsets[slot]); |
457 | 0 | } |
458 | 0 | else { |
459 | 0 | MVM_exception_throw_adhoc(tc, |
460 | 0 | "Can only perform atomic operations on object or atomicint attributes"); |
461 | 0 | } |
462 | 0 | } |
463 | 0 | else { |
464 | 0 | no_such_attribute(tc, "get atomic reference to", class_handle, name, st); |
465 | 0 | } |
466 | 0 | } |
467 | | |
468 | | /* Used with boxing. Sets an integer value, for representations that can hold |
469 | | * one. */ |
470 | 45 | static void set_int(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 value) { |
471 | 45 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
472 | 45 | data = MVM_p6opaque_real_data(tc, data); |
473 | 45 | if (repr_data->unbox_int_slot >= 0) { |
474 | 45 | MVMSTable *st = repr_data->flattened_stables[repr_data->unbox_int_slot]; |
475 | 45 | st->REPR->box_funcs.set_int(tc, st, root, (char *)data + repr_data->attribute_offsets[repr_data->unbox_int_slot], value); |
476 | 45 | } |
477 | 0 | else { |
478 | 0 | MVM_exception_throw_adhoc(tc, |
479 | 0 | "This type cannot box a native integer: P6opaque, %s", MVM_6model_get_stable_debug_name(tc, st)); |
480 | 0 | } |
481 | 45 | } |
482 | | |
483 | | /* Used with boxing. Gets an integer value, for representations that can |
484 | | * hold one. */ |
485 | 11 | static MVMint64 get_int(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) { |
486 | 11 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
487 | 11 | data = MVM_p6opaque_real_data(tc, data); |
488 | 11 | if (repr_data->unbox_int_slot >= 0) { |
489 | 11 | MVMSTable *st = repr_data->flattened_stables[repr_data->unbox_int_slot]; |
490 | 11 | return st->REPR->box_funcs.get_int(tc, st, root, (char *)data + repr_data->attribute_offsets[repr_data->unbox_int_slot]); |
491 | 11 | } |
492 | 0 | else { |
493 | 0 | MVM_exception_throw_adhoc(tc, |
494 | 0 | "This type cannot unbox to a native integer: P6opaque, %s", MVM_6model_get_stable_debug_name(tc, st)); |
495 | 0 | } |
496 | 11 | } |
497 | | |
498 | | /* Used with boxing. Sets a floating point value, for representations that can |
499 | | * hold one. */ |
500 | 7 | static void set_num(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMnum64 value) { |
501 | 7 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
502 | 7 | data = MVM_p6opaque_real_data(tc, data); |
503 | 7 | if (repr_data->unbox_num_slot >= 0) { |
504 | 7 | MVMSTable *st = repr_data->flattened_stables[repr_data->unbox_num_slot]; |
505 | 7 | st->REPR->box_funcs.set_num(tc, st, root, (char *)data + repr_data->attribute_offsets[repr_data->unbox_num_slot], value); |
506 | 7 | } |
507 | 0 | else { |
508 | 0 | MVM_exception_throw_adhoc(tc, |
509 | 0 | "This type cannot box a native number: P6opaque, %s", MVM_6model_get_stable_debug_name(tc, st)); |
510 | 0 | } |
511 | 7 | } |
512 | | |
513 | | /* Used with boxing. Gets a floating point value, for representations that can |
514 | | * hold one. */ |
515 | 6 | static MVMnum64 get_num(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) { |
516 | 6 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
517 | 6 | data = MVM_p6opaque_real_data(tc, data); |
518 | 6 | if (repr_data->unbox_num_slot >= 0) { |
519 | 6 | MVMSTable *st = repr_data->flattened_stables[repr_data->unbox_num_slot]; |
520 | 6 | return st->REPR->box_funcs.get_num(tc, st, root, (char *)data + repr_data->attribute_offsets[repr_data->unbox_num_slot]); |
521 | 6 | } |
522 | 0 | else { |
523 | 0 | MVM_exception_throw_adhoc(tc, |
524 | 0 | "This type cannot unbox to a native number: P6opaque, %s", MVM_6model_get_stable_debug_name(tc, st)); |
525 | 0 | } |
526 | 6 | } |
527 | | |
528 | | /* Used with boxing. Sets a string value, for representations that can hold |
529 | | * one. */ |
530 | 13 | static void set_str(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMString *value) { |
531 | 13 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
532 | 13 | data = MVM_p6opaque_real_data(tc, data); |
533 | 13 | if (repr_data->unbox_str_slot >= 0) { |
534 | 13 | MVMSTable *st = repr_data->flattened_stables[repr_data->unbox_str_slot]; |
535 | 13 | st->REPR->box_funcs.set_str(tc, st, root, (char *)data + repr_data->attribute_offsets[repr_data->unbox_str_slot], value); |
536 | 13 | } |
537 | 0 | else { |
538 | 0 | MVM_exception_throw_adhoc(tc, |
539 | 0 | "This type cannot box a native string: P6opaque, %s", MVM_6model_get_stable_debug_name(tc, st)); |
540 | 0 | } |
541 | 13 | } |
542 | | |
543 | | /* Used with boxing. Gets a string value, for representations that can hold |
544 | | * one. */ |
545 | 12 | static MVMString * get_str(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) { |
546 | 12 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
547 | 12 | data = MVM_p6opaque_real_data(tc, data); |
548 | 12 | if (repr_data->unbox_str_slot >= 0) { |
549 | 12 | MVMSTable *st = repr_data->flattened_stables[repr_data->unbox_str_slot]; |
550 | 12 | return st->REPR->box_funcs.get_str(tc, st, root, (char *)data + repr_data->attribute_offsets[repr_data->unbox_str_slot]); |
551 | 12 | } |
552 | 0 | else { |
553 | 0 | MVM_exception_throw_adhoc(tc, |
554 | 0 | "This type cannot unbox to a native string: P6opaque, %s", MVM_6model_get_stable_debug_name(tc, st)); |
555 | 0 | } |
556 | 12 | } |
557 | | |
558 | | /* Used with boxing. Sets an unsigned integer value, for representations that can hold |
559 | | * one. */ |
560 | 0 | static void set_uint(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMuint64 value) { |
561 | 0 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
562 | 0 | data = MVM_p6opaque_real_data(tc, data); |
563 | 0 | if (repr_data->unbox_int_slot >= 0) { |
564 | 0 | MVMSTable *st = repr_data->flattened_stables[repr_data->unbox_int_slot]; |
565 | 0 | st->REPR->box_funcs.set_uint(tc, st, root, (char *)data + repr_data->attribute_offsets[repr_data->unbox_int_slot], value); |
566 | 0 | } |
567 | 0 | else { |
568 | 0 | MVM_exception_throw_adhoc(tc, |
569 | 0 | "This type cannot box a native integer: P6opaque, %s", MVM_6model_get_stable_debug_name(tc, st)); |
570 | 0 | } |
571 | 0 | } |
572 | | |
573 | | /* Used with boxing. Gets an unsigned integer value, for representations that can |
574 | | * hold one. */ |
575 | 0 | static MVMuint64 get_uint(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) { |
576 | 0 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
577 | 0 | data = MVM_p6opaque_real_data(tc, data); |
578 | 0 | if (repr_data->unbox_int_slot >= 0) { |
579 | 0 | MVMSTable *st = repr_data->flattened_stables[repr_data->unbox_int_slot]; |
580 | 0 | return st->REPR->box_funcs.get_uint(tc, st, root, (char *)data + repr_data->attribute_offsets[repr_data->unbox_int_slot]); |
581 | 0 | } |
582 | 0 | else { |
583 | 0 | MVM_exception_throw_adhoc(tc, |
584 | 0 | "This type cannot unbox to a native integer: P6opaque, %s", MVM_6model_get_stable_debug_name(tc, st)); |
585 | 0 | } |
586 | 0 | } |
587 | | |
588 | 21 | static void * get_boxed_ref(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMuint32 repr_id) { |
589 | 21 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
590 | 21 | data = MVM_p6opaque_real_data(tc, data); |
591 | 21 | if (repr_data->unbox_slots) { |
592 | 21 | MVMuint16 offset = repr_data->unbox_slots[repr_id]; |
593 | 21 | if (offset != MVM_P6OPAQUE_NO_UNBOX_SLOT) |
594 | 21 | return (char *)data + repr_data->attribute_offsets[offset]; |
595 | 21 | } |
596 | 21 | |
597 | 0 | MVM_exception_throw_adhoc(tc, |
598 | 0 | "P6opaque: get_boxed_ref could not unbox for the representation '%s' of type %s", MVM_repr_get_by_id(tc, repr_id)->name, MVM_6model_get_stable_debug_name(tc, st)); |
599 | 0 | } |
600 | | |
601 | | static const MVMStorageSpec default_storage_spec = { |
602 | | MVM_STORAGE_SPEC_REFERENCE, /* inlineable */ |
603 | | 0, /* bits */ |
604 | | ALIGNOF(void *), /* align */ |
605 | | MVM_STORAGE_SPEC_BP_NONE, /* boxed_primitive */ |
606 | | 0, /* can_box */ |
607 | | 0, /* is_unsigned */ |
608 | | }; |
609 | | |
610 | | |
611 | | /* Gets the storage specification for this representation. */ |
612 | 235k | static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) { |
613 | 235k | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
614 | 235k | if (repr_data) |
615 | 235k | return &repr_data->storage_spec; |
616 | 0 | return &default_storage_spec; |
617 | 235k | } |
618 | | |
619 | 20.2k | static void mk_storage_spec(MVMThreadContext *tc, MVMP6opaqueREPRData * repr_data, MVMStorageSpec *spec) { |
620 | 20.2k | |
621 | 20.2k | spec->inlineable = MVM_STORAGE_SPEC_REFERENCE; |
622 | 20.2k | spec->boxed_primitive = MVM_STORAGE_SPEC_BP_NONE; |
623 | 20.2k | spec->can_box = 0; |
624 | 20.2k | |
625 | 20.2k | if (repr_data->unbox_int_slot >= 0) |
626 | 10 | spec->can_box += MVM_STORAGE_SPEC_CAN_BOX_INT; |
627 | 20.2k | if (repr_data->unbox_num_slot >= 0) |
628 | 4 | spec->can_box += MVM_STORAGE_SPEC_CAN_BOX_NUM; |
629 | 20.2k | if (repr_data->unbox_str_slot >= 0) |
630 | 5 | spec->can_box += MVM_STORAGE_SPEC_CAN_BOX_STR; |
631 | 20.2k | } |
632 | | |
633 | | /* Compose the representation. */ |
634 | 19 | static MVMuint16 * allocate_unbox_slots() { |
635 | 19 | MVMuint16 *slots = MVM_malloc(MVM_REPR_MAX_COUNT * sizeof(MVMuint16)); |
636 | 19 | MVMuint16 i; |
637 | 1.23k | for (i = 0; i < MVM_REPR_MAX_COUNT; i++) |
638 | 1.21k | slots[i] = MVM_P6OPAQUE_NO_UNBOX_SLOT; |
639 | 19 | return slots; |
640 | 19 | } |
641 | 1.49k | static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) { |
642 | 1.49k | MVMint64 mro_pos, mro_count, num_parents, total_attrs, num_attrs, |
643 | 1.49k | cur_slot, cur_type, cur_alloc_addr, cur_obj_attr, |
644 | 1.49k | cur_init_slot, cur_mark_slot, cur_cleanup_slot, |
645 | 1.49k | unboxed_type, i; |
646 | 1.49k | MVMObject *info; |
647 | 1.49k | MVMP6opaqueREPRData *repr_data; |
648 | 1.49k | |
649 | 1.49k | MVMStringConsts str_consts = tc->instance->str_consts; |
650 | 1.49k | MVMString * const str_avc = str_consts.auto_viv_container; |
651 | 1.49k | MVMString * const str_name = str_consts.name; |
652 | 1.49k | MVMString * const str_type = str_consts.type; |
653 | 1.49k | MVMString * const str_ass_del = str_consts.associative_delegate; |
654 | 1.49k | MVMString * const str_pos_del = str_consts.positional_delegate; |
655 | 1.49k | MVMString * const str_attribute = str_consts.attribute; |
656 | 1.49k | MVMString * const str_box_target = str_consts.box_target; |
657 | 1.49k | |
658 | 1.49k | /* Check not already composed. */ |
659 | 1.49k | if (st->REPR_data) |
660 | 0 | MVM_exception_throw_adhoc(tc, "Type %s is already composed", MVM_6model_get_stable_debug_name(tc, st)); |
661 | 1.49k | |
662 | 1.49k | /* Allocate the representation data. */ |
663 | 1.49k | repr_data = (MVMP6opaqueREPRData *)MVM_calloc(1, sizeof(MVMP6opaqueREPRData)); |
664 | 1.49k | |
665 | 1.49k | /* Find attribute information. */ |
666 | 1.49k | info = MVM_repr_at_key_o(tc, info_hash, str_attribute); |
667 | 1.49k | if (MVM_is_null(tc, info)) |
668 | 0 | MVM_exception_throw_adhoc(tc, "P6opaque: missing attribute protocol in compose of %s", MVM_6model_get_stable_debug_name(tc, st)); |
669 | 1.49k | |
670 | 1.49k | /* In this first pass, we'll loop over the MRO entries, looking for |
671 | 1.49k | * if there is any multiple inheritance and counting the number of |
672 | 1.49k | * attributes. */ |
673 | 1.49k | mro_count = REPR(info)->elems(tc, STABLE(info), info, OBJECT_BODY(info)); |
674 | 1.49k | mro_pos = mro_count; |
675 | 1.49k | total_attrs = 0; |
676 | 4.05k | while (mro_pos--) { |
677 | 2.56k | /* Get info for the class at the current position. */ |
678 | 2.56k | MVMObject *class_info = MVM_repr_at_pos_o(tc, info, mro_pos); |
679 | 2.56k | |
680 | 2.56k | /* Get its list of attributes and parents. */ |
681 | 2.56k | MVMObject *attr_list = MVM_repr_at_pos_o(tc, class_info, 1); |
682 | 2.56k | MVMObject *parent_list = MVM_repr_at_pos_o(tc, class_info, 2); |
683 | 2.56k | |
684 | 2.56k | /* If there's more than one parent, set the multiple inheritance |
685 | 2.56k | * flag (this means we have non-linear layout). */ |
686 | 2.56k | num_parents = REPR(parent_list)->elems(tc, STABLE(parent_list), |
687 | 2.56k | parent_list, OBJECT_BODY(parent_list)); |
688 | 2.56k | if (num_parents > 1) |
689 | 0 | repr_data->mi = 1; |
690 | 2.56k | |
691 | 2.56k | /* Add attribute count to the running total. */ |
692 | 2.56k | total_attrs += REPR(attr_list)->elems(tc, STABLE(attr_list), |
693 | 2.56k | attr_list, OBJECT_BODY(attr_list)); |
694 | 2.56k | } |
695 | 1.49k | |
696 | 1.49k | /* Fill out and allocate other things we now can. */ |
697 | 1.49k | repr_data->num_attributes = total_attrs; |
698 | 1.49k | if (total_attrs) { |
699 | 372 | repr_data->attribute_offsets = MVM_malloc(total_attrs * sizeof(MVMuint16)); |
700 | 372 | repr_data->flattened_stables = (MVMSTable **)MVM_calloc(total_attrs, sizeof(MVMSTable *)); |
701 | 372 | repr_data->auto_viv_values = (MVMObject **)MVM_calloc(total_attrs, sizeof(MVMObject *)); |
702 | 372 | repr_data->gc_obj_mark_offsets = MVM_malloc(total_attrs * sizeof(MVMuint16)); |
703 | 372 | } |
704 | 1.49k | repr_data->name_to_index_mapping = (MVMP6opaqueNameMap *)MVM_calloc((mro_count + 1), sizeof(MVMP6opaqueNameMap)); |
705 | 1.49k | repr_data->initialize_slots = MVM_malloc((total_attrs + 1) * sizeof(MVMuint16)); |
706 | 1.49k | repr_data->gc_mark_slots = MVM_malloc((total_attrs + 1) * sizeof(MVMuint16)); |
707 | 1.49k | repr_data->gc_cleanup_slots = MVM_malloc((total_attrs + 1) * sizeof(MVMuint16)); |
708 | 1.49k | |
709 | 1.49k | /* -1 indicates no unboxing or delegate possible for a type. */ |
710 | 1.49k | repr_data->unbox_int_slot = -1; |
711 | 1.49k | repr_data->unbox_num_slot = -1; |
712 | 1.49k | repr_data->unbox_str_slot = -1; |
713 | 1.49k | repr_data->pos_del_slot = -1; |
714 | 1.49k | repr_data->ass_del_slot = -1; |
715 | 1.49k | |
716 | 1.49k | /* Second pass populates the rest of the REPR data. */ |
717 | 1.49k | mro_pos = mro_count; |
718 | 1.49k | cur_slot = 0; |
719 | 1.49k | cur_type = 0; |
720 | 1.49k | cur_alloc_addr = sizeof(MVMP6opaqueBody); |
721 | 1.49k | cur_obj_attr = 0; |
722 | 1.49k | cur_init_slot = 0; |
723 | 1.49k | cur_mark_slot = 0; |
724 | 1.49k | cur_cleanup_slot = 0; |
725 | 4.05k | while (mro_pos--) { |
726 | 2.56k | /* Get info for the class at the current position. */ |
727 | 2.56k | MVMObject *class_info = MVM_repr_at_pos_o(tc, info, mro_pos); |
728 | 2.56k | MVMObject *type_obj = MVM_repr_at_pos_o(tc, class_info, 0); |
729 | 2.56k | MVMObject *attr_list = MVM_repr_at_pos_o(tc, class_info, 1); |
730 | 2.56k | |
731 | 2.56k | /* Set up name map entry. */ |
732 | 2.56k | MVMP6opaqueNameMap *name_map = &repr_data->name_to_index_mapping[cur_type]; |
733 | 2.56k | num_attrs = REPR(attr_list)->elems(tc, STABLE(attr_list), |
734 | 2.56k | attr_list, OBJECT_BODY(attr_list)); |
735 | 2.56k | MVM_ASSIGN_REF(tc, &(st->header), name_map->class_key, type_obj); |
736 | 2.56k | name_map->num_attrs = num_attrs; |
737 | 2.56k | if (num_attrs) { |
738 | 934 | name_map->names = MVM_malloc(num_attrs * sizeof(MVMString *)); |
739 | 934 | name_map->slots = MVM_malloc(num_attrs * sizeof(MVMuint16)); |
740 | 934 | } |
741 | 2.56k | |
742 | 2.56k | /* Go over the attributes. */ |
743 | 5.64k | for (i = 0; i < num_attrs; i++) { |
744 | 3.08k | MVMObject *attr_info = MVM_repr_at_pos_o(tc, attr_list, i); |
745 | 3.08k | |
746 | 3.08k | /* Extract name, type and if it's a box target. */ |
747 | 3.08k | MVMObject *name_obj = MVM_repr_at_key_o(tc, attr_info, str_name); |
748 | 3.08k | MVMObject *type = MVM_repr_at_key_o(tc, attr_info, str_type); |
749 | 3.08k | MVMint64 is_box_target = REPR(attr_info)->ass_funcs.exists_key(tc, |
750 | 3.08k | STABLE(attr_info), attr_info, OBJECT_BODY(attr_info), (MVMObject *)str_box_target); |
751 | 3.08k | MVMint8 inlined = 0; |
752 | 3.08k | MVMuint32 bits; |
753 | 3.08k | MVMuint32 align; |
754 | 3.08k | |
755 | 3.08k | /* Ensure we have a name. */ |
756 | 3.08k | if (MVM_is_null(tc, name_obj)) |
757 | 0 | MVM_exception_throw_adhoc(tc, "P6opaque: %s missing attribute name for attribute %"PRId64, MVM_6model_get_stable_debug_name(tc, st), i); |
758 | 3.08k | |
759 | 3.08k | if (REPR(name_obj)->ID == MVM_REPR_ID_MVMString) { |
760 | 5 | MVM_ASSIGN_REF(tc, &(st->header), name_map->names[i], (MVMString *)name_obj); |
761 | 5 | } |
762 | 3.07k | else { |
763 | 3.07k | MVM_ASSIGN_REF(tc, &(st->header), name_map->names[i], MVM_repr_get_str(tc, name_obj)); |
764 | 3.07k | } |
765 | 3.08k | name_map->slots[i] = cur_slot; |
766 | 3.08k | |
767 | 3.08k | /* Consider the type. */ |
768 | 3.08k | unboxed_type = MVM_STORAGE_SPEC_BP_NONE; |
769 | 3.08k | bits = sizeof(MVMObject *) * 8; |
770 | 3.08k | align = ALIGNOF(void *); |
771 | 3.08k | if (!MVM_is_null(tc, type)) { |
772 | 1.43k | /* Get the storage spec of the type and see what it wants. */ |
773 | 1.43k | const MVMStorageSpec *spec = REPR(type)->get_storage_spec(tc, STABLE(type)); |
774 | 1.43k | if (spec->inlineable == MVM_STORAGE_SPEC_INLINED) { |
775 | 1.43k | /* Yes, it's something we'll flatten. */ |
776 | 1.43k | unboxed_type = spec->boxed_primitive; |
777 | 1.43k | bits = spec->bits; |
778 | 1.43k | align = spec->align; |
779 | 1.43k | MVM_ASSIGN_REF(tc, &(st->header), repr_data->flattened_stables[cur_slot], STABLE(type)); |
780 | 1.43k | inlined = 1; |
781 | 1.43k | |
782 | 1.43k | /* Does it need special initialization? */ |
783 | 1.43k | if (REPR(type)->initialize) { |
784 | 3 | repr_data->initialize_slots[cur_init_slot] = cur_slot; |
785 | 3 | cur_init_slot++; |
786 | 3 | } |
787 | 1.43k | |
788 | 1.43k | /* Does it have special GC needs? */ |
789 | 1.43k | if (REPR(type)->gc_mark) { |
790 | 563 | repr_data->gc_mark_slots[cur_mark_slot] = cur_slot; |
791 | 563 | cur_mark_slot++; |
792 | 563 | } |
793 | 1.43k | if (REPR(type)->gc_cleanup) { |
794 | 3 | repr_data->gc_cleanup_slots[cur_cleanup_slot] = cur_slot; |
795 | 3 | cur_cleanup_slot++; |
796 | 3 | } |
797 | 1.43k | |
798 | 1.43k | /* Is it a target for box/unbox operations? */ |
799 | 1.43k | if (is_box_target) { |
800 | 17 | /* If it boxes a primitive, note that. */ |
801 | 17 | switch (unboxed_type) { |
802 | 8 | case MVM_STORAGE_SPEC_BP_INT: |
803 | 8 | if (repr_data->unbox_int_slot >= 0) |
804 | 0 | MVM_exception_throw_adhoc(tc, |
805 | 0 | "While composing %s: Duplicate box_target for native int: attributes %d and %"PRId64, MVM_6model_get_stable_debug_name(tc, st), repr_data->unbox_int_slot, i); |
806 | 8 | repr_data->unbox_int_slot = cur_slot; |
807 | 8 | break; |
808 | 4 | case MVM_STORAGE_SPEC_BP_NUM: |
809 | 4 | if (repr_data->unbox_num_slot >= 0) |
810 | 0 | MVM_exception_throw_adhoc(tc, |
811 | 0 | "While composing %s: Duplicate box_target for native num: attributes %d and %"PRId64, MVM_6model_get_stable_debug_name(tc, st), repr_data->unbox_num_slot, i); |
812 | 4 | repr_data->unbox_num_slot = cur_slot; |
813 | 4 | break; |
814 | 5 | case MVM_STORAGE_SPEC_BP_STR: |
815 | 5 | if (repr_data->unbox_str_slot >= 0) |
816 | 0 | MVM_exception_throw_adhoc(tc, |
817 | 0 | "While composing %s: Duplicate box_target for native str: attributes %d and %"PRId64, MVM_6model_get_stable_debug_name(tc, st), repr_data->unbox_str_slot, i); |
818 | 5 | repr_data->unbox_str_slot = cur_slot; |
819 | 5 | break; |
820 | 0 | default: |
821 | 0 | /* nothing, just suppress 'missing default' warning */ |
822 | 0 | break; |
823 | 17 | } |
824 | 17 | |
825 | 17 | /* Also list in the by-repr unbox list. */ |
826 | 17 | if (repr_data->unbox_slots == NULL) |
827 | 17 | repr_data->unbox_slots = allocate_unbox_slots(); |
828 | 17 | repr_data->unbox_slots[REPR(type)->ID] = cur_slot; |
829 | 17 | } |
830 | 1.43k | } |
831 | 1.43k | } |
832 | 3.08k | |
833 | 3.08k | /* C structure needs careful alignment. If cur_alloc_addr is not |
834 | 3.08k | * aligned to align bytes (cur_alloc_addr % align), make sure it is |
835 | 3.08k | * before we add the next element. */ |
836 | 3.08k | if (cur_alloc_addr % align) { |
837 | 0 | cur_alloc_addr += align - cur_alloc_addr % align; |
838 | 0 | } |
839 | 3.08k | |
840 | 3.08k | /* Attribute will live at the current position in the object. */ |
841 | 3.08k | repr_data->attribute_offsets[cur_slot] = cur_alloc_addr; |
842 | 3.08k | |
843 | 3.08k | /* Handle object attributes, which need marking and may have auto-viv needs. */ |
844 | 3.08k | if (!inlined) { |
845 | 1.65k | repr_data->gc_obj_mark_offsets[cur_obj_attr] = cur_alloc_addr; |
846 | 1.65k | if (MVM_repr_exists_key(tc, attr_info, str_avc)) |
847 | 1.64k | MVM_ASSIGN_REF(tc, &(st->header), repr_data->auto_viv_values[cur_slot], |
848 | 1.65k | MVM_repr_at_key_o(tc, attr_info, str_avc)); |
849 | 1.65k | cur_obj_attr++; |
850 | 1.65k | } |
851 | 3.08k | |
852 | 3.08k | /* Is it a positional or associative delegate? */ |
853 | 3.08k | if (MVM_repr_exists_key(tc, attr_info, str_pos_del)) { |
854 | 185 | if (repr_data->pos_del_slot != -1) |
855 | 0 | MVM_exception_throw_adhoc(tc, |
856 | 0 | "While composing %s: Duplicate positional delegate attributes: %d and %"PRId64"", MVM_6model_get_stable_debug_name(tc, st), repr_data->pos_del_slot, cur_slot); |
857 | 185 | if (unboxed_type == MVM_STORAGE_SPEC_BP_NONE) |
858 | 185 | repr_data->pos_del_slot = cur_slot; |
859 | 185 | else |
860 | 0 | MVM_exception_throw_adhoc(tc, |
861 | 0 | "While composing %s: Positional delegate attribute must be a reference type", MVM_6model_get_stable_debug_name(tc, st)); |
862 | 185 | } |
863 | 3.08k | if (MVM_repr_exists_key(tc, attr_info, str_ass_del)) { |
864 | 16 | if (repr_data->ass_del_slot != -1) |
865 | 0 | MVM_exception_throw_adhoc(tc, |
866 | 0 | "While composing %s: Duplicate associative delegate attributes: %d and %"PRId64, MVM_6model_get_stable_debug_name(tc, st), repr_data->pos_del_slot, cur_slot); |
867 | 16 | if (unboxed_type == MVM_STORAGE_SPEC_BP_NONE) |
868 | 16 | repr_data->ass_del_slot = cur_slot; |
869 | 16 | else |
870 | 0 | MVM_exception_throw_adhoc(tc, |
871 | 0 | "While composing %s: Associative delegate attribute must be a reference type", MVM_6model_get_stable_debug_name(tc, st)); |
872 | 16 | } |
873 | 3.08k | |
874 | 3.08k | /* Add the required space for this type. */ |
875 | 3.08k | cur_alloc_addr += bits / 8; |
876 | 3.08k | |
877 | 3.08k | /* Increment slot count. */ |
878 | 3.08k | cur_slot++; |
879 | 3.08k | } |
880 | 2.56k | |
881 | 2.56k | /* Increment name map type index. */ |
882 | 2.56k | cur_type++; |
883 | 2.56k | } |
884 | 1.49k | |
885 | 1.49k | /* Add allocated amount for body to have total object size. */ |
886 | 1.49k | st->size = sizeof(MVMP6opaque) + (cur_alloc_addr - sizeof(MVMP6opaqueBody)); |
887 | 1.49k | |
888 | 1.49k | /* Add sentinels/counts. */ |
889 | 1.49k | repr_data->gc_obj_mark_offsets_count = cur_obj_attr; |
890 | 1.49k | repr_data->initialize_slots[cur_init_slot] = -1; |
891 | 1.49k | repr_data->gc_mark_slots[cur_mark_slot] = -1; |
892 | 1.49k | repr_data->gc_cleanup_slots[cur_cleanup_slot] = -1; |
893 | 1.49k | |
894 | 1.49k | /* Add storage spec */ |
895 | 1.49k | mk_storage_spec(tc, repr_data, &repr_data->storage_spec); |
896 | 1.49k | |
897 | 1.49k | /* Install representation data. */ |
898 | 1.49k | st->REPR_data = repr_data; |
899 | 1.49k | } |
900 | | |
901 | | /* Set the size of the STable. */ |
902 | 18.7k | static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) { |
903 | 18.7k | /* To calculate size, we need number of attributes and to know about |
904 | 18.7k | * anything flattend in. */ |
905 | 18.7k | MVMint64 num_attributes = MVM_serialization_read_int(tc, reader); |
906 | 18.7k | MVMuint32 cur_offset = sizeof(MVMP6opaque); |
907 | 18.7k | MVMint64 i; |
908 | 89.6k | for (i = 0; i < num_attributes; i++) { |
909 | 70.8k | if (MVM_serialization_read_int(tc, reader)) { |
910 | 15.1k | MVMSTable *st = MVM_serialization_read_stable_ref(tc, reader); |
911 | 15.1k | const MVMStorageSpec *ss = st->REPR->get_storage_spec(tc, st); |
912 | 15.1k | if (ss->inlineable) { |
913 | 15.1k | /* TODO: Review if/when we get sub-byte things. */ |
914 | 15.1k | if (cur_offset % ss->align) { |
915 | 0 | cur_offset += ss->align - cur_offset % ss->align; |
916 | 0 | } |
917 | 15.1k | cur_offset += ss->bits / 8; |
918 | 15.1k | } |
919 | 15.1k | else |
920 | 0 | cur_offset += sizeof(MVMObject *); |
921 | 15.1k | } |
922 | 55.7k | else { |
923 | 55.7k | cur_offset += sizeof(MVMObject *); |
924 | 55.7k | } |
925 | 70.8k | } |
926 | 18.7k | |
927 | 18.7k | st->size = cur_offset; |
928 | 18.7k | } |
929 | | |
930 | | /* Serializes the REPR data. */ |
931 | 17 | static void serialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationWriter *writer) { |
932 | 17 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
933 | 17 | MVMuint16 i, num_classes; |
934 | 17 | |
935 | 17 | if (!repr_data) |
936 | 0 | MVM_exception_throw_adhoc(tc, |
937 | 0 | "Representation for %s must be composed before it can be serialized", MVM_6model_get_stable_debug_name(tc, st)); |
938 | 17 | |
939 | 17 | MVM_serialization_write_int(tc, writer, repr_data->num_attributes); |
940 | 17 | |
941 | 26 | for (i = 0; i < repr_data->num_attributes; i++) { |
942 | 9 | MVM_serialization_write_int(tc, writer, repr_data->flattened_stables[i] != NULL); |
943 | 9 | if (repr_data->flattened_stables[i]) |
944 | 5 | MVM_serialization_write_stable_ref(tc, writer, repr_data->flattened_stables[i]); |
945 | 9 | } |
946 | 17 | |
947 | 17 | MVM_serialization_write_int(tc, writer, repr_data->mi); |
948 | 17 | |
949 | 17 | if (repr_data->auto_viv_values) { |
950 | 7 | MVM_serialization_write_int(tc, writer, 1); |
951 | 16 | for (i = 0; i < repr_data->num_attributes; i++) |
952 | 9 | MVM_serialization_write_ref(tc, writer, repr_data->auto_viv_values[i]); |
953 | 7 | } |
954 | 10 | else { |
955 | 10 | MVM_serialization_write_int(tc, writer, 0); |
956 | 10 | } |
957 | 17 | |
958 | 17 | MVM_serialization_write_int(tc, writer, repr_data->unbox_int_slot); |
959 | 17 | MVM_serialization_write_int(tc, writer, repr_data->unbox_num_slot); |
960 | 17 | MVM_serialization_write_int(tc, writer, repr_data->unbox_str_slot); |
961 | 17 | |
962 | 17 | if (repr_data->unbox_slots) { |
963 | 2 | MVMuint32 num_written = 0; |
964 | 2 | MVM_serialization_write_int(tc, writer, 1); |
965 | 130 | for (i = 0; i < MVM_REPR_MAX_COUNT; i++) { |
966 | 128 | if (repr_data->unbox_slots[i] != MVM_P6OPAQUE_NO_UNBOX_SLOT) { |
967 | 2 | MVM_serialization_write_int(tc, writer, i); |
968 | 2 | MVM_serialization_write_int(tc, writer, repr_data->unbox_slots[i]); |
969 | 2 | num_written++; |
970 | 2 | } |
971 | 128 | } |
972 | 2 | for (i = num_written; i < repr_data->num_attributes; i++) { |
973 | 0 | MVM_serialization_write_int(tc, writer, 0); |
974 | 0 | MVM_serialization_write_int(tc, writer, 0); |
975 | 0 | } |
976 | 2 | } |
977 | 15 | else { |
978 | 15 | MVM_serialization_write_int(tc, writer, 0); |
979 | 15 | } |
980 | 17 | |
981 | 17 | i = 0; |
982 | 47 | while (repr_data->name_to_index_mapping[i].class_key) |
983 | 30 | i++; |
984 | 17 | num_classes = i; |
985 | 17 | MVM_serialization_write_int(tc, writer, num_classes); |
986 | 47 | for (i = 0; i < num_classes; i++) { |
987 | 30 | const MVMuint32 num_attrs = repr_data->name_to_index_mapping[i].num_attrs; |
988 | 30 | MVMuint32 j; |
989 | 30 | MVM_serialization_write_ref(tc, writer, repr_data->name_to_index_mapping[i].class_key); |
990 | 30 | MVM_serialization_write_int(tc, writer, num_attrs); |
991 | 39 | for (j = 0; j < num_attrs; j++) { |
992 | 9 | MVM_serialization_write_str(tc, writer, repr_data->name_to_index_mapping[i].names[j]); |
993 | 9 | MVM_serialization_write_int(tc, writer, repr_data->name_to_index_mapping[i].slots[j]); |
994 | 9 | } |
995 | 30 | } |
996 | 17 | |
997 | 17 | MVM_serialization_write_int(tc, writer, repr_data->pos_del_slot); |
998 | 17 | MVM_serialization_write_int(tc, writer, repr_data->ass_del_slot); |
999 | 17 | } |
1000 | | |
1001 | | /* Deserializes representation data. */ |
1002 | 18.7k | static void deserialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) { |
1003 | 18.7k | MVMuint16 i, j, num_classes, cur_offset; |
1004 | 18.7k | MVMint16 cur_initialize_slot, cur_gc_mark_slot, cur_gc_cleanup_slot; |
1005 | 18.7k | |
1006 | 18.7k | MVMP6opaqueREPRData *repr_data = MVM_malloc(sizeof(MVMP6opaqueREPRData)); |
1007 | 18.7k | |
1008 | 18.7k | repr_data->num_attributes = (MVMuint16)MVM_serialization_read_int(tc, reader); |
1009 | 18.7k | |
1010 | 18.7k | repr_data->flattened_stables = (MVMSTable **)MVM_malloc(P6OMAX(repr_data->num_attributes, 1) * sizeof(MVMSTable *)); |
1011 | 89.6k | for (i = 0; i < repr_data->num_attributes; i++) |
1012 | 70.8k | if (MVM_serialization_read_int(tc, reader)) { |
1013 | 15.1k | MVM_ASSIGN_REF(tc, &(st->header), repr_data->flattened_stables[i], MVM_serialization_read_stable_ref(tc, reader)); |
1014 | 15.1k | } |
1015 | 55.7k | else { |
1016 | 55.7k | repr_data->flattened_stables[i] = NULL; |
1017 | 55.7k | } |
1018 | 18.7k | |
1019 | 18.7k | repr_data->mi = MVM_serialization_read_int(tc, reader); |
1020 | 18.7k | |
1021 | 18.7k | if (MVM_serialization_read_int(tc, reader)) { |
1022 | 10.3k | repr_data->auto_viv_values = (MVMObject **)MVM_malloc(P6OMAX(repr_data->num_attributes, 1) * sizeof(MVMObject *)); |
1023 | 81.2k | for (i = 0; i < repr_data->num_attributes; i++) |
1024 | 70.8k | MVM_ASSIGN_REF(tc, &(st->header), repr_data->auto_viv_values[i], MVM_serialization_read_ref(tc, reader)); |
1025 | 8.38k | } else { |
1026 | 8.38k | repr_data->auto_viv_values = NULL; |
1027 | 8.38k | } |
1028 | 18.7k | |
1029 | 18.7k | repr_data->unbox_int_slot = MVM_serialization_read_int(tc, reader); |
1030 | 18.7k | repr_data->unbox_num_slot = MVM_serialization_read_int(tc, reader); |
1031 | 18.7k | repr_data->unbox_str_slot = MVM_serialization_read_int(tc, reader); |
1032 | 18.7k | |
1033 | 18.7k | if (MVM_serialization_read_int(tc, reader)) { |
1034 | 2 | repr_data->unbox_slots = allocate_unbox_slots(); |
1035 | 4 | for (i = 0; i < repr_data->num_attributes; i++) { |
1036 | 2 | MVMuint16 repr_id = MVM_serialization_read_int(tc, reader); |
1037 | 2 | MVMuint16 slot = MVM_serialization_read_int(tc, reader); |
1038 | 2 | if (repr_id) |
1039 | 2 | repr_data->unbox_slots[repr_id] = slot; |
1040 | 2 | } |
1041 | 18.7k | } else { |
1042 | 18.7k | repr_data->unbox_slots = NULL; |
1043 | 18.7k | } |
1044 | 18.7k | |
1045 | 18.7k | num_classes = (MVMuint16)MVM_serialization_read_int(tc, reader); |
1046 | 18.7k | repr_data->name_to_index_mapping = (MVMP6opaqueNameMap *)MVM_malloc((num_classes + 1) * sizeof(MVMP6opaqueNameMap)); |
1047 | 56.8k | for (i = 0; i < num_classes; i++) { |
1048 | 38.0k | MVMint32 num_attrs = 0; |
1049 | 38.0k | |
1050 | 38.0k | MVM_ASSIGN_REF(tc, &(st->header), repr_data->name_to_index_mapping[i].class_key, |
1051 | 38.0k | MVM_serialization_read_ref(tc, reader)); |
1052 | 38.0k | |
1053 | 38.0k | num_attrs = MVM_serialization_read_int(tc, reader); |
1054 | 38.0k | repr_data->name_to_index_mapping[i].names = (MVMString **)MVM_malloc(P6OMAX(num_attrs, 1) * sizeof(MVMString *)); |
1055 | 38.0k | repr_data->name_to_index_mapping[i].slots = (MVMuint16 *)MVM_malloc(P6OMAX(num_attrs, 1) * sizeof(MVMuint16)); |
1056 | 108k | for (j = 0; j < num_attrs; j++) { |
1057 | 70.8k | MVM_ASSIGN_REF(tc, &(st->header), repr_data->name_to_index_mapping[i].names[j], |
1058 | 70.8k | MVM_serialization_read_str(tc, reader)); |
1059 | 70.8k | |
1060 | 70.8k | repr_data->name_to_index_mapping[i].slots[j] = (MVMuint16)MVM_serialization_read_int(tc, reader); |
1061 | 70.8k | } |
1062 | 38.0k | |
1063 | 38.0k | repr_data->name_to_index_mapping[i].num_attrs = num_attrs; |
1064 | 38.0k | } |
1065 | 18.7k | |
1066 | 18.7k | /* set the last one to be NULL */ |
1067 | 18.7k | repr_data->name_to_index_mapping[i].class_key = NULL; |
1068 | 18.7k | |
1069 | 18.7k | repr_data->pos_del_slot = (MVMint16)MVM_serialization_read_int(tc, reader); |
1070 | 18.7k | repr_data->ass_del_slot = (MVMint16)MVM_serialization_read_int(tc, reader); |
1071 | 18.7k | |
1072 | 18.7k | /* Re-calculate the remaining info, which is platform specific or |
1073 | 18.7k | * derived information. */ |
1074 | 18.7k | repr_data->attribute_offsets = (MVMuint16 *)MVM_malloc(P6OMAX(repr_data->num_attributes, 1) * sizeof(MVMuint16)); |
1075 | 18.7k | repr_data->gc_obj_mark_offsets = (MVMuint16 *)MVM_malloc(P6OMAX(repr_data->num_attributes, 1) * sizeof(MVMuint16)); |
1076 | 18.7k | repr_data->initialize_slots = (MVMint16 *)MVM_malloc((repr_data->num_attributes + 1) * sizeof(MVMint16)); |
1077 | 18.7k | repr_data->gc_mark_slots = (MVMint16 *)MVM_malloc((repr_data->num_attributes + 1) * sizeof(MVMint16)); |
1078 | 18.7k | repr_data->gc_cleanup_slots = (MVMint16 *)MVM_malloc((repr_data->num_attributes + 1) * sizeof(MVMint16)); |
1079 | 18.7k | repr_data->gc_obj_mark_offsets_count = 0; |
1080 | 18.7k | cur_offset = sizeof(MVMP6opaqueBody); |
1081 | 18.7k | cur_initialize_slot = 0; |
1082 | 18.7k | cur_gc_mark_slot = 0; |
1083 | 18.7k | cur_gc_cleanup_slot = 0; |
1084 | 89.6k | for (i = 0; i < repr_data->num_attributes; i++) { |
1085 | 70.8k | if (repr_data->flattened_stables[i] == NULL) { |
1086 | 55.7k | /* Store position. */ |
1087 | 55.7k | repr_data->attribute_offsets[i] = cur_offset; |
1088 | 55.7k | |
1089 | 55.7k | /* Reference type. Needs marking. */ |
1090 | 55.7k | repr_data->gc_obj_mark_offsets[repr_data->gc_obj_mark_offsets_count] = cur_offset; |
1091 | 55.7k | repr_data->gc_obj_mark_offsets_count++; |
1092 | 55.7k | |
1093 | 55.7k | /* Increment by pointer size. */ |
1094 | 55.7k | cur_offset += sizeof(MVMObject *); |
1095 | 55.7k | } |
1096 | 15.1k | else { |
1097 | 15.1k | /* Store position. */ |
1098 | 15.1k | MVMSTable *cur_st = repr_data->flattened_stables[i]; |
1099 | 15.1k | const MVMStorageSpec *spec = cur_st->REPR->get_storage_spec(tc, cur_st); |
1100 | 15.1k | /* Set up flags for initialization and GC. */ |
1101 | 15.1k | if (cur_st->REPR->initialize) |
1102 | 1 | repr_data->initialize_slots[cur_initialize_slot++] = i; |
1103 | 15.1k | if (cur_st->REPR->gc_mark) |
1104 | 4.18k | repr_data->gc_mark_slots[cur_gc_mark_slot++] = i; |
1105 | 15.1k | if (cur_st->REPR->gc_cleanup) |
1106 | 1 | repr_data->gc_cleanup_slots[cur_gc_cleanup_slot++] = i; |
1107 | 15.1k | |
1108 | 15.1k | if (spec->align == 0) { |
1109 | 0 | MVM_exception_throw_adhoc(tc, "Serialization error: Storage Spec of P6opaque must not have align set to 0."); |
1110 | 0 | } |
1111 | 15.1k | |
1112 | 15.1k | if (cur_offset % spec->align) { |
1113 | 0 | cur_offset += spec->align - cur_offset % spec->align; |
1114 | 0 | } |
1115 | 15.1k | |
1116 | 15.1k | repr_data->attribute_offsets[i] = cur_offset; |
1117 | 15.1k | |
1118 | 15.1k | /* Increment by size reported by representation. */ |
1119 | 15.1k | cur_offset += spec->bits / 8; |
1120 | 15.1k | } |
1121 | 70.8k | } |
1122 | 18.7k | repr_data->initialize_slots[cur_initialize_slot] = -1; |
1123 | 18.7k | repr_data->gc_mark_slots[cur_gc_mark_slot] = -1; |
1124 | 18.7k | repr_data->gc_cleanup_slots[cur_gc_cleanup_slot] = -1; |
1125 | 18.7k | |
1126 | 18.7k | mk_storage_spec(tc, repr_data, &repr_data->storage_spec); |
1127 | 18.7k | |
1128 | 18.7k | st->REPR_data = repr_data; |
1129 | 18.7k | } |
1130 | | |
1131 | | /* Deserializes the data. */ |
1132 | 217k | static void deserialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMSerializationReader *reader) { |
1133 | 217k | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1134 | 217k | MVMuint16 num_attributes = repr_data->num_attributes; |
1135 | 217k | MVMuint16 i; |
1136 | 1.75M | for (i = 0; i < num_attributes; i++) { |
1137 | 1.53M | MVMuint16 a_offset = repr_data->attribute_offsets[i]; |
1138 | 1.53M | MVMSTable *a_st = repr_data->flattened_stables[i]; |
1139 | 1.53M | if (a_st) |
1140 | 160k | a_st->REPR->deserialize(tc, a_st, root, (char *)data + a_offset, reader); |
1141 | 1.53M | else |
1142 | 1.37M | set_obj_at_offset(tc, root, data, a_offset, MVM_serialization_read_ref(tc, reader)); |
1143 | 1.53M | } |
1144 | 217k | } |
1145 | | |
1146 | | /* Serializes the object's body. */ |
1147 | 110 | static void serialize(MVMThreadContext *tc, MVMSTable *st, void *data, MVMSerializationWriter *writer) { |
1148 | 110 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1149 | 110 | MVMuint16 num_attributes; |
1150 | 110 | MVMuint16 i; |
1151 | 110 | |
1152 | 110 | if (!repr_data) |
1153 | 0 | MVM_exception_throw_adhoc(tc, |
1154 | 0 | "Representation of %s must be composed before it can be serialized", MVM_6model_get_stable_debug_name(tc, st)); |
1155 | 110 | |
1156 | 110 | num_attributes = repr_data->num_attributes; |
1157 | 110 | |
1158 | 110 | data = MVM_p6opaque_real_data(tc, data); |
1159 | 110 | |
1160 | 529 | for (i = 0; i < num_attributes; i++) { |
1161 | 419 | MVMuint16 a_offset = repr_data->attribute_offsets[i]; |
1162 | 419 | MVMSTable *a_st = repr_data->flattened_stables[i]; |
1163 | 419 | if (a_st) { |
1164 | 23 | if (a_st->REPR->serialize) |
1165 | 23 | a_st->REPR->serialize(tc, a_st, (char *)data + a_offset, writer); |
1166 | 23 | else |
1167 | 0 | MVM_exception_throw_adhoc(tc, "Missing serialize REPR function for REPR %s in type %s", a_st->REPR->name, MVM_6model_get_stable_debug_name(tc, a_st)); |
1168 | 23 | } |
1169 | 419 | else |
1170 | 396 | MVM_serialization_write_ref(tc, writer, get_obj_at_offset(data, a_offset)); |
1171 | 419 | } |
1172 | 110 | } |
1173 | | |
1174 | | /* Performs a change of type, where possible. */ |
1175 | 2.45k | static void change_type(MVMThreadContext *tc, MVMObject *obj, MVMObject *new_type) { |
1176 | 2.45k | MVMP6opaqueREPRData *cur_repr_data = (MVMP6opaqueREPRData *)STABLE(obj)->REPR_data; |
1177 | 2.45k | MVMP6opaqueREPRData *new_repr_data = (MVMP6opaqueREPRData *)STABLE(new_type)->REPR_data; |
1178 | 2.45k | MVMP6opaqueNameMap *cur_map_entry, *new_map_entry; |
1179 | 2.45k | |
1180 | 2.45k | /* Ensure we don't have a type object. */ |
1181 | 2.45k | if (!IS_CONCRETE(obj)) |
1182 | 0 | MVM_exception_throw_adhoc(tc, |
1183 | 0 | "Cannot change the type of a %s type object", MVM_6model_get_debug_name(tc, obj)); |
1184 | 2.45k | |
1185 | 2.45k | /* Ensure that the REPR of the new type is also P6opaque. */ |
1186 | 2.45k | if (REPR(new_type)->ID != REPR(obj)->ID) |
1187 | 1 | MVM_exception_throw_adhoc(tc, |
1188 | 1 | "New type for %s must have a matching representation (P6opaque vs %s)", MVM_6model_get_debug_name(tc, obj), REPR(new_type)->name); |
1189 | 2.45k | |
1190 | 2.45k | /* Ensure the MRO prefixes match up. */ |
1191 | 2.45k | cur_map_entry = cur_repr_data->name_to_index_mapping; |
1192 | 2.45k | new_map_entry = new_repr_data->name_to_index_mapping; |
1193 | 4.92k | while (cur_map_entry->class_key != NULL && cur_map_entry->num_attrs == 0) |
1194 | 2.46k | cur_map_entry++; |
1195 | 4.93k | while (new_map_entry->class_key != NULL && new_map_entry->num_attrs == 0) |
1196 | 2.47k | new_map_entry++; |
1197 | 7.34k | while (cur_map_entry->class_key != NULL) { |
1198 | 4.88k | if (new_map_entry->class_key == NULL || new_map_entry->class_key != cur_map_entry->class_key) |
1199 | 1 | MVM_exception_throw_adhoc(tc, |
1200 | 1 | "Incompatible MROs in P6opaque rebless for types %s and %s", MVM_6model_get_debug_name(tc, obj), MVM_6model_get_debug_name(tc, new_type)); |
1201 | 4.88k | cur_map_entry++; |
1202 | 4.88k | new_map_entry++; |
1203 | 4.88k | } |
1204 | 2.45k | |
1205 | 2.45k | /* Resize if needed. */ |
1206 | 2.45k | if (STABLE(obj)->size != STABLE(new_type)->size) { |
1207 | 2.44k | /* Get current object body. */ |
1208 | 2.44k | MVMP6opaqueBody *body = (MVMP6opaqueBody *)OBJECT_BODY(obj); |
1209 | 2.44k | void *old = body->replaced ? body->replaced : body; |
1210 | 2.44k | |
1211 | 2.44k | /* Allocate new memory. */ |
1212 | 2.44k | size_t new_size = STABLE(new_type)->size - sizeof(MVMObject); |
1213 | 2.44k | void *new = MVM_malloc(new_size); |
1214 | 2.44k | memset((char *)new + (STABLE(obj)->size - sizeof(MVMObject)), |
1215 | 2.44k | 0, new_size - (STABLE(obj)->size - sizeof(MVMObject))); |
1216 | 2.44k | |
1217 | 2.44k | /* Copy existing to new. |
1218 | 2.44k | * XXX Need more care here, as may have to re-barrier pointers. */ |
1219 | 2.44k | memcpy(new, old, STABLE(obj)->size - sizeof(MVMObject)); |
1220 | 2.44k | |
1221 | 2.44k | /* Pointer switch, taking care of existing body issues. */ |
1222 | 2.44k | if (body->replaced) { |
1223 | 0 | body->replaced = new; |
1224 | 0 | MVM_free(old); |
1225 | 0 | } |
1226 | 2.44k | else { |
1227 | 2.44k | body->replaced = new; |
1228 | 2.44k | } |
1229 | 2.44k | } |
1230 | 2.45k | |
1231 | 2.45k | /* Finally, ready to switch over the STable. */ |
1232 | 2.45k | MVM_ASSIGN_REF(tc, &(obj->header), obj->st, STABLE(new_type)); |
1233 | 2.45k | } |
1234 | | |
1235 | 0 | static void die_no_pos_del(MVMThreadContext *tc, MVMSTable *st) { |
1236 | 0 | MVM_exception_throw_adhoc(tc, "This type (%s) does not support positional operations", MVM_6model_get_stable_debug_name(tc, st)); |
1237 | 0 | } |
1238 | | |
1239 | 164k | static void at_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister *value, MVMuint16 kind) { |
1240 | 164k | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1241 | 164k | MVMObject *del; |
1242 | 164k | if (repr_data->pos_del_slot == -1) |
1243 | 0 | die_no_pos_del(tc, st); |
1244 | 164k | data = MVM_p6opaque_real_data(tc, data); |
1245 | 164k | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]); |
1246 | 164k | REPR(del)->pos_funcs.at_pos(tc, STABLE(del), del, OBJECT_BODY(del), index, value, kind); |
1247 | 164k | } |
1248 | 17.8k | void MVM_P6opaque_at_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister *value, MVMuint16 kind) { |
1249 | 17.8k | return at_pos(tc, st, root, data, index, value, kind); |
1250 | 17.8k | } |
1251 | | |
1252 | 33.6k | static void bind_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister value, MVMuint16 kind) { |
1253 | 33.6k | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1254 | 33.6k | MVMObject *del; |
1255 | 33.6k | if (repr_data->pos_del_slot == -1) |
1256 | 0 | die_no_pos_del(tc, st); |
1257 | 33.6k | data = MVM_p6opaque_real_data(tc, data); |
1258 | 33.6k | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]); |
1259 | 33.6k | REPR(del)->pos_funcs.bind_pos(tc, STABLE(del), del, OBJECT_BODY(del), index, value, kind); |
1260 | 33.6k | } |
1261 | | |
1262 | 0 | static void set_elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMuint64 count) { |
1263 | 0 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1264 | 0 | MVMObject *del; |
1265 | 0 | if (repr_data->pos_del_slot == -1) |
1266 | 0 | die_no_pos_del(tc, st); |
1267 | 0 | data = MVM_p6opaque_real_data(tc, data); |
1268 | 0 | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]); |
1269 | 0 | REPR(del)->pos_funcs.set_elems(tc, STABLE(del), del, OBJECT_BODY(del), count); |
1270 | 0 | } |
1271 | | |
1272 | 553 | static void push(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister value, MVMuint16 kind) { |
1273 | 553 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1274 | 553 | MVMObject *del; |
1275 | 553 | if (repr_data->pos_del_slot == -1) |
1276 | 0 | die_no_pos_del(tc, st); |
1277 | 553 | data = MVM_p6opaque_real_data(tc, data); |
1278 | 553 | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]); |
1279 | 553 | REPR(del)->pos_funcs.push(tc, STABLE(del), del, OBJECT_BODY(del), value, kind); |
1280 | 553 | } |
1281 | | |
1282 | 1 | static void pop(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) { |
1283 | 1 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1284 | 1 | MVMObject *del; |
1285 | 1 | if (repr_data->pos_del_slot == -1) |
1286 | 0 | die_no_pos_del(tc, st); |
1287 | 1 | data = MVM_p6opaque_real_data(tc, data); |
1288 | 1 | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]); |
1289 | 1 | REPR(del)->pos_funcs.pop(tc, STABLE(del), del, OBJECT_BODY(del), value, kind); |
1290 | 1 | } |
1291 | | |
1292 | 18.7k | static void unshift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister value, MVMuint16 kind) { |
1293 | 18.7k | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1294 | 18.7k | MVMObject *del; |
1295 | 18.7k | if (repr_data->pos_del_slot == -1) |
1296 | 0 | die_no_pos_del(tc, st); |
1297 | 18.7k | data = MVM_p6opaque_real_data(tc, data); |
1298 | 18.7k | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]); |
1299 | 18.7k | REPR(del)->pos_funcs.unshift(tc, STABLE(del), del, OBJECT_BODY(del), value, kind); |
1300 | 18.7k | } |
1301 | | |
1302 | 1 | static void shift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) { |
1303 | 1 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1304 | 1 | MVMObject *del; |
1305 | 1 | if (repr_data->pos_del_slot == -1) |
1306 | 0 | die_no_pos_del(tc, st); |
1307 | 1 | data = MVM_p6opaque_real_data(tc, data); |
1308 | 1 | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]); |
1309 | 1 | REPR(del)->pos_funcs.shift(tc, STABLE(del), del, OBJECT_BODY(del), value, kind); |
1310 | 1 | } |
1311 | | |
1312 | 0 | static void oslice(MVMThreadContext *tc, MVMSTable *st, MVMObject *src, void *data, MVMObject *dest, MVMint64 start, MVMint64 end) { |
1313 | 0 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1314 | 0 | MVMObject *del; |
1315 | 0 | if (repr_data->pos_del_slot == -1) |
1316 | 0 | die_no_pos_del(tc, st); |
1317 | 0 | data = MVM_p6opaque_real_data(tc, data); |
1318 | 0 | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]); |
1319 | 0 | REPR(del)->pos_funcs.slice(tc, STABLE(del), del, OBJECT_BODY(del), dest, start, end); |
1320 | 0 | } |
1321 | | |
1322 | 0 | static void osplice(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *target_array, MVMint64 offset, MVMuint64 elems) { |
1323 | 0 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1324 | 0 | MVMObject *del; |
1325 | 0 | if (repr_data->pos_del_slot == -1) |
1326 | 0 | die_no_pos_del(tc, st); |
1327 | 0 | data = MVM_p6opaque_real_data(tc, data); |
1328 | 0 | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]); |
1329 | 0 | REPR(del)->pos_funcs.splice(tc, STABLE(del), del, OBJECT_BODY(del), target_array, offset, elems); |
1330 | 0 | } |
1331 | | |
1332 | 0 | static void die_no_ass_del(MVMThreadContext *tc, MVMSTable *st) { |
1333 | 0 | MVM_exception_throw_adhoc(tc, "This type (%s) does not support associative operations", MVM_6model_get_stable_debug_name(tc, st)); |
1334 | 0 | } |
1335 | | |
1336 | 761k | static void at_key(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *key, MVMRegister *result, MVMuint16 kind) { |
1337 | 761k | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1338 | 761k | MVMObject *del; |
1339 | 761k | if (repr_data->ass_del_slot == -1) |
1340 | 0 | die_no_ass_del(tc, st); |
1341 | 761k | data = MVM_p6opaque_real_data(tc, data); |
1342 | 761k | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->ass_del_slot]); |
1343 | 761k | REPR(del)->ass_funcs.at_key(tc, STABLE(del), del, OBJECT_BODY(del), key, result, kind); |
1344 | 761k | } |
1345 | | |
1346 | 4 | static void bind_key(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *key, MVMRegister value, MVMuint16 kind) { |
1347 | 4 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1348 | 4 | MVMObject *del; |
1349 | 4 | if (repr_data->ass_del_slot == -1) |
1350 | 0 | die_no_ass_del(tc, st); |
1351 | 4 | data = MVM_p6opaque_real_data(tc, data); |
1352 | 4 | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->ass_del_slot]); |
1353 | 4 | REPR(del)->ass_funcs.bind_key(tc, STABLE(del), del, OBJECT_BODY(del), key, value, kind); |
1354 | 4 | } |
1355 | | |
1356 | 38.2k | static MVMint64 exists_key(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *key) { |
1357 | 38.2k | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1358 | 38.2k | MVMObject *del; |
1359 | 38.2k | if (repr_data->ass_del_slot == -1) |
1360 | 0 | die_no_ass_del(tc, st); |
1361 | 38.2k | data = MVM_p6opaque_real_data(tc, data); |
1362 | 38.2k | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->ass_del_slot]); |
1363 | 38.2k | return REPR(del)->ass_funcs.exists_key(tc, STABLE(del), del, OBJECT_BODY(del), key); |
1364 | 38.2k | } |
1365 | | |
1366 | 76.5k | static void delete_key(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *key) { |
1367 | 76.5k | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1368 | 76.5k | MVMObject *del; |
1369 | 76.5k | if (repr_data->ass_del_slot == -1) |
1370 | 0 | die_no_ass_del(tc, st); |
1371 | 76.5k | data = MVM_p6opaque_real_data(tc, data); |
1372 | 76.5k | del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->ass_del_slot]); |
1373 | 76.5k | REPR(del)->ass_funcs.delete_key(tc, STABLE(del), del, OBJECT_BODY(del), key); |
1374 | 76.5k | } |
1375 | | |
1376 | 483 | static MVMuint64 elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) { |
1377 | 483 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1378 | 483 | data = MVM_p6opaque_real_data(tc, data); |
1379 | 483 | if (repr_data->pos_del_slot >= 0) { |
1380 | 483 | MVMObject *del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]); |
1381 | 483 | return REPR(del)->elems(tc, STABLE(del), del, OBJECT_BODY(del)); |
1382 | 483 | } |
1383 | 0 | else if (repr_data->ass_del_slot >= 0) { |
1384 | 0 | MVMObject *del = get_obj_at_offset(data, repr_data->attribute_offsets[repr_data->ass_del_slot]); |
1385 | 0 | return REPR(del)->elems(tc, STABLE(del), del, OBJECT_BODY(del)); |
1386 | 0 | } |
1387 | 0 | else { |
1388 | 0 | MVM_exception_throw_adhoc(tc, "This type (%s) does not support elems", MVM_6model_get_stable_debug_name(tc, st)); |
1389 | 0 | } |
1390 | 483 | } |
1391 | | |
1392 | | /* Bytecode specialization for this REPR. */ |
1393 | 34.3k | static MVMString * spesh_attr_name(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand o, MVMint32 indirect) { |
1394 | 34.3k | if (indirect) { |
1395 | 1 | MVMSpeshFacts *name_facts = MVM_spesh_get_and_use_facts(tc, g, o); |
1396 | 1 | if (name_facts->flags & MVM_SPESH_FACT_KNOWN_VALUE) |
1397 | 1 | return name_facts->value.s; |
1398 | 1 | else |
1399 | 0 | return NULL; |
1400 | 1 | } |
1401 | 34.3k | else { |
1402 | 34.3k | return MVM_spesh_get_string(tc, g, o); |
1403 | 34.3k | } |
1404 | 34.3k | } |
1405 | 37.0k | static void spesh(MVMThreadContext *tc, MVMSTable *st, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) { |
1406 | 37.0k | MVMP6opaqueREPRData * repr_data = (MVMP6opaqueREPRData *)st->REPR_data; |
1407 | 37.0k | MVMuint16 opcode = ins->info->opcode; |
1408 | 37.0k | if (!repr_data) |
1409 | 0 | return; |
1410 | 37.0k | switch (opcode) { |
1411 | 748 | case MVM_OP_create: { |
1412 | 748 | /* Create can be optimized if there are no initialization slots. */ |
1413 | 748 | if (repr_data->initialize_slots[0] < 0 && !(st->mode_flags & MVM_FINALIZE_TYPE)) { |
1414 | 748 | MVMSpeshOperand target = ins->operands[0]; |
1415 | 748 | MVMSpeshOperand type = ins->operands[1]; |
1416 | 748 | ins->info = MVM_op_get_op(MVM_OP_sp_fastcreate); |
1417 | 748 | ins->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand)); |
1418 | 748 | ins->operands[0] = target; |
1419 | 748 | ins->operands[1].lit_i16 = st->size; |
1420 | 748 | ins->operands[2].lit_i16 = MVM_spesh_add_spesh_slot(tc, g, (MVMCollectable *)st); |
1421 | 748 | MVM_spesh_get_facts(tc, g, type)->usages--; |
1422 | 748 | } |
1423 | 748 | break; |
1424 | 748 | } |
1425 | 14.2k | case MVM_OP_getattr_o: |
1426 | 14.2k | case MVM_OP_getattrs_o: { |
1427 | 14.2k | MVMSpeshFacts *obj_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[1]); |
1428 | 14.2k | MVMSpeshFacts *ch_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[2]); |
1429 | 14.2k | MVMString *name = spesh_attr_name(tc, g, ins->operands[3], opcode == MVM_OP_getattrs_o); |
1430 | 14.2k | if (name && ch_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && ch_facts->type |
1431 | 13.7k | && obj_facts->flags & MVM_SPESH_FACT_CONCRETE) { |
1432 | 13.7k | MVMint64 slot = try_get_slot(tc, repr_data, ch_facts->type, name); |
1433 | 13.7k | if (slot >= 0 && !repr_data->flattened_stables[slot]) { |
1434 | 13.7k | if (repr_data->auto_viv_values && repr_data->auto_viv_values[slot]) { |
1435 | 12.9k | MVMObject *av_value = repr_data->auto_viv_values[slot]; |
1436 | 12.9k | if (IS_CONCRETE(av_value)) { |
1437 | 0 | ins->info = MVM_op_get_op(MVM_OP_sp_p6ogetvc_o); |
1438 | 0 | } |
1439 | 12.9k | else { |
1440 | 12.9k | ins->info = MVM_op_get_op(MVM_OP_sp_p6ogetvt_o); |
1441 | 12.9k | } |
1442 | 12.9k | if (opcode == MVM_OP_getattrs_o) |
1443 | 1 | MVM_spesh_get_facts(tc, g, ins->operands[3])->usages--; |
1444 | 12.9k | MVM_spesh_get_facts(tc, g, ins->operands[2])->usages--; |
1445 | 12.9k | ins->operands[2].lit_i16 = repr_data->attribute_offsets[slot]; |
1446 | 12.9k | ins->operands[3].lit_i16 = MVM_spesh_add_spesh_slot(tc, g, |
1447 | 12.9k | (MVMCollectable *)av_value); |
1448 | 12.9k | } |
1449 | 812 | else { |
1450 | 812 | if (opcode == MVM_OP_getattrs_o) |
1451 | 0 | MVM_spesh_get_facts(tc, g, ins->operands[3])->usages--; |
1452 | 812 | MVM_spesh_get_facts(tc, g, ins->operands[2])->usages--; |
1453 | 812 | ins->info = MVM_op_get_op(MVM_OP_sp_p6oget_o); |
1454 | 812 | ins->operands[2].lit_i16 = repr_data->attribute_offsets[slot]; |
1455 | 812 | MVM_spesh_manipulate_remove_handler_successors(tc, bb); |
1456 | 812 | } |
1457 | 13.7k | } |
1458 | 13.7k | } |
1459 | 14.2k | break; |
1460 | 14.2k | } |
1461 | 7.42k | case MVM_OP_getattr_i: |
1462 | 7.42k | case MVM_OP_getattrs_i: { |
1463 | 7.42k | MVMSpeshFacts *obj_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[1]); |
1464 | 7.42k | MVMSpeshFacts *ch_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[2]); |
1465 | 7.42k | MVMString *name = spesh_attr_name(tc, g, ins->operands[3], opcode == MVM_OP_getattrs_i); |
1466 | 7.42k | if (name && ch_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && ch_facts->type |
1467 | 7.05k | && obj_facts->flags & MVM_SPESH_FACT_CONCRETE) { |
1468 | 7.05k | MVMint64 slot = try_get_slot(tc, repr_data, ch_facts->type, name); |
1469 | 7.05k | if (slot >= 0 && repr_data->flattened_stables[slot]) { |
1470 | 7.05k | MVMSTable *flat_st = repr_data->flattened_stables[slot]; |
1471 | 7.05k | const MVMStorageSpec *flat_ss = flat_st->REPR->get_storage_spec(tc, flat_st); |
1472 | 7.05k | if (flat_st->REPR->ID == MVM_REPR_ID_P6int && flat_ss->bits == 64) { |
1473 | 7.05k | if (opcode == MVM_OP_getattrs_i) |
1474 | 0 | MVM_spesh_get_facts(tc, g, ins->operands[3])->usages--; |
1475 | 7.05k | MVM_spesh_get_facts(tc, g, ins->operands[2])->usages--; |
1476 | 7.05k | ins->info = MVM_op_get_op(MVM_OP_sp_p6oget_i); |
1477 | 7.05k | ins->operands[2].lit_i16 = repr_data->attribute_offsets[slot]; |
1478 | 7.05k | } |
1479 | 7.05k | } |
1480 | 7.05k | } |
1481 | 7.42k | break; |
1482 | 7.42k | } |
1483 | 1 | case MVM_OP_getattr_n: |
1484 | 1 | case MVM_OP_getattrs_n: { |
1485 | 1 | MVMSpeshFacts *obj_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[1]); |
1486 | 1 | MVMSpeshFacts *ch_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[2]); |
1487 | 1 | MVMString *name = spesh_attr_name(tc, g, ins->operands[3], opcode == MVM_OP_getattrs_n); |
1488 | 1 | if (name && ch_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && ch_facts->type |
1489 | 1 | && obj_facts->flags & MVM_SPESH_FACT_CONCRETE) { |
1490 | 1 | MVMint64 slot = try_get_slot(tc, repr_data, ch_facts->type, name); |
1491 | 1 | if (slot >= 0 && repr_data->flattened_stables[slot]) { |
1492 | 1 | MVMSTable *flat_st = repr_data->flattened_stables[slot]; |
1493 | 1 | const MVMStorageSpec *flat_ss = flat_st->REPR->get_storage_spec(tc, flat_st); |
1494 | 1 | if (flat_st->REPR->ID == MVM_REPR_ID_P6num && flat_ss->bits == 64) { |
1495 | 1 | if (opcode == MVM_OP_getattrs_n) |
1496 | 0 | MVM_spesh_get_facts(tc, g, ins->operands[3])->usages--; |
1497 | 1 | MVM_spesh_get_facts(tc, g, ins->operands[2])->usages--; |
1498 | 1 | ins->info = MVM_op_get_op(MVM_OP_sp_p6oget_n); |
1499 | 1 | ins->operands[2].lit_i16 = repr_data->attribute_offsets[slot]; |
1500 | 1 | } |
1501 | 1 | } |
1502 | 1 | } |
1503 | 1 | break; |
1504 | 1 | } |
1505 | 2.13k | case MVM_OP_getattr_s: |
1506 | 2.13k | case MVM_OP_getattrs_s: { |
1507 | 2.13k | MVMSpeshFacts *obj_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[1]); |
1508 | 2.13k | MVMSpeshFacts *ch_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[2]); |
1509 | 2.13k | MVMString *name = spesh_attr_name(tc, g, ins->operands[3], opcode == MVM_OP_getattrs_s); |
1510 | 2.13k | if (name && ch_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && ch_facts->type |
1511 | 2.13k | && obj_facts->flags & MVM_SPESH_FACT_CONCRETE) { |
1512 | 2.13k | MVMint64 slot = try_get_slot(tc, repr_data, ch_facts->type, name); |
1513 | 2.13k | if (slot >= 0 && repr_data->flattened_stables[slot]) { |
1514 | 2.13k | MVMSTable *flat_st = repr_data->flattened_stables[slot]; |
1515 | 2.13k | if (flat_st->REPR->ID == MVM_REPR_ID_P6str) { |
1516 | 2.13k | if (opcode == MVM_OP_getattrs_s) |
1517 | 0 | MVM_spesh_get_facts(tc, g, ins->operands[3])->usages--; |
1518 | 2.13k | MVM_spesh_get_facts(tc, g, ins->operands[2])->usages--; |
1519 | 2.13k | ins->info = MVM_op_get_op(MVM_OP_sp_p6oget_s); |
1520 | 2.13k | ins->operands[2].lit_i16 = repr_data->attribute_offsets[slot]; |
1521 | 2.13k | } |
1522 | 2.13k | } |
1523 | 2.13k | } |
1524 | 2.13k | break; |
1525 | 2.13k | } |
1526 | 5.23k | case MVM_OP_bindattr_o: |
1527 | 5.23k | case MVM_OP_bindattrs_o: { |
1528 | 5.23k | MVMSpeshFacts *obj_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[0]); |
1529 | 5.23k | MVMSpeshFacts *ch_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[1]); |
1530 | 5.23k | MVMString *name = spesh_attr_name(tc, g, ins->operands[2], opcode == MVM_OP_bindattrs_o); |
1531 | 5.23k | if (name && ch_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && ch_facts->type |
1532 | 4.91k | && obj_facts->flags & MVM_SPESH_FACT_CONCRETE) { |
1533 | 4.91k | MVMint64 slot = try_get_slot(tc, repr_data, ch_facts->type, name); |
1534 | 4.91k | if (slot >= 0 && !repr_data->flattened_stables[slot]) { |
1535 | 4.91k | if (opcode == MVM_OP_bindattrs_o) |
1536 | 0 | MVM_spesh_get_facts(tc, g, ins->operands[2])->usages--; |
1537 | 4.91k | MVM_spesh_get_facts(tc, g, ins->operands[1])->usages--; |
1538 | 4.91k | ins->info = MVM_op_get_op(MVM_OP_sp_p6obind_o); |
1539 | 4.91k | ins->operands[1].lit_i16 = repr_data->attribute_offsets[slot]; |
1540 | 4.91k | ins->operands[2] = ins->operands[3]; |
1541 | 4.91k | } |
1542 | 4.91k | } |
1543 | 5.23k | break; |
1544 | 5.23k | } |
1545 | 4.74k | case MVM_OP_bindattr_i: |
1546 | 4.74k | case MVM_OP_bindattrs_i: { |
1547 | 4.74k | MVMSpeshFacts *obj_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[0]); |
1548 | 4.74k | MVMSpeshFacts *ch_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[1]); |
1549 | 4.74k | MVMString *name = spesh_attr_name(tc, g, ins->operands[2], opcode == MVM_OP_bindattrs_i); |
1550 | 4.74k | if (name && ch_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && ch_facts->type |
1551 | 4.66k | && obj_facts->flags & MVM_SPESH_FACT_CONCRETE) { |
1552 | 4.66k | MVMint64 slot = try_get_slot(tc, repr_data, ch_facts->type, name); |
1553 | 4.66k | if (slot >= 0 && repr_data->flattened_stables[slot]) { |
1554 | 4.66k | MVMSTable *flat_st = repr_data->flattened_stables[slot]; |
1555 | 4.66k | const MVMStorageSpec *flat_ss = flat_st->REPR->get_storage_spec(tc, flat_st); |
1556 | 4.66k | if (flat_st->REPR->ID == MVM_REPR_ID_P6int && flat_ss->bits == 64) { |
1557 | 4.66k | if (opcode == MVM_OP_bindattrs_i) |
1558 | 0 | MVM_spesh_get_facts(tc, g, ins->operands[2])->usages--; |
1559 | 4.66k | MVM_spesh_get_facts(tc, g, ins->operands[1])->usages--; |
1560 | 4.66k | ins->info = MVM_op_get_op(MVM_OP_sp_p6obind_i); |
1561 | 4.66k | ins->operands[1].lit_i16 = repr_data->attribute_offsets[slot]; |
1562 | 4.66k | ins->operands[2] = ins->operands[3]; |
1563 | 4.66k | } |
1564 | 4.66k | } |
1565 | 4.66k | } |
1566 | 4.74k | break; |
1567 | 4.74k | } |
1568 | 3 | case MVM_OP_bindattr_n: |
1569 | 3 | case MVM_OP_bindattrs_n: { |
1570 | 3 | MVMSpeshFacts *obj_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[0]); |
1571 | 3 | MVMSpeshFacts *ch_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[1]); |
1572 | 3 | MVMString *name = spesh_attr_name(tc, g, ins->operands[2], opcode == MVM_OP_bindattrs_n); |
1573 | 3 | if (name && ch_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && ch_facts->type |
1574 | 3 | && obj_facts->flags & MVM_SPESH_FACT_CONCRETE) { |
1575 | 3 | MVMint64 slot = try_get_slot(tc, repr_data, ch_facts->type, name); |
1576 | 3 | if (slot >= 0 && repr_data->flattened_stables[slot]) { |
1577 | 3 | MVMSTable *flat_st = repr_data->flattened_stables[slot]; |
1578 | 3 | const MVMStorageSpec *flat_ss = flat_st->REPR->get_storage_spec(tc, flat_st); |
1579 | 3 | if (flat_st->REPR->ID == MVM_REPR_ID_P6num && flat_ss->bits == 64) { |
1580 | 3 | if (opcode == MVM_OP_bindattrs_n) |
1581 | 0 | MVM_spesh_get_facts(tc, g, ins->operands[2])->usages--; |
1582 | 3 | MVM_spesh_get_facts(tc, g, ins->operands[1])->usages--; |
1583 | 3 | ins->info = MVM_op_get_op(MVM_OP_sp_p6obind_n); |
1584 | 3 | ins->operands[1].lit_i16 = repr_data->attribute_offsets[slot]; |
1585 | 3 | ins->operands[2] = ins->operands[3]; |
1586 | 3 | } |
1587 | 3 | } |
1588 | 3 | } |
1589 | 3 | break; |
1590 | 3 | } |
1591 | 548 | case MVM_OP_bindattr_s: |
1592 | 548 | case MVM_OP_bindattrs_s: { |
1593 | 548 | MVMSpeshFacts *obj_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[0]); |
1594 | 548 | MVMSpeshFacts *ch_facts = MVM_spesh_get_and_use_facts(tc, g, ins->operands[1]); |
1595 | 548 | MVMString *name = spesh_attr_name(tc, g, ins->operands[2], opcode == MVM_OP_bindattrs_s); |
1596 | 548 | if (name && ch_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && ch_facts->type |
1597 | 547 | && obj_facts->flags & MVM_SPESH_FACT_CONCRETE) { |
1598 | 547 | MVMint64 slot = try_get_slot(tc, repr_data, ch_facts->type, name); |
1599 | 547 | if (slot >= 0 && repr_data->flattened_stables[slot]) { |
1600 | 547 | MVMSTable *flat_st = repr_data->flattened_stables[slot]; |
1601 | 547 | if (flat_st->REPR->ID == MVM_REPR_ID_P6str) { |
1602 | 547 | if (opcode == MVM_OP_bindattrs_s) |
1603 | 0 | MVM_spesh_get_facts(tc, g, ins->operands[2])->usages--; |
1604 | 547 | MVM_spesh_get_facts(tc, g, ins->operands[1])->usages--; |
1605 | 547 | ins->info = MVM_op_get_op(MVM_OP_sp_p6obind_s); |
1606 | 547 | ins->operands[1].lit_i16 = repr_data->attribute_offsets[slot]; |
1607 | 547 | ins->operands[2] = ins->operands[3]; |
1608 | 547 | } |
1609 | 547 | } |
1610 | 547 | } |
1611 | 548 | break; |
1612 | 548 | } |
1613 | 37.0k | } |
1614 | 37.0k | } |
1615 | | |
1616 | | /* Initializes the representation. */ |
1617 | 144 | const MVMREPROps * MVMP6opaque_initialize(MVMThreadContext *tc) { |
1618 | 144 | return &P6opaque_this_repr; |
1619 | 144 | } |
1620 | | |
1621 | | static const MVMREPROps P6opaque_this_repr = { |
1622 | | type_object_for, |
1623 | | allocate, |
1624 | | initialize, |
1625 | | copy_to, |
1626 | | { |
1627 | | get_attribute, |
1628 | | bind_attribute, |
1629 | | hint_for, |
1630 | | is_attribute_initialized, |
1631 | | attribute_as_atomic |
1632 | | }, /* attr_funcs */ |
1633 | | { |
1634 | | set_int, |
1635 | | get_int, |
1636 | | set_num, |
1637 | | get_num, |
1638 | | set_str, |
1639 | | get_str, |
1640 | | set_uint, |
1641 | | get_uint, |
1642 | | get_boxed_ref |
1643 | | }, /* box_funcs */ |
1644 | | { |
1645 | | at_pos, |
1646 | | bind_pos, |
1647 | | set_elems, |
1648 | | push, |
1649 | | pop, |
1650 | | unshift, |
1651 | | shift, |
1652 | | oslice, |
1653 | | osplice, |
1654 | | MVM_REPR_DEFAULT_AT_POS_MULTIDIM, |
1655 | | MVM_REPR_DEFAULT_BIND_POS_MULTIDIM, |
1656 | | MVM_REPR_DEFAULT_DIMENSIONS, |
1657 | | MVM_REPR_DEFAULT_SET_DIMENSIONS, |
1658 | | MVM_REPR_DEFAULT_GET_ELEM_STORAGE_SPEC, |
1659 | | MVM_REPR_DEFAULT_POS_AS_ATOMIC, |
1660 | | MVM_REPR_DEFAULT_POS_AS_ATOMIC_MULTIDIM |
1661 | | }, /* pos_funcs */ |
1662 | | { |
1663 | | at_key, |
1664 | | bind_key, |
1665 | | exists_key, |
1666 | | delete_key, |
1667 | | NULL |
1668 | | }, /* ass_funcs */ |
1669 | | elems, |
1670 | | get_storage_spec, |
1671 | | change_type, |
1672 | | serialize, |
1673 | | deserialize, /* deserialize */ |
1674 | | serialize_repr_data, |
1675 | | deserialize_repr_data, |
1676 | | deserialize_stable_size, |
1677 | | gc_mark, |
1678 | | gc_free, |
1679 | | NULL, /* gc_cleanup */ |
1680 | | gc_mark_repr_data, |
1681 | | gc_free_repr_data, |
1682 | | compose, |
1683 | | spesh, |
1684 | | "P6opaque", /* name */ |
1685 | | MVM_REPR_ID_P6opaque, |
1686 | | NULL, /* unmanaged_size */ |
1687 | | NULL, /* describe_refs */ |
1688 | | }; |
1689 | | |
1690 | | /* Get the pointer offset of an attribute. Used for optimizing access to it on |
1691 | | * precisely known types. */ |
1692 | | size_t MVM_p6opaque_attr_offset(MVMThreadContext *tc, MVMObject *type, |
1693 | 714 | MVMObject *class_handle, MVMString *name) { |
1694 | 714 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)type->st->REPR_data; |
1695 | 714 | size_t slot = try_get_slot(tc, repr_data, class_handle, name); |
1696 | 714 | return repr_data->attribute_offsets[slot]; |
1697 | 714 | } |
1698 | | |
1699 | | #ifdef DEBUG_HELPERS |
1700 | | /* This is meant to be called in a debugging session and not used anywhere else. |
1701 | | * Plese don't delete. */ |
1702 | 0 | static void dump_p6opaque(MVMThreadContext *tc, MVMObject *obj, int nested) { |
1703 | 0 | MVMP6opaqueREPRData *repr_data = (MVMP6opaqueREPRData *)STABLE(obj)->REPR_data; |
1704 | 0 | MVMP6opaqueBody *data = MVM_p6opaque_real_data(tc, OBJECT_BODY(obj)); |
1705 | 0 | if (repr_data) { |
1706 | 0 | MVMint16 const num_attributes = repr_data->num_attributes; |
1707 | 0 | MVMint16 cur_attribute = 0; |
1708 | 0 | MVMP6opaqueNameMap * const name_to_index_mapping = repr_data->name_to_index_mapping; |
1709 | 0 | if (!IS_CONCRETE(obj)) { |
1710 | 0 | fprintf(stderr, "(%s", MVM_6model_get_debug_name(tc, obj)); |
1711 | 0 | fprintf(stderr, nested ? ")" : ")\n"); |
1712 | 0 | return; |
1713 | 0 | } |
1714 | 0 | fprintf(stderr, "%s.new(", MVM_6model_get_debug_name(tc, obj)); |
1715 | 0 | if (name_to_index_mapping != NULL) { |
1716 | 0 | MVMint16 i; |
1717 | 0 | MVMP6opaqueNameMap *cur_map_entry = name_to_index_mapping; |
1718 | 0 |
|
1719 | 0 | while (cur_map_entry->class_key != NULL) { |
1720 | 0 | MVMint16 i; |
1721 | 0 | MVMint64 slot; |
1722 | 0 | if (cur_map_entry->num_attrs > 0) { |
1723 | 0 | fprintf(stderr, "#`(from %s) ", MVM_6model_get_stable_debug_name(tc, cur_map_entry->class_key->st)); |
1724 | 0 | } |
1725 | 0 | for (i = 0; i < cur_map_entry->num_attrs; i++) { |
1726 | 0 | char * name = MVM_string_utf8_encode_C_string(tc, cur_map_entry->names[i]); |
1727 | 0 | fprintf(stderr, "%s", name); |
1728 | 0 | MVM_free(name); |
1729 | 0 |
|
1730 | 0 | slot = cur_map_entry->slots[i]; |
1731 | 0 | if (slot >= 0) { |
1732 | 0 | MVMuint16 const offset = repr_data->attribute_offsets[slot]; |
1733 | 0 | MVMSTable * const attr_st = repr_data->flattened_stables[slot]; |
1734 | 0 | if (attr_st == NULL) { |
1735 | 0 | MVMObject *value = get_obj_at_offset(data, offset); |
1736 | 0 | if (value != NULL) { |
1737 | 0 | fprintf(stderr, "="); |
1738 | 0 | dump_p6opaque(tc, value, 1); |
1739 | 0 | } |
1740 | 0 | } |
1741 | 0 | else { |
1742 | 0 | if (attr_st->REPR->ID == MVM_REPR_ID_P6str) { |
1743 | 0 | char * const str = MVM_string_utf8_encode_C_string(tc, (MVMString *)get_obj_at_offset(data, offset)); |
1744 | 0 | fprintf(stderr, "='%s'", str); |
1745 | 0 | MVM_free(str); |
1746 | 0 | } |
1747 | 0 | else if (attr_st->REPR->ID == MVM_REPR_ID_P6int) { |
1748 | 0 | MVMint64 val = attr_st->REPR->box_funcs.get_int(tc, attr_st, obj, (char *)data + offset); |
1749 | 0 | fprintf(stderr, "=%ld", val); |
1750 | 0 | } |
1751 | 0 | else { |
1752 | 0 | fprintf(stderr, "[%d]=%s", repr_data->attribute_offsets[slot], MVM_6model_get_stable_debug_name(tc, attr_st)); |
1753 | 0 | } |
1754 | 0 | /*MVMString * const s = attr_st->REPR->box_funcs.get_str(tc, attr_st, obj, (char *)data + offset);*/ |
1755 | 0 | /*char * const str = MVM_string_utf8_encode_C_string(tc, s);*/ |
1756 | 0 | /*fprintf(stderr, "='%s'", str);*/ |
1757 | 0 | /*MVM_free(str);*/ |
1758 | 0 | } |
1759 | 0 | } |
1760 | 0 | if (cur_attribute++ < num_attributes - 1) |
1761 | 0 | fprintf(stderr, ", "); |
1762 | 0 | } |
1763 | 0 | cur_map_entry++; |
1764 | 0 | } |
1765 | 0 | } |
1766 | 0 | fprintf(stderr, nested ? ")" : ")\n"); |
1767 | 0 | } |
1768 | 0 | else { |
1769 | 0 | fprintf(stderr, "%s%s", MVM_6model_get_debug_name(tc, obj), nested ? "" : "\n"); |
1770 | 0 | } |
1771 | 0 | } |
1772 | | |
1773 | 0 | void MVM_dump_p6opaque(MVMThreadContext *tc, MVMObject *obj) { |
1774 | 0 | dump_p6opaque(tc, obj, 0); |
1775 | 0 | } |
1776 | | #endif |