Coverage Report

Created: 2017-04-15 07:07

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