Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/6model/reprs/CPPStruct.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* This representation's function pointer table. */
4
static const MVMREPROps CPPStruct_this_repr;
5
6
/* Locates all of the attributes. Puts them onto a flattened, ordered
7
 * list of attributes (populating the passed flat_list). Also builds
8
 * the index mapping for doing named lookups. Note index is not related
9
 * to the storage position. */
10
static MVMObject * index_mapping_and_flat_list(MVMThreadContext *tc, MVMObject *mro,
11
0
         MVMCPPStructREPRData *repr_data, MVMSTable *st) {
12
0
    MVMInstance *instance  = tc->instance;
13
0
    MVMObject *flat_list, *class_list, *attr_map_list;
14
0
    MVMint32  num_classes, i, current_slot = 0;
15
0
    MVMCPPStructNameMap *result;
16
0
17
0
    MVMint32 mro_idx = MVM_repr_elems(tc, mro);
18
0
19
0
    MVM_gc_root_temp_push(tc, (MVMCollectable **)&st);
20
0
    MVM_gc_root_temp_push(tc, (MVMCollectable **)&mro);
21
0
22
0
    flat_list = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_array_type);
23
0
    MVM_gc_root_temp_push(tc, (MVMCollectable **)&flat_list);
24
0
25
0
    class_list = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_array_type);
26
0
    MVM_gc_root_temp_push(tc, (MVMCollectable **)&class_list);
27
0
28
0
    attr_map_list = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_array_type);
29
0
    MVM_gc_root_temp_push(tc, (MVMCollectable **)&attr_map_list);
30
0
31
0
    /* Walk through the parents list. */
32
0
    while (mro_idx)
33
0
    {
34
0
        /* Get current class in MRO. */
35
0
        MVMObject *type_info     = MVM_repr_at_pos_o(tc, mro, --mro_idx);
36
0
        MVMObject *current_class = MVM_repr_at_pos_o(tc, type_info, 0);
37
0
38
0
        /* Get its local parents; make sure we're not doing MI. */
39
0
        MVMObject *parents     = MVM_repr_at_pos_o(tc, type_info, 2);
40
0
        MVMint32  num_parents = MVM_repr_elems(tc, parents);
41
0
        if (num_parents <= 1) {
42
0
            /* Get attributes and iterate over them. */
43
0
            MVMObject *attributes     = MVM_repr_at_pos_o(tc, type_info, 1);
44
0
            MVMIter * const attr_iter = (MVMIter *)MVM_iter(tc, attributes);
45
0
            MVMObject *attr_map = NULL;
46
0
47
0
            if (MVM_iter_istrue(tc, attr_iter)) {
48
0
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&attr_iter);
49
0
                attr_map = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_hash_type);
50
0
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&attr_map);
51
0
            }
52
0
53
0
            while (MVM_iter_istrue(tc, attr_iter)) {
54
0
                MVMObject *current_slot_obj = MVM_repr_box_int(tc, MVM_hll_current(tc)->int_box_type, current_slot);
55
0
                MVMObject *attr, *name_obj;
56
0
                MVMString *name;
57
0
58
0
                MVM_repr_shift_o(tc, (MVMObject *)attr_iter);
59
0
60
0
                /* Get attribute. */
61
0
                attr = MVM_iterval(tc, attr_iter);
62
0
63
0
                /* Get its name. */
64
0
                name_obj = MVM_repr_at_key_o(tc, attr, instance->str_consts.name);
65
0
                name     = MVM_repr_get_str(tc, name_obj);
66
0
67
0
                MVM_repr_bind_key_o(tc, attr_map, name, current_slot_obj);
68
0
69
0
                current_slot++;
70
0
71
0
                /* Push attr onto the flat list. */
72
0
                MVM_repr_push_o(tc, flat_list, attr);
73
0
            }
74
0
75
0
            if (attr_map) {
76
0
                MVM_gc_root_temp_pop_n(tc, 2);
77
0
            }
78
0
79
0
            /* Add to class list and map list. */
80
0
            MVM_repr_push_o(tc, class_list, current_class);
81
0
            MVM_repr_push_o(tc, attr_map_list, attr_map);
82
0
        }
83
0
        else {
84
0
            MVM_exception_throw_adhoc(tc,
85
0
                "CPPStruct representation does not support multiple inheritance");
86
0
        }
87
0
    }
88
0
89
0
    MVM_gc_root_temp_pop_n(tc, 5);
90
0
91
0
    /* We can now form the name map. */
92
0
    num_classes = MVM_repr_elems(tc, class_list);
93
0
    result = (MVMCPPStructNameMap *) MVM_malloc(sizeof(MVMCPPStructNameMap) * (1 + num_classes));
94
0
95
0
    for (i = 0; i < num_classes; i++) {
96
0
        MVM_ASSIGN_REF(tc, &(st->header), result[i].class_key,
97
0
            MVM_repr_at_pos_o(tc, class_list, i));
98
0
        MVM_ASSIGN_REF(tc, &(st->header), result[i].name_map,
99
0
            MVM_repr_at_pos_o(tc, attr_map_list, i));
100
0
    }
101
0
102
0
    /* set the end to be NULL, it's useful for iteration. */
103
0
    result[i].class_key = NULL;
104
0
105
0
    repr_data->name_to_index_mapping = result;
106
0
107
0
    return flat_list;
108
0
}
109
110
0
static MVMint32 round_up_to_multi(MVMint32 i, MVMint32 m) {
111
0
    return (MVMint32)((i + m - 1) / m) * m;
112
0
}
113
114
/* This works out an allocation strategy for the object. It takes care of
115
 * "inlining" storage of attributes that are natively typed, as well as
116
 * noting unbox targets. */
117
static void compute_allocation_strategy(MVMThreadContext *tc, MVMSTable *st,
118
0
                                        MVMObject *repr_info, MVMCPPStructREPRData *repr_data) {
119
0
    /* Compute index mapping table and get flat list of attributes. */
120
0
    MVMObject *flat_list;
121
0
    MVMROOT(tc, st, {
122
0
        flat_list = index_mapping_and_flat_list(tc, repr_info, repr_data, st);
123
0
    });
124
0
125
0
    /* If we have no attributes in the index mapping, then just the header. */
126
0
    if (repr_data->name_to_index_mapping[0].class_key == NULL) {
127
0
        repr_data->struct_size = 1; /* avoid 0-byte malloc */
128
0
        repr_data->struct_align = ALIGNOF(void *);
129
0
    }
130
0
131
0
    /* Otherwise, we need to compute the allocation strategy.  */
132
0
    else {
133
0
        /* We track the size of the struct, which is what we'll want offsets into. */
134
0
        MVMint32 cur_size    = 0;
135
0
        MVMint32 struct_size = 0;
136
0
137
0
        /* Get number of attributes and set up various counters. */
138
0
        MVMint32 num_attrs        = MVM_repr_elems(tc, flat_list);
139
0
        MVMint32 info_alloc       = num_attrs == 0 ? 1 : num_attrs;
140
0
        MVMint32 cur_obj_attr     = 0;
141
0
        MVMint32 cur_init_slot    = 0;
142
0
        MVMint32 i;
143
0
144
0
        /* Allocate location/offset arrays and GC mark info arrays. */
145
0
        repr_data->num_attributes      = num_attrs;
146
0
        repr_data->attribute_locations = (MVMint32 *)   MVM_malloc(info_alloc * sizeof(MVMint32));
147
0
        repr_data->struct_offsets      = (MVMint32 *)   MVM_malloc(info_alloc * sizeof(MVMint32));
148
0
        repr_data->flattened_stables   = (MVMSTable **) MVM_calloc(info_alloc, sizeof(MVMObject *));
149
0
        repr_data->member_types        = (MVMObject **) MVM_calloc(info_alloc, sizeof(MVMObject *));
150
0
        repr_data->struct_align        = 0;
151
0
152
0
        /* Go over the attributes and arrange their allocation. */
153
0
        for (i = 0; i < num_attrs; i++) {
154
0
            /* Fetch its type; see if it's some kind of unboxed type. */
155
0
            MVMObject *attr  = MVM_repr_at_pos_o(tc, flat_list, i);
156
0
            MVMObject *type  = MVM_repr_at_key_o(tc, attr, tc->instance->str_consts.type);
157
0
            MVMObject *inlined_val = MVM_repr_at_key_o(tc, attr, tc->instance->str_consts.inlined);
158
0
            MVMObject *dimensions         = MVM_repr_at_key_o(tc, attr, tc->instance->str_consts.dimensions);
159
0
            MVMP6opaqueREPRData *dim_repr = (MVMP6opaqueREPRData *)STABLE(dimensions)->REPR_data;
160
0
            MVMint64 num_dimensions       = dim_repr && dim_repr->pos_del_slot >= 0
161
0
                                          ? MVM_repr_elems(tc, dimensions)
162
0
                                          : 0;
163
0
            MVMint64 inlined = !MVM_is_null(tc, inlined_val) && MVM_repr_get_int(tc, inlined_val);
164
0
            MVMint32   bits  = sizeof(void *) * 8;
165
0
            MVMint32   align = ALIGNOF(void *);
166
0
167
0
            if (num_dimensions > 1) {
168
0
                MVM_exception_throw_adhoc(tc,
169
0
                    "Only one dimensions supported in CPPStruct attribute");
170
0
            }
171
0
172
0
            if (!MVM_is_null(tc, type)) {
173
0
                /* See if it's a type that we know how to handle in a C struct. */
174
0
                const MVMStorageSpec *spec = REPR(type)->get_storage_spec(tc, STABLE(type));
175
0
                MVMint32  type_id    = REPR(type)->ID;
176
0
                if (spec->inlineable == MVM_STORAGE_SPEC_INLINED &&
177
0
                        (spec->boxed_primitive == MVM_STORAGE_SPEC_BP_INT ||
178
0
                         spec->boxed_primitive == MVM_STORAGE_SPEC_BP_NUM)) {
179
0
                    /* It's a boxed int or num; pretty easy. It'll just live in the
180
0
                     * body of the struct. Instead of masking in i here (which
181
0
                     * would be the parallel to how we handle boxed types) we
182
0
                     * repurpose it to store the bit-width of the type, so
183
0
                     * that get_attribute_ref can find it later. */
184
0
                    bits = spec->bits;
185
0
                    align = spec->align;
186
0
187
0
                    repr_data->attribute_locations[i] = (bits << MVM_CPPSTRUCT_ATTR_SHIFT)
188
0
                        | MVM_CPPSTRUCT_ATTR_IN_STRUCT;
189
0
                    MVM_ASSIGN_REF(tc, &(st->header), repr_data->flattened_stables[i],
190
0
                        STABLE(type));
191
0
                    if (REPR(type)->initialize) {
192
0
                        if (!repr_data->initialize_slots)
193
0
                            repr_data->initialize_slots = (MVMint32 *) MVM_calloc(
194
0
                                info_alloc + 1, sizeof(MVMint32));
195
0
                        repr_data->initialize_slots[cur_init_slot] = i;
196
0
                        cur_init_slot++;
197
0
                    }
198
0
                }
199
0
                else if (spec->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR) {
200
0
                    /* It's a string of some kind.  */
201
0
                    repr_data->num_child_objs++;
202
0
                    repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CPPSTRUCT_ATTR_SHIFT)
203
0
                        | MVM_CPPSTRUCT_ATTR_STRING;
204
0
                    MVM_ASSIGN_REF(tc, &(st->header), repr_data->member_types[i], type);
205
0
                    MVM_ASSIGN_REF(tc, &(st->header), repr_data->flattened_stables[i],
206
0
                        STABLE(type));
207
0
                    if (REPR(type)->initialize) {
208
0
                        if (!repr_data->initialize_slots)
209
0
                            repr_data->initialize_slots = (MVMint32 *) MVM_calloc(info_alloc + 1, sizeof(MVMint32));
210
0
                        repr_data->initialize_slots[cur_init_slot] = i;
211
0
                        cur_init_slot++;
212
0
                    }
213
0
                }
214
0
                else if (type_id == MVM_REPR_ID_MVMCArray) {
215
0
                    /* It's a CArray of some kind.  */
216
0
                    repr_data->num_child_objs++;
217
0
                    repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CPPSTRUCT_ATTR_SHIFT) | MVM_CPPSTRUCT_ATTR_CARRAY;
218
0
                    MVM_ASSIGN_REF(tc, &(st->header), repr_data->member_types[i], type);
219
0
                    if (inlined) {
220
0
                        MVMCArrayREPRData *carray_repr_data = (MVMCArrayREPRData *)STABLE(type)->REPR_data;
221
0
                        bits                                = carray_repr_data->elem_size * 8;
222
0
                        repr_data->attribute_locations[i]  |= MVM_CSTRUCT_ATTR_INLINED;
223
0
224
0
                        if (num_dimensions > 0) {
225
0
                            MVMint64 dim_one =  MVM_repr_at_pos_i(tc, dimensions, 0);
226
0
227
0
                            // How do we distinguish between these members:
228
0
                            // a) struct  foo [32] alias;
229
0
                            // b) struct *foo [32] alias;
230
0
                            if (carray_repr_data->elem_kind == MVM_CARRAY_ELEM_KIND_CSTRUCT) {
231
0
                                MVMCStructREPRData *cstruct_repr_data = (MVMCStructREPRData *)STABLE(carray_repr_data->elem_type)->REPR_data;
232
0
                                bits                                  = cstruct_repr_data->struct_size * 8 * dim_one;
233
0
                                align                                 = cstruct_repr_data->struct_align;
234
0
                            }
235
0
                            else {
236
0
                                bits  = bits * dim_one;
237
0
                            }
238
0
                        }
239
0
                    }
240
0
                }
241
0
                else if (type_id == MVM_REPR_ID_MVMCStruct) {
242
0
                    /* It's a CStruct. */
243
0
                    repr_data->num_child_objs++;
244
0
                    repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CPPSTRUCT_ATTR_SHIFT) | MVM_CPPSTRUCT_ATTR_CSTRUCT;
245
0
                    MVM_ASSIGN_REF(tc, &(st->header), repr_data->member_types[i], type);
246
0
                    if (inlined) {
247
0
                        MVMCStructREPRData *cstruct_repr_data = (MVMCStructREPRData *)STABLE(type)->REPR_data;
248
0
                        bits                                  = cstruct_repr_data->struct_size * 8;
249
0
                        align                                 = cstruct_repr_data->struct_align;
250
0
                        repr_data->attribute_locations[i]    |= MVM_CSTRUCT_ATTR_INLINED;
251
0
                    }
252
0
                }
253
0
                else if (type_id == MVM_REPR_ID_MVMCPPStruct) {
254
0
                    /* It's a CPPStruct. */
255
0
                    repr_data->num_child_objs++;
256
0
                    repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CPPSTRUCT_ATTR_SHIFT) | MVM_CPPSTRUCT_ATTR_CPPSTRUCT;
257
0
                    MVM_ASSIGN_REF(tc, &(st->header), repr_data->member_types[i], type);
258
0
                    if (inlined) {
259
0
                        MVMCPPStructREPRData *cppstruct_repr_data = (MVMCPPStructREPRData *)STABLE(type)->REPR_data;
260
0
                        bits                                      = cppstruct_repr_data->struct_size * 8;
261
0
                        align                                     = cppstruct_repr_data->struct_align;
262
0
                        repr_data->attribute_locations[i]        |= MVM_CPPSTRUCT_ATTR_INLINED;
263
0
                    }
264
0
                }
265
0
                else if (type_id == MVM_REPR_ID_MVMCUnion) {
266
0
                    /* It's a CUnion. */
267
0
                    repr_data->num_child_objs++;
268
0
                    repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CSTRUCT_ATTR_SHIFT) | MVM_CSTRUCT_ATTR_CUNION;
269
0
                    MVM_ASSIGN_REF(tc, &(st->header), repr_data->member_types[i], type);
270
0
                    if (inlined) {
271
0
                        MVMCUnionREPRData *cunion_repr_data = (MVMCUnionREPRData *)STABLE(type)->REPR_data;
272
0
                        bits                                = cunion_repr_data->struct_size * 8;
273
0
                        align                               = cunion_repr_data->struct_align;
274
0
                        repr_data->attribute_locations[i]  |= MVM_CSTRUCT_ATTR_INLINED;
275
0
                    }
276
0
                }
277
0
                else if (type_id == MVM_REPR_ID_MVMCPointer) {
278
0
                    /* It's a CPointer. */
279
0
                    repr_data->num_child_objs++;
280
0
                    repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CPPSTRUCT_ATTR_SHIFT) | MVM_CPPSTRUCT_ATTR_CPTR;
281
0
                    MVM_ASSIGN_REF(tc, &(st->header), repr_data->member_types[i], type);
282
0
                }
283
0
                else {
284
0
                    MVM_exception_throw_adhoc(tc,
285
0
                        "CPPStruct representation only handles attributes of type:\n"
286
0
                        "  (u)int8, (u)int16, (u)int32, (u)int64, (u)long, (u)longlong, num32, num64, (s)size_t, bool, Str\n"
287
0
                        "  and types with representation: CArray, CPointer, CStruct, CPPStruct and CUnion");
288
0
                }
289
0
            }
290
0
            else {
291
0
                MVM_exception_throw_adhoc(tc,
292
0
                    "CPPStruct representation requires the types of all attributes to be specified");
293
0
            }
294
0
295
0
            if (bits % 8) {
296
0
                 MVM_exception_throw_adhoc(tc,
297
0
                    "CPPStruct only supports native types that are a multiple of 8 bits wide (was passed: %"PRId32")", bits);
298
0
            }
299
0
300
0
            /* Do allocation. */
301
0
            /* C structure needs careful alignment. If cur_size is not aligned
302
0
             * to align bytes (cur_size % align), make sure it is before we
303
0
             * add the next element. */
304
0
            if (cur_size % align) {
305
0
                cur_size += align - cur_size % align;
306
0
            }
307
0
308
0
            if (align > repr_data->struct_align)
309
0
                repr_data->struct_align = align;
310
0
311
0
            repr_data->struct_offsets[i] = cur_size;
312
0
            cur_size += bits / 8;
313
0
314
0
            struct_size = round_up_to_multi(struct_size, align) + bits/8;
315
0
        }
316
0
317
0
        /* Finally, put computed allocation size in place; it's body size plus
318
0
         * header size. Also number of markables and sentinels. */
319
0
        repr_data->struct_size = round_up_to_multi(struct_size, repr_data->struct_align);
320
0
        if (repr_data->initialize_slots)
321
0
            repr_data->initialize_slots[cur_init_slot] = -1;
322
0
    }
323
0
}
324
325
/* Helper for reading a pointer at the specified offset. */
326
0
static void * get_ptr_at_offset(void *data, MVMint32 offset) {
327
0
    void *location = (char *)data + offset;
328
0
    return *((void **)location);
329
0
}
330
331
/* Helper for writing a pointer at the specified offset. */
332
0
static void set_ptr_at_offset(void *data, MVMint32 offset, void *value) {
333
0
    void *location = (char *)data + offset;
334
0
    *((void **)location) = value;
335
0
}
336
337
/* Helper for finding a slot number. */
338
0
static MVMint32 try_get_slot(MVMThreadContext *tc, MVMCPPStructREPRData *repr_data, MVMObject *class_key, MVMString *name) {
339
0
    if (repr_data->name_to_index_mapping) {
340
0
        MVMCPPStructNameMap *cur_map_entry = repr_data->name_to_index_mapping;
341
0
        while (cur_map_entry->class_key != NULL) {
342
0
            if (cur_map_entry->class_key == class_key) {
343
0
                MVMObject *slot_obj = MVM_repr_at_key_o(tc, cur_map_entry->name_map, name);
344
0
                if (IS_CONCRETE(slot_obj))
345
0
                    return MVM_repr_get_int(tc, slot_obj);
346
0
                break;
347
0
            }
348
0
            cur_map_entry++;
349
0
        }
350
0
    }
351
0
    return -1;
352
0
}
353
354
/* Creates a new type object of this representation, and associates it with
355
 * the given HOW. */
356
0
static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
357
0
    MVMSTable *st  = MVM_gc_allocate_stable(tc, &CPPStruct_this_repr, HOW);
358
0
359
0
    MVMROOT(tc, st, {
360
0
        MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
361
0
        MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj);
362
0
        st->size = sizeof(MVMCPPStruct);
363
0
    });
364
0
365
0
    return st->WHAT;
366
0
}
367
368
/* Composes the representation. */
369
0
static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *repr_info) {
370
0
    /* Compute allocation strategy. */
371
0
    MVMCPPStructREPRData *repr_data = MVM_calloc(1, sizeof(MVMCPPStructREPRData));
372
0
    MVMObject *attr_info = MVM_repr_at_key_o(tc, repr_info, tc->instance->str_consts.attribute);
373
0
    compute_allocation_strategy(tc, st, attr_info, repr_data);
374
0
    st->REPR_data = repr_data;
375
0
}
376
377
/* Initialize a new instance. */
378
0
static void initialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) {
379
0
    MVMCPPStructREPRData * repr_data = (MVMCPPStructREPRData *)st->REPR_data;
380
0
381
0
    /* Allocate object body. */
382
0
    MVMCPPStructBody *body = (MVMCPPStructBody *)data;
383
0
    body->cppstruct = MVM_calloc(1, repr_data->struct_size > 0 ? repr_data->struct_size : 1);
384
0
385
0
    /* Allocate child obj array. */
386
0
    if (repr_data->num_child_objs > 0)
387
0
        body->child_objs = (MVMObject **)MVM_calloc(repr_data->num_child_objs,
388
0
            sizeof(MVMObject *));
389
0
390
0
    /* Initialize the slots. */
391
0
    if (repr_data->initialize_slots) {
392
0
        MVMint32 i;
393
0
        for (i = 0; repr_data->initialize_slots[i] >= 0; i++) {
394
0
            MVMint32  offset = repr_data->struct_offsets[repr_data->initialize_slots[i]];
395
0
            MVMSTable *st     = repr_data->flattened_stables[repr_data->initialize_slots[i]];
396
0
            st->REPR->initialize(tc, st, root, (char *)body->cppstruct + offset);
397
0
        }
398
0
    }
399
0
}
400
401
/* Copies to the body of one object to another. */
402
0
static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) {
403
0
    MVM_exception_throw_adhoc(tc, "cloning a CPPStruct is NYI");
404
0
}
405
406
/* Helper for complaining about attribute access errors. */
407
MVM_NO_RETURN static void no_such_attribute(MVMThreadContext *tc, const char *action, MVMObject *class_handle, MVMString *name) MVM_NO_RETURN_ATTRIBUTE;
408
0
static void no_such_attribute(MVMThreadContext *tc, const char *action, MVMObject *class_handle, MVMString *name) {
409
0
    char *c_name = MVM_string_utf8_encode_C_string(tc, name);
410
0
    char *waste[] = { c_name, NULL };
411
0
    MVM_exception_throw_adhoc_free(tc, waste, "Can not %s non-existent attribute '%s'",
412
0
        action, c_name);
413
0
}
414
415
/* Helper to die because this type doesn't support attributes. */
416
MVM_NO_RETURN static void die_no_attrs(MVMThreadContext *tc) MVM_NO_RETURN_ATTRIBUTE;
417
0
static void die_no_attrs(MVMThreadContext *tc) {
418
0
    MVM_exception_throw_adhoc(tc,
419
0
        "CPPStruct representation attribute not yet fully implemented");
420
0
}
421
422
static void get_attribute(MVMThreadContext *tc, MVMSTable *st, MVMObject *root,
423
        void *data, MVMObject *class_handle, MVMString *name, MVMint64 hint,
424
0
        MVMRegister *result_reg, MVMuint16 kind) {
425
0
    MVMCPPStructREPRData *repr_data = (MVMCPPStructREPRData *)st->REPR_data;
426
0
    MVMCPPStructBody *body = (MVMCPPStructBody *)data;
427
0
    MVMint64 slot;
428
0
429
0
    if (!repr_data)
430
0
        MVM_exception_throw_adhoc(tc, "CPPStruct: must compose before using get_attribute");
431
0
432
0
    slot = hint >= 0 ? hint : try_get_slot(tc, repr_data, class_handle, name);
433
0
    if (slot >= 0) {
434
0
        MVMSTable *attr_st = repr_data->flattened_stables[slot];
435
0
        switch (kind) {
436
0
        case MVM_reg_obj: {
437
0
            MVMint32 type      = repr_data->attribute_locations[slot] & MVM_CPPSTRUCT_ATTR_MASK;
438
0
            MVMint32 real_slot = repr_data->attribute_locations[slot] >> MVM_CPPSTRUCT_ATTR_SHIFT;
439
0
440
0
            if (type == MVM_CPPSTRUCT_ATTR_IN_STRUCT) {
441
0
                MVM_exception_throw_adhoc(tc,
442
0
                    "CPPStruct can't perform boxed get on flattened attributes yet");
443
0
            }
444
0
            else {
445
0
                MVMObject *typeobj = repr_data->member_types[slot];
446
0
                MVMObject *obj     = body->child_objs[real_slot];
447
0
                if (!obj) {
448
0
                    /* No cached object. */
449
0
                    void *cobj = get_ptr_at_offset(body->cppstruct, repr_data->struct_offsets[slot]);
450
0
                    if (cobj) {
451
0
                        MVMObject **child_objs = body->child_objs;
452
0
                        if (type == MVM_CPPSTRUCT_ATTR_CARRAY) {
453
0
                            obj = MVM_nativecall_make_carray(tc, typeobj, cobj);
454
0
                        }
455
0
                        else if(type == MVM_CPPSTRUCT_ATTR_CSTRUCT) {
456
0
                            if (repr_data->attribute_locations[slot] & MVM_CPPSTRUCT_ATTR_INLINED)
457
0
                                obj = MVM_nativecall_make_cstruct(tc, typeobj,
458
0
                                    (char *)body->cppstruct + repr_data->struct_offsets[slot]);
459
0
                            else
460
0
                                obj = MVM_nativecall_make_cstruct(tc, typeobj, cobj);
461
0
                        }
462
0
                        else if(type == MVM_CPPSTRUCT_ATTR_CPPSTRUCT) {
463
0
                            if (repr_data->attribute_locations[slot] & MVM_CPPSTRUCT_ATTR_INLINED)
464
0
                                obj = MVM_nativecall_make_cppstruct(tc, typeobj,
465
0
                                    (char *)body->cppstruct + repr_data->struct_offsets[slot]);
466
0
                            else
467
0
                                obj = MVM_nativecall_make_cppstruct(tc, typeobj, cobj);
468
0
                        }
469
0
                        else if(type == MVM_CPPSTRUCT_ATTR_CUNION) {
470
0
                            if (repr_data->attribute_locations[slot] & MVM_CPPSTRUCT_ATTR_INLINED)
471
0
                                obj = MVM_nativecall_make_cunion(tc, typeobj,
472
0
                                    (char *)body->cppstruct + repr_data->struct_offsets[slot]);
473
0
                            else
474
0
                                obj = MVM_nativecall_make_cunion(tc, typeobj, cobj);
475
0
                        }
476
0
                        else if(type == MVM_CPPSTRUCT_ATTR_CPTR) {
477
0
                            obj = MVM_nativecall_make_cpointer(tc, typeobj, cobj);
478
0
                        }
479
0
                        else if(type == MVM_CPPSTRUCT_ATTR_STRING) {
480
0
                            MVMROOT(tc, typeobj, {
481
0
                                MVMString *str = MVM_string_utf8_decode(tc, tc->instance->VMString,
482
0
                                    cobj, strlen(cobj));
483
0
                                obj = MVM_repr_box_str(tc, typeobj, str);
484
0
                            });
485
0
                        }
486
0
                        child_objs[real_slot] = obj;
487
0
                    }
488
0
                    else {
489
0
                        obj = typeobj;
490
0
                    }
491
0
                }
492
0
                result_reg->o = obj;
493
0
            }
494
0
            break;
495
0
        }
496
0
        case MVM_reg_int64: {
497
0
            if (attr_st)
498
0
                result_reg->i64 = attr_st->REPR->box_funcs.get_int(tc, attr_st, root,
499
0
                    ((char *)body->cppstruct) + repr_data->struct_offsets[slot]);
500
0
            else
501
0
                MVM_exception_throw_adhoc(tc, "CPPStruct: invalid native get of object attribute");
502
0
            break;
503
0
        }
504
0
        case MVM_reg_num64: {
505
0
            if (attr_st)
506
0
                result_reg->n64 = attr_st->REPR->box_funcs.get_num(tc, attr_st, root,
507
0
                    ((char *)body->cppstruct) + repr_data->struct_offsets[slot]);
508
0
            else
509
0
                MVM_exception_throw_adhoc(tc, "CPPStruct: invalid native get of object attribute");
510
0
            break;
511
0
        }
512
0
        case MVM_reg_str: {
513
0
            if (attr_st)
514
0
                result_reg->s = attr_st->REPR->box_funcs.get_str(tc, attr_st, root,
515
0
                    ((char *)body->cppstruct) + repr_data->struct_offsets[slot]);
516
0
            else
517
0
                MVM_exception_throw_adhoc(tc, "CPPStruct: invalid native get of object attribute");
518
0
            if (!result_reg->s)
519
0
                result_reg->s = tc->instance->str_consts.empty;
520
0
            break;
521
0
        }
522
0
        default:
523
0
            MVM_exception_throw_adhoc(tc, "CPPStruct: invalid kind in attribute get");
524
0
        }
525
0
    }
526
0
    else {
527
0
        no_such_attribute(tc, "bind", class_handle, name);
528
0
    }
529
0
}
530
531
/* Binds the given value to the specified attribute. */
532
static void bind_attribute(MVMThreadContext *tc, MVMSTable *st, MVMObject *root,
533
        void *data, MVMObject *class_handle, MVMString *name, MVMint64 hint,
534
0
        MVMRegister value_reg, MVMuint16 kind) {
535
0
    MVMCPPStructREPRData *repr_data = (MVMCPPStructREPRData *)st->REPR_data;
536
0
    MVMCPPStructBody *body = (MVMCPPStructBody *)data;
537
0
    MVMint64 slot;
538
0
539
0
    if (!repr_data)
540
0
        MVM_exception_throw_adhoc(tc, "CPPStruct: must compose before using bind_attribute");
541
0
542
0
    slot = hint >= 0 ? hint : try_get_slot(tc, repr_data, class_handle, name);
543
0
    if (slot >= 0) {
544
0
        MVMSTable *attr_st = repr_data->flattened_stables[slot];
545
0
        switch (kind) {
546
0
        case MVM_reg_obj: {
547
0
            MVMObject *value = value_reg.o;
548
0
            MVMint32   type  = repr_data->attribute_locations[slot] & MVM_CPPSTRUCT_ATTR_MASK;
549
0
550
0
            if (type == MVM_CPPSTRUCT_ATTR_IN_STRUCT) {
551
0
                MVM_exception_throw_adhoc(tc,
552
0
                    "CPPStruct can't perform boxed bind on flattened attributes yet");
553
0
            }
554
0
            else {
555
0
                MVMint32   real_slot = repr_data->attribute_locations[slot] >> MVM_CPPSTRUCT_ATTR_SHIFT;
556
0
557
0
                if (IS_CONCRETE(value)) {
558
0
                    void *cobj       = NULL;
559
0
560
0
                    MVM_ASSIGN_REF(tc, &(root->header), body->child_objs[real_slot], value);
561
0
562
0
                    /* Set cobj to correct pointer based on type of value. */
563
0
                    if (type == MVM_CPPSTRUCT_ATTR_CARRAY) {
564
0
                        if (REPR(value)->ID != MVM_REPR_ID_MVMCArray)
565
0
                            MVM_exception_throw_adhoc(tc,
566
0
                                "Can only store CArray attribute in CArray slot in CPPStruct");
567
0
                        cobj = ((MVMCArray *)value)->body.storage;
568
0
                    }
569
0
                    else if (type == MVM_CPPSTRUCT_ATTR_CSTRUCT) {
570
0
                        if (REPR(value)->ID != MVM_REPR_ID_MVMCStruct)
571
0
                            MVM_exception_throw_adhoc(tc,
572
0
                                "Can only store CStruct attribute in CStruct slot in CPPStruct");
573
0
                        cobj = ((MVMCStruct *)value)->body.cstruct;
574
0
                    }
575
0
                    else if (type == MVM_CPPSTRUCT_ATTR_CPPSTRUCT) {
576
0
                        if (REPR(value)->ID != MVM_REPR_ID_MVMCPPStruct)
577
0
                            MVM_exception_throw_adhoc(tc,
578
0
                                "Can only store CPPStruct attribute in CPPStruct slot in CPPStruct");
579
0
                        cobj = ((MVMCPPStruct *)value)->body.cppstruct;
580
0
                    }
581
0
                    else if (type == MVM_CPPSTRUCT_ATTR_CUNION) {
582
0
                        if (REPR(value)->ID != MVM_REPR_ID_MVMCUnion)
583
0
                            MVM_exception_throw_adhoc(tc,
584
0
                                "Can only store CUnion attribute in CUnion slot in CPPStruct");
585
0
                        cobj = ((MVMCUnion *)value)->body.cunion;
586
0
                    }
587
0
                    else if (type == MVM_CPPSTRUCT_ATTR_CPTR) {
588
0
                        if (REPR(value)->ID != MVM_REPR_ID_MVMCPointer)
589
0
                            MVM_exception_throw_adhoc(tc,
590
0
                                "Can only store CPointer attribute in CPointer slot in CPPStruct");
591
0
                        cobj = ((MVMCPointer *)value)->body.ptr;
592
0
                    }
593
0
                    else if (type == MVM_CPPSTRUCT_ATTR_STRING) {
594
0
                        MVMString *str  = MVM_repr_get_str(tc, value);
595
0
                        cobj = MVM_string_utf8_encode_C_string(tc, str);
596
0
                    }
597
0
598
0
                    set_ptr_at_offset(body->cppstruct, repr_data->struct_offsets[slot], cobj);
599
0
                }
600
0
                else {
601
0
                    body->child_objs[real_slot] = NULL;
602
0
                    set_ptr_at_offset(body->cppstruct, repr_data->struct_offsets[slot], NULL);
603
0
                }
604
0
            }
605
0
            break;
606
0
        }
607
0
        case MVM_reg_int64: {
608
0
            if (attr_st)
609
0
                attr_st->REPR->box_funcs.set_int(tc, attr_st, root,
610
0
                    ((char *)body->cppstruct) + repr_data->struct_offsets[slot], value_reg.i64);
611
0
            else
612
0
                MVM_exception_throw_adhoc(tc, "CPPStruct: invalid native binding to object attribute");
613
0
            break;
614
0
        }
615
0
        case MVM_reg_num64: {
616
0
            if (attr_st)
617
0
                attr_st->REPR->box_funcs.set_num(tc, attr_st, root,
618
0
                    ((char *)body->cppstruct) + repr_data->struct_offsets[slot], value_reg.n64);
619
0
            else
620
0
                MVM_exception_throw_adhoc(tc, "CPPStruct: invalid native binding to object attribute");
621
0
            break;
622
0
        }
623
0
        case MVM_reg_str: {
624
0
            if (attr_st)
625
0
                attr_st->REPR->box_funcs.set_str(tc, attr_st, root,
626
0
                    ((char *)body->cppstruct) + repr_data->struct_offsets[slot], value_reg.s);
627
0
            else
628
0
                MVM_exception_throw_adhoc(tc, "CPPStruct: invalid native binding to object attribute");
629
0
            break;
630
0
        }
631
0
        default:
632
0
            MVM_exception_throw_adhoc(tc, "CPPStruct: invalid kind in attribute bind");
633
0
        }
634
0
    }
635
0
    else {
636
0
        no_such_attribute(tc, "bind", class_handle, name);
637
0
    }
638
0
}
639
640
641
/* Checks if an attribute has been initialized. */
642
0
static MVMint64 is_attribute_initialized(MVMThreadContext *tc, MVMSTable *st, void *data, MVMObject *class_handle, MVMString *name, MVMint64 hint) {
643
0
    die_no_attrs(tc);
644
0
}
645
646
/* Gets the hint for the given attribute ID. */
647
0
static MVMint64 hint_for(MVMThreadContext *tc, MVMSTable *st, MVMObject *class_handle, MVMString *name) {
648
0
    return MVM_NO_HINT;
649
0
}
650
651
/* Adds held objects to the GC worklist. */
652
0
static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) {
653
0
    MVMCPPStructREPRData *repr_data = (MVMCPPStructREPRData *) st->REPR_data;
654
0
    MVMCPPStructBody *body = (MVMCPPStructBody *)data;
655
0
    MVMint32 i;
656
0
    for (i = 0; i < repr_data->num_child_objs; i++)
657
0
        MVM_gc_worklist_add(tc, worklist, &body->child_objs[i]);
658
0
}
659
660
/* Marks the representation data in an STable.*/
661
0
static void gc_mark_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMGCWorklist *worklist) {
662
0
    MVMCPPStructREPRData *repr_data = (MVMCPPStructREPRData *)st->REPR_data;
663
0
    if (repr_data) {
664
0
        MVMint32 i;
665
0
        if (repr_data->name_to_index_mapping) {
666
0
            MVMCPPStructNameMap *map = repr_data->name_to_index_mapping;
667
0
            for (i = 0; map[i].class_key; i++) {
668
0
                MVM_gc_worklist_add(tc, worklist, &map[i].class_key);
669
0
                MVM_gc_worklist_add(tc, worklist, &map[i].name_map);
670
0
            }
671
0
        }
672
0
673
0
        if (repr_data->flattened_stables) {
674
0
            MVMSTable **flattened_stables = repr_data->flattened_stables;
675
0
            for (i = 0; i < repr_data->num_attributes; i++)
676
0
                MVM_gc_worklist_add(tc, worklist, &flattened_stables[i]);
677
0
        }
678
0
679
0
        if (repr_data->member_types) {
680
0
            MVMObject **member_types = repr_data->member_types;
681
0
            for (i = 0; i < repr_data->num_attributes; i++)
682
0
                MVM_gc_worklist_add(tc, worklist, &member_types[i]);
683
0
        }
684
0
    }
685
0
}
686
687
/* Free representation data. */
688
0
static void gc_free_repr_data(MVMThreadContext *tc, MVMSTable *st) {
689
0
    MVMCPPStructREPRData *repr_data = (MVMCPPStructREPRData *)st->REPR_data;
690
0
691
0
    /* May not have survived to composition. */
692
0
    if (repr_data == NULL)
693
0
        return;
694
0
695
0
    if (repr_data->name_to_index_mapping) {
696
0
        MVM_free(repr_data->name_to_index_mapping);
697
0
        MVM_free(repr_data->attribute_locations);
698
0
        MVM_free(repr_data->struct_offsets);
699
0
        MVM_free(repr_data->flattened_stables);
700
0
        MVM_free(repr_data->member_types);
701
0
        MVM_free(repr_data->initialize_slots);
702
0
    }
703
0
704
0
    MVM_free(st->REPR_data);
705
0
}
706
707
/* This is called to do any cleanup of resources when an object gets
708
 * embedded inside another one. Never called on a top-level object. */
709
0
static void gc_cleanup(MVMThreadContext *tc, MVMSTable *st, void *data) {
710
0
    MVMCPPStructBody *body = (MVMCPPStructBody *)data;
711
0
    if (body->child_objs)
712
0
        MVM_free(body->child_objs);
713
0
    /* XXX For some reason, this causes crashes at the moment. Need to
714
0
     * work out why. */
715
0
    /*if (body->cppstruct)
716
0
        MVM_free(body->cppstruct);*/
717
0
}
718
719
/* Called by the VM in order to free memory associated with this object. */
720
0
static void gc_free(MVMThreadContext *tc, MVMObject *obj) {
721
0
    gc_cleanup(tc, STABLE(obj), OBJECT_BODY(obj));
722
0
}
723
724
static const MVMStorageSpec storage_spec = {
725
    MVM_STORAGE_SPEC_REFERENCE, /* inlineable */
726
    sizeof(void*) * 8,          /* bits */
727
    ALIGNOF(void*),             /* align */
728
    MVM_STORAGE_SPEC_BP_NONE,   /* boxed_primitive */
729
    0,                          /* can_box */
730
    0,                          /* is_unsigned */
731
};
732
733
/* Gets the storage specification for this representation. */
734
0
static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
735
0
    return &storage_spec;
736
0
}
737
738
/* Serializes the REPR data. */
739
0
static void serialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationWriter *writer) {
740
0
    MVMCPPStructREPRData *repr_data = (MVMCPPStructREPRData *)st->REPR_data;
741
0
    MVMint32 i, num_classes, num_slots;
742
0
743
0
    MVM_serialization_write_int(tc, writer, repr_data->struct_size);
744
0
    MVM_serialization_write_int(tc, writer, repr_data->struct_align);
745
0
    MVM_serialization_write_int(tc, writer, repr_data->num_attributes);
746
0
    MVM_serialization_write_int(tc, writer, repr_data->num_child_objs);
747
0
    for(i = 0; i < repr_data->num_attributes; i++){
748
0
        MVM_serialization_write_int(tc, writer, repr_data->attribute_locations[i]);
749
0
        MVM_serialization_write_int(tc, writer, repr_data->struct_offsets[i]);
750
0
751
0
        MVM_serialization_write_int(tc, writer, repr_data->flattened_stables[i] != NULL);
752
0
        if (repr_data->flattened_stables[i])
753
0
            MVM_serialization_write_stable_ref(tc, writer, repr_data->flattened_stables[i]);
754
0
755
0
        MVM_serialization_write_ref(tc, writer, repr_data->member_types[i]);
756
0
    }
757
0
758
0
    i=0;
759
0
    while (repr_data->name_to_index_mapping[i].class_key)
760
0
        i++;
761
0
    num_classes = i;
762
0
    MVM_serialization_write_int(tc, writer, num_classes);
763
0
    for(i = 0; i < num_classes; i++){
764
0
        MVM_serialization_write_ref(tc, writer, repr_data->name_to_index_mapping[i].class_key);
765
0
        MVM_serialization_write_ref(tc, writer, repr_data->name_to_index_mapping[i].name_map);
766
0
    }
767
0
768
0
    i=0;
769
0
    while(repr_data->initialize_slots && repr_data->initialize_slots[i] != -1)
770
0
        i++;
771
0
    num_slots = i;
772
0
    MVM_serialization_write_int(tc, writer, num_slots);
773
0
    for(i = 0; i < num_slots; i++){
774
0
        MVM_serialization_write_int(tc, writer, repr_data->initialize_slots[i]);
775
0
    }
776
0
}
777
778
/* Deserializes the REPR data. */
779
0
static void deserialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
780
0
    MVMCPPStructREPRData *repr_data = (MVMCPPStructREPRData *) MVM_malloc(sizeof(MVMCPPStructREPRData));
781
0
    MVMint32 i, num_classes, num_slots;
782
0
783
0
    repr_data->struct_size    = MVM_serialization_read_int(tc, reader);
784
0
    if (reader->root.version >= 17) {
785
0
        repr_data->struct_align = MVM_serialization_read_int(tc, reader);
786
0
    }
787
0
    repr_data->num_attributes = MVM_serialization_read_int(tc, reader);
788
0
    repr_data->num_child_objs = MVM_serialization_read_int(tc, reader);
789
0
790
0
    repr_data->attribute_locations = (MVMint32 *)MVM_malloc(sizeof(MVMint32) * repr_data->num_attributes);
791
0
    repr_data->struct_offsets      = (MVMint32 *)MVM_malloc(sizeof(MVMint32) * repr_data->num_attributes);
792
0
    repr_data->flattened_stables   = (MVMSTable **)MVM_malloc(repr_data->num_attributes * sizeof(MVMSTable *));
793
0
    repr_data->member_types        = (MVMObject **)MVM_malloc(repr_data->num_attributes * sizeof(MVMObject *));
794
0
795
0
    for(i = 0; i < repr_data->num_attributes; i++) {
796
0
        repr_data->attribute_locations[i] = MVM_serialization_read_int(tc, reader);
797
0
        repr_data->struct_offsets[i] = MVM_serialization_read_int(tc, reader);
798
0
799
0
        if(MVM_serialization_read_int(tc, reader)){
800
0
            MVM_ASSIGN_REF(tc, &(st->header), repr_data->flattened_stables[i], MVM_serialization_read_stable_ref(tc, reader));
801
0
        }
802
0
        else {
803
0
            repr_data->flattened_stables[i] = NULL;
804
0
        }
805
0
806
0
        repr_data->member_types[i] = MVM_serialization_read_ref(tc, reader);
807
0
    }
808
0
809
0
    num_classes = MVM_serialization_read_int(tc, reader);
810
0
    repr_data->name_to_index_mapping = (MVMCPPStructNameMap *)MVM_malloc(sizeof(MVMCPPStructNameMap) * (1 + num_classes));
811
0
    for(i = 0; i < num_classes; i++){
812
0
        repr_data->name_to_index_mapping[i].class_key = MVM_serialization_read_ref(tc, reader);
813
0
        repr_data->name_to_index_mapping[i].name_map = MVM_serialization_read_ref(tc, reader);
814
0
    }
815
0
    repr_data->name_to_index_mapping[i].class_key = NULL;
816
0
    repr_data->name_to_index_mapping[i].name_map = NULL;
817
0
818
0
    num_slots = MVM_serialization_read_int(tc, reader);
819
0
    repr_data->initialize_slots = (MVMint32 *)MVM_malloc(sizeof(MVMint32) * (1 + num_slots));
820
0
    for(i = 0; i < num_slots; i++){
821
0
        repr_data->initialize_slots[i] = MVM_serialization_read_int(tc, reader);
822
0
    }
823
0
    repr_data->initialize_slots[i] = -1;
824
0
825
0
    st->REPR_data = repr_data;
826
0
}
827
828
0
static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
829
0
    st->size = sizeof(MVMCPPStruct);
830
0
}
831
832
/* Initializes the representation. */
833
144
const MVMREPROps * MVMCPPStruct_initialize(MVMThreadContext *tc) {
834
144
    return &CPPStruct_this_repr;
835
144
}
836
837
static const MVMREPROps CPPStruct_this_repr = {
838
    type_object_for,
839
    MVM_gc_allocate_object,
840
    initialize,
841
    copy_to,
842
    {
843
        get_attribute,
844
        bind_attribute,
845
        hint_for,
846
        is_attribute_initialized,
847
        MVM_REPR_DEFAULT_ATTRIBUTE_AS_ATOMIC
848
    },   /* attr_funcs */
849
    MVM_REPR_DEFAULT_BOX_FUNCS,
850
    MVM_REPR_DEFAULT_POS_FUNCS,
851
    MVM_REPR_DEFAULT_ASS_FUNCS,
852
    MVM_REPR_DEFAULT_ELEMS,
853
    get_storage_spec,
854
    NULL, /* change_type */
855
    NULL, /* serialize */
856
    NULL, /* deserialize */
857
    serialize_repr_data,
858
    deserialize_repr_data,
859
    deserialize_stable_size,
860
    gc_mark,
861
    gc_free,
862
    gc_cleanup,
863
    gc_mark_repr_data,
864
    gc_free_repr_data,
865
    compose,
866
    NULL, /* spesh */
867
    "CPPStruct", /* name */
868
    MVM_REPR_ID_MVMCPPStruct,
869
    NULL, /* unmanaged_size */
870
    NULL, /* describe_refs */
871
};