Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/6model/reprs/MultiDimArray.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 MultiDimArray_this_repr;
5
6
/* Computes the flat number of elements from the given dimension list. */
7
25
static MVMint64 flat_elements(MVMint64 num_dimensions, MVMint64 *dimensions) {
8
25
    MVMint64 result = dimensions[0];
9
25
    MVMint64 i;
10
44
    for (i = 1; i < num_dimensions; i++)
11
19
        result *= dimensions[i];
12
25
    return result;
13
25
}
14
15
/* Computes the flat size from representation data. */
16
23
static size_t flat_size(MVMMultiDimArrayREPRData *repr_data, MVMint64 *dimensions) {
17
23
    return repr_data->elem_size * flat_elements(repr_data->num_dimensions, dimensions);
18
23
}
19
20
/* Takes a number of dimensions, indices we were passed, and dimension sizes.
21
 * Computes the offset into flat space. */
22
122
MVM_STATIC_INLINE size_t indices_to_flat_index(MVMThreadContext *tc, MVMint64 num_dimensions, MVMint64 *dimensions, MVMint64 *indices) {
23
122
    MVMint64 multiplier = 1;
24
122
    size_t   result     = 0;
25
122
    MVMint64 i;
26
376
    for (i = num_dimensions - 1; i >= 0; i--) {
27
254
        MVMint64  dim_size = dimensions[i];
28
254
        MVMint64  index    = indices[i];
29
254
        if (index >= 0 && index < dim_size) {
30
230
            result += index * multiplier;
31
230
            multiplier *= dim_size;
32
230
        }
33
24
        else {
34
24
            MVM_exception_throw_adhoc(tc,
35
24
                "Index %"PRId64" for dimension %"PRId64" out of range (must be 0..%"PRId64")",
36
24
                index, i + 1, dim_size - 1);
37
24
        }
38
254
    }
39
122
    return result;
40
122
}
41
42
/* Creates a new type object of this representation, and associates it with
43
 * the given HOW. */
44
7
static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
45
7
    MVMSTable *st  = MVM_gc_allocate_stable(tc, &MultiDimArray_this_repr, HOW);
46
7
47
7
    MVMROOT(tc, st, {
48
7
        MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
49
7
        MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj);
50
7
        st->size = sizeof(MVMMultiDimArray);
51
7
    });
52
7
53
7
    return st->WHAT;
54
7
}
55
56
/* Allocates the mutli-dimensional array and sets up its dimensions array with
57
 * all zeroes, for later filling. */
58
32
static MVMObject * allocate(MVMThreadContext *tc, MVMSTable *st) {
59
32
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
60
32
    if (repr_data) {
61
32
        MVMObject *obj = MVM_gc_allocate_object(tc, st);
62
32
        ((MVMMultiDimArray *)obj)->body.dimensions = MVM_fixed_size_alloc_zeroed(tc,
63
32
            tc->instance->fsa, repr_data->num_dimensions * sizeof(MVMint64));
64
32
        return obj;
65
32
    }
66
0
    else {
67
0
        MVM_exception_throw_adhoc(tc,
68
0
            "Cannot allocate a multi-dim array type before it is composed");
69
0
    }
70
32
}
71
72
/* Composes the representation. */
73
2
static void spec_to_repr_data(MVMThreadContext *tc, MVMMultiDimArrayREPRData *repr_data, const MVMStorageSpec *spec) {
74
2
    switch (spec->boxed_primitive) {
75
2
        case MVM_STORAGE_SPEC_BP_INT:
76
2
            if (spec->is_unsigned) {
77
0
                switch (spec->bits) {
78
0
                    case 64:
79
0
                        repr_data->slot_type = MVM_ARRAY_U64;
80
0
                        repr_data->elem_size = sizeof(MVMuint64);
81
0
                        break;
82
0
                    case 32:
83
0
                        repr_data->slot_type = MVM_ARRAY_U32;
84
0
                        repr_data->elem_size = sizeof(MVMuint32);
85
0
                        break;
86
0
                    case 16:
87
0
                        repr_data->slot_type = MVM_ARRAY_U16;
88
0
                        repr_data->elem_size = sizeof(MVMuint16);
89
0
                        break;
90
0
                    case 8:
91
0
                        repr_data->slot_type = MVM_ARRAY_U8;
92
0
                        repr_data->elem_size = sizeof(MVMuint8);
93
0
                        break;
94
0
                    case 4:
95
0
                        repr_data->slot_type = MVM_ARRAY_U4;
96
0
                        repr_data->elem_size = 0;
97
0
                        break;
98
0
                    case 2:
99
0
                        repr_data->slot_type = MVM_ARRAY_U2;
100
0
                        repr_data->elem_size = 0;
101
0
                        break;
102
0
                    case 1:
103
0
                        repr_data->slot_type = MVM_ARRAY_U1;
104
0
                        repr_data->elem_size = 0;
105
0
                        break;
106
0
                    default:
107
0
                        MVM_exception_throw_adhoc(tc,
108
0
                            "MVMMultiDimArray: Unsupported uint size");
109
0
                }
110
0
            }
111
2
            else {
112
2
                switch (spec->bits) {
113
2
                    case 64:
114
2
                        repr_data->slot_type = MVM_ARRAY_I64;
115
2
                        repr_data->elem_size = sizeof(MVMint64);
116
2
                        break;
117
0
                    case 32:
118
0
                        repr_data->slot_type = MVM_ARRAY_I32;
119
0
                        repr_data->elem_size = sizeof(MVMint32);
120
0
                        break;
121
0
                    case 16:
122
0
                        repr_data->slot_type = MVM_ARRAY_I16;
123
0
                        repr_data->elem_size = sizeof(MVMint16);
124
0
                        break;
125
0
                    case 8:
126
0
                        repr_data->slot_type = MVM_ARRAY_I8;
127
0
                        repr_data->elem_size = sizeof(MVMint8);
128
0
                        break;
129
0
                    case 4:
130
0
                        repr_data->slot_type = MVM_ARRAY_I4;
131
0
                        repr_data->elem_size = 0;
132
0
                        break;
133
0
                    case 2:
134
0
                        repr_data->slot_type = MVM_ARRAY_I2;
135
0
                        repr_data->elem_size = 0;
136
0
                        break;
137
0
                    case 1:
138
0
                        repr_data->slot_type = MVM_ARRAY_I1;
139
0
                        repr_data->elem_size = 0;
140
0
                        break;
141
0
                    default:
142
0
                        MVM_exception_throw_adhoc(tc,
143
0
                            "MVMMultiDimArray: Unsupported int size");
144
2
                }
145
2
            }
146
2
            break;
147
0
        case MVM_STORAGE_SPEC_BP_NUM:
148
0
            switch (spec->bits) {
149
0
                case 64:
150
0
                    repr_data->slot_type = MVM_ARRAY_N64;
151
0
                    repr_data->elem_size = sizeof(MVMnum64);
152
0
                    break;
153
0
                case 32:
154
0
                    repr_data->slot_type = MVM_ARRAY_N32;
155
0
                    repr_data->elem_size = sizeof(MVMnum32);
156
0
                    break;
157
0
                default:
158
0
                    MVM_exception_throw_adhoc(tc,
159
0
                        "MVMMultiDimArray: Unsupported num size");
160
0
            }
161
0
            break;
162
0
        case MVM_STORAGE_SPEC_BP_STR:
163
0
            repr_data->slot_type = MVM_ARRAY_STR;
164
0
            repr_data->elem_size = sizeof(MVMString *);
165
0
            break;
166
0
        default:
167
0
            repr_data->slot_type = MVM_ARRAY_OBJ;
168
0
            repr_data->elem_size = sizeof(MVMObject *);
169
2
    }
170
2
}
171
6
static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *repr_info) {
172
6
    MVMStringConsts          *str_consts = &(tc->instance->str_consts);
173
6
    MVMMultiDimArrayREPRData *repr_data;
174
6
175
6
    MVMObject *info = MVM_repr_at_key_o(tc, repr_info, str_consts->array);
176
6
    if (!MVM_is_null(tc, info)) {
177
6
        MVMObject *dims = MVM_repr_at_key_o(tc, info, str_consts->dimensions);
178
6
        MVMObject *type = MVM_repr_at_key_o(tc, info, str_consts->type);
179
6
        MVMint64 dimensions;
180
6
        if (!MVM_is_null(tc, dims)) {
181
6
            dimensions = MVM_repr_get_int(tc, dims);
182
6
            if (dimensions < 1)
183
1
                MVM_exception_throw_adhoc(tc,
184
1
                    "MultiDimArray REPR must be composed with at least 1 dimension");
185
6
            repr_data = MVM_calloc(1, sizeof(MVMMultiDimArrayREPRData));
186
6
            repr_data->num_dimensions = dimensions;
187
6
        }
188
0
        else {
189
0
            MVM_exception_throw_adhoc(tc,
190
0
                "MultiDimArray REPR must be composed with a number of dimensions");
191
0
        }
192
6
        if (!MVM_is_null(tc, type)) {
193
2
            const MVMStorageSpec *spec = REPR(type)->get_storage_spec(tc, STABLE(type));
194
2
            MVM_ASSIGN_REF(tc, &(st->header), repr_data->elem_type, type);
195
2
            spec_to_repr_data(tc, repr_data, spec);
196
2
        }
197
4
        else {
198
4
            repr_data->slot_type = MVM_ARRAY_OBJ;
199
4
            repr_data->elem_size = sizeof(MVMObject *);
200
4
        }
201
6
        st->REPR_data = repr_data;
202
6
    }
203
0
    else {
204
0
        MVM_exception_throw_adhoc(tc,
205
0
            "MultiDimArray REPR must be composed with array information");
206
0
    }
207
6
}
208
209
/* Copies to the body of one object to another. */
210
1
static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) {
211
1
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
212
1
    MVMMultiDimArrayBody     *src_body  = (MVMMultiDimArrayBody *)src;
213
1
    MVMMultiDimArrayBody     *dest_body = (MVMMultiDimArrayBody *)dest;
214
1
    if (src_body->slots.any) {
215
1
        size_t dim_size  = repr_data->num_dimensions * sizeof(MVMint64);
216
1
        size_t data_size = flat_size(repr_data, src_body->dimensions);
217
1
        dest_body->dimensions = MVM_fixed_size_alloc(tc, tc->instance->fsa, dim_size);
218
1
        dest_body->slots.any  = MVM_fixed_size_alloc(tc, tc->instance->fsa, data_size);
219
1
        memcpy(dest_body->dimensions, src_body->dimensions, dim_size);
220
1
        memcpy(dest_body->slots.any, src_body->slots.any, data_size);
221
1
    }
222
1
}
223
224
/* Adds held objects to the GC worklist. */
225
0
static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) {
226
0
    MVMMultiDimArrayBody *body = (MVMMultiDimArrayBody *)data;
227
0
    if (body->slots.any) {
228
0
        MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
229
0
        MVMint64 flat_elems = flat_elements(repr_data->num_dimensions, body->dimensions);
230
0
        MVMint64 i;
231
0
        switch (repr_data->slot_type) {
232
0
            case MVM_ARRAY_OBJ: {
233
0
                MVMObject **slots = body->slots.o;
234
0
                for (i = 0; i < flat_elems; i++)
235
0
                    MVM_gc_worklist_add(tc, worklist, &slots[i]);
236
0
                break;
237
0
            }
238
0
            case MVM_ARRAY_STR: {
239
0
                MVMString **slots = body->slots.s;
240
0
                for (i = 0; i < flat_elems; i++)
241
0
                    MVM_gc_worklist_add(tc, worklist, &slots[i]);
242
0
                break;
243
0
            }
244
0
        }
245
0
    }
246
0
}
247
248
/* Called by the VM in order to free memory associated with this object. */
249
0
static void gc_free(MVMThreadContext *tc, MVMObject *obj) {
250
0
    MVMMultiDimArray *arr = (MVMMultiDimArray *)obj;
251
0
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)STABLE(obj)->REPR_data;
252
0
    if (arr->body.slots.any)
253
0
        MVM_fixed_size_free(tc, tc->instance->fsa,
254
0
            flat_size(repr_data, arr->body.dimensions),
255
0
            arr->body.slots.any);
256
0
    MVM_fixed_size_free(tc, tc->instance->fsa,
257
0
        repr_data->num_dimensions * sizeof(MVMint64),
258
0
        arr->body.dimensions);
259
0
}
260
261
/* Marks the representation data in an STable.*/
262
0
static void gc_mark_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMGCWorklist *worklist) {
263
0
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
264
0
    if (repr_data == NULL)
265
0
        return;
266
0
    MVM_gc_worklist_add(tc, worklist, &repr_data->elem_type);
267
0
}
268
269
/* Free representation data. */
270
0
static void gc_free_repr_data(MVMThreadContext *tc, MVMSTable *st) {
271
0
    MVM_free(st->REPR_data);
272
0
}
273
274
/* Gets the storage specification for this representation. */
275
static const MVMStorageSpec storage_spec = {
276
    MVM_STORAGE_SPEC_REFERENCE, /* inlineable */
277
    0,                          /* bits */
278
    0,                          /* align */
279
    MVM_STORAGE_SPEC_BP_NONE,   /* boxed_primitive */
280
    0,                          /* can_box */
281
    0,                          /* is_unsigned */
282
};
283
0
static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
284
0
    return &storage_spec;
285
0
}
286
287
/* Serializes the data held in the array. */
288
1
static void serialize(MVMThreadContext *tc, MVMSTable *st, void *data, MVMSerializationWriter *writer) {
289
1
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
290
1
    MVMMultiDimArrayBody     *body      = (MVMMultiDimArrayBody *)data;
291
1
    MVMint64 i, flat_elems;
292
1
293
1
    /* Write out dimensions. */
294
3
    for (i = 0; i < repr_data->num_dimensions; i++)
295
2
        MVM_serialization_write_int(tc, writer, body->dimensions[i]);
296
1
297
1
    /* Write out values. */
298
1
    flat_elems = flat_elements(repr_data->num_dimensions, body->dimensions);
299
5
    for (i = 0; i < flat_elems; i++) {
300
4
        switch (repr_data->slot_type) {
301
4
            case MVM_ARRAY_OBJ:
302
4
                MVM_serialization_write_ref(tc, writer, body->slots.o[i]);
303
4
                break;
304
0
            case MVM_ARRAY_STR:
305
0
                MVM_serialization_write_str(tc, writer, body->slots.s[i]);
306
0
                break;
307
0
            case MVM_ARRAY_I64:
308
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i64[i]);
309
0
                break;
310
0
            case MVM_ARRAY_I32:
311
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i32[i]);
312
0
                break;
313
0
            case MVM_ARRAY_I16:
314
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i16[i]);
315
0
                break;
316
0
            case MVM_ARRAY_I8:
317
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i8[i]);
318
0
                break;
319
0
            case MVM_ARRAY_U64:
320
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u64[i]);
321
0
                break;
322
0
            case MVM_ARRAY_U32:
323
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u32[i]);
324
0
                break;
325
0
            case MVM_ARRAY_U16:
326
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u16[i]);
327
0
                break;
328
0
            case MVM_ARRAY_U8:
329
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u8[i]);
330
0
                break;
331
0
            case MVM_ARRAY_N64:
332
0
                MVM_serialization_write_num(tc, writer, (MVMnum64)body->slots.n64[i]);
333
0
                break;
334
0
            case MVM_ARRAY_N32:
335
0
                MVM_serialization_write_num(tc, writer, (MVMnum64)body->slots.n32[i]);
336
0
                break;
337
0
            default:
338
0
                MVM_exception_throw_adhoc(tc, "MVMMultiDimArray: Unhandled slot type");
339
4
        }
340
4
    }
341
1
}
342
343
/* Deserializes the data held in the array. */
344
1
static void deserialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMSerializationReader *reader) {
345
1
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
346
1
    MVMMultiDimArrayBody     *body      = (MVMMultiDimArrayBody *)data;
347
1
    MVMint64 i, flat_elems;
348
1
349
1
    /* Read in dimensions. */
350
3
    for (i = 0; i < repr_data->num_dimensions; i++)
351
2
        body->dimensions[i] = MVM_serialization_read_int(tc, reader);
352
1
353
1
    /* Allocate storage. */
354
1
    body->slots.any = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa,
355
1
        flat_size(repr_data, body->dimensions));
356
1
357
1
    /* Read in elements. */
358
1
    flat_elems = flat_elements(repr_data->num_dimensions, body->dimensions);
359
5
    for (i = 0; i < flat_elems; i++) {
360
4
        switch (repr_data->slot_type) {
361
4
            case MVM_ARRAY_OBJ:
362
4
                MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[i], MVM_serialization_read_ref(tc, reader));
363
4
                break;
364
0
            case MVM_ARRAY_STR:
365
0
                MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[i], MVM_serialization_read_str(tc, reader));
366
0
                break;
367
0
            case MVM_ARRAY_I64:
368
0
                body->slots.i64[i] = MVM_serialization_read_int(tc, reader);
369
0
                break;
370
0
            case MVM_ARRAY_I32:
371
0
                body->slots.i32[i] = (MVMint32)MVM_serialization_read_int(tc, reader);
372
0
                break;
373
0
            case MVM_ARRAY_I16:
374
0
                body->slots.i16[i] = (MVMint16)MVM_serialization_read_int(tc, reader);
375
0
                break;
376
0
            case MVM_ARRAY_I8:
377
0
                body->slots.i8[i] = (MVMint8)MVM_serialization_read_int(tc, reader);
378
0
                break;
379
0
            case MVM_ARRAY_U64:
380
0
                body->slots.i64[i] = MVM_serialization_read_int(tc, reader);
381
0
                break;
382
0
            case MVM_ARRAY_U32:
383
0
                body->slots.i32[i] = (MVMuint32)MVM_serialization_read_int(tc, reader);
384
0
                break;
385
0
            case MVM_ARRAY_U16:
386
0
                body->slots.i16[i] = (MVMuint16)MVM_serialization_read_int(tc, reader);
387
0
                break;
388
0
            case MVM_ARRAY_U8:
389
0
                body->slots.i8[i] = (MVMuint8)MVM_serialization_read_int(tc, reader);
390
0
                break;
391
0
            case MVM_ARRAY_N64:
392
0
                body->slots.n64[i] = MVM_serialization_read_num(tc, reader);
393
0
                break;
394
0
            case MVM_ARRAY_N32:
395
0
                body->slots.n32[i] = (MVMnum32)MVM_serialization_read_num(tc, reader);
396
0
                break;
397
0
            default:
398
0
                MVM_exception_throw_adhoc(tc, "MVMMultiDimArray: Unhandled slot type");
399
4
        }
400
4
    }
401
1
}
402
403
/* Serializes the REPR data. */
404
2
static void serialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationWriter *writer) {
405
2
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
406
2
    if (repr_data) {
407
1
        MVM_serialization_write_int(tc, writer, repr_data->num_dimensions);
408
1
        MVM_serialization_write_ref(tc, writer, repr_data->elem_type);
409
1
    }
410
1
    else {
411
1
        MVM_serialization_write_int(tc, writer, 0);
412
1
    }
413
2
}
414
415
/* Deserializes the REPR data. */
416
2
static void deserialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
417
2
    MVMint64 num_dims;
418
2
419
2
    if (reader->root.version >= 19) {
420
2
        num_dims = MVM_serialization_read_int(tc, reader);
421
0
    } else {
422
0
        num_dims = MVM_serialization_read_int64(tc, reader);
423
0
    }
424
2
425
2
    if (num_dims > 0) {
426
1
        MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)MVM_malloc(sizeof(MVMMultiDimArrayREPRData));
427
1
        MVMObject *type;
428
1
429
1
        repr_data->num_dimensions = num_dims;
430
1
        type = MVM_serialization_read_ref(tc, reader);
431
1
        MVM_ASSIGN_REF(tc, &(st->header), repr_data->elem_type, type);
432
1
433
1
        if (type) {
434
0
            MVM_serialization_force_stable(tc, reader, STABLE(type));
435
0
            spec_to_repr_data(tc, repr_data, REPR(type)->get_storage_spec(tc, STABLE(type)));
436
0
        }
437
1
        else {
438
1
            repr_data->slot_type = MVM_ARRAY_OBJ;
439
1
            repr_data->elem_size = sizeof(MVMObject *);
440
1
        }
441
1
442
1
        st->REPR_data = repr_data;
443
1
    }
444
2
}
445
446
2
static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
447
2
    st->size = sizeof(MVMMultiDimArray);
448
2
}
449
450
1
static void push(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister value, MVMuint16 kind) {
451
1
    MVM_exception_throw_adhoc(tc, "Cannot push onto a fixed dimension array");
452
1
}
453
1
static void pop(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) {
454
1
    MVM_exception_throw_adhoc(tc, "Cannot pop a fixed dimension array");
455
1
}
456
1
static void unshift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister value, MVMuint16 kind) {
457
1
    MVM_exception_throw_adhoc(tc, "Cannot unshift onto a fixed dimension array");
458
1
}
459
1
static void shift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) {
460
1
    MVM_exception_throw_adhoc(tc, "Cannot shift a fixed dimension array");
461
1
}
462
1
static void asplice(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *from, MVMint64 offset, MVMuint64 count) {
463
1
    MVM_exception_throw_adhoc(tc, "Cannot splice a fixed dimension array");
464
1
}
465
466
70
static void at_pos_multidim(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_indices, MVMint64 *indices, MVMRegister *value, MVMuint16 kind) {
467
70
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
468
70
    if (num_indices == repr_data->num_dimensions) {
469
64
        MVMMultiDimArrayBody *body = (MVMMultiDimArrayBody *)data;
470
64
        size_t flat_index = indices_to_flat_index(tc, repr_data->num_dimensions, body->dimensions, indices);
471
64
        switch (repr_data->slot_type) {
472
30
            case MVM_ARRAY_OBJ:
473
30
                if (kind == MVM_reg_obj) {
474
30
                    MVMObject *found = body->slots.o[flat_index];
475
30
                    value->o = found ? found : tc->instance->VMNull;
476
30
                }
477
0
                else {
478
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected object register");
479
0
                }
480
30
                break;
481
0
            case MVM_ARRAY_STR:
482
0
                if (kind == MVM_reg_str)
483
0
                    value->s = body->slots.s[flat_index];
484
0
                else
485
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected string register");
486
0
                break;
487
22
            case MVM_ARRAY_I64:
488
22
                if (kind == MVM_reg_int64)
489
16
                    value->i64 = (MVMint64)body->slots.i64[flat_index];
490
22
                else
491
6
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
492
22
                break;
493
0
            case MVM_ARRAY_I32:
494
0
                if (kind == MVM_reg_int64)
495
0
                    value->i64 = (MVMint64)body->slots.i32[flat_index];
496
0
                else
497
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
498
0
                break;
499
0
            case MVM_ARRAY_I16:
500
0
                if (kind == MVM_reg_int64)
501
0
                    value->i64 = (MVMint64)body->slots.i16[flat_index];
502
0
                else
503
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
504
0
                break;
505
0
            case MVM_ARRAY_I8:
506
0
                if (kind == MVM_reg_int64)
507
0
                    value->i64 = (MVMint64)body->slots.i8[flat_index];
508
0
                else
509
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
510
0
                break;
511
0
            case MVM_ARRAY_N64:
512
0
                if (kind == MVM_reg_num64)
513
0
                    value->n64 = (MVMnum64)body->slots.n64[flat_index];
514
0
                else
515
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected num register");
516
0
                break;
517
0
            case MVM_ARRAY_N32:
518
0
                if (kind == MVM_reg_num64)
519
0
                    value->n64 = (MVMnum64)body->slots.n32[flat_index];
520
0
                else
521
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected num register");
522
0
                break;
523
0
            case MVM_ARRAY_U64:
524
0
                if (kind == MVM_reg_int64)
525
0
                    value->i64 = (MVMint64)body->slots.u64[flat_index];
526
0
                else
527
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
528
0
                break;
529
0
            case MVM_ARRAY_U32:
530
0
                if (kind == MVM_reg_int64)
531
0
                    value->i64 = (MVMint64)body->slots.u32[flat_index];
532
0
                else
533
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
534
0
                break;
535
0
            case MVM_ARRAY_U16:
536
0
                if (kind == MVM_reg_int64)
537
0
                    value->i64 = (MVMint64)body->slots.u16[flat_index];
538
0
                else
539
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
540
0
                break;
541
0
            case MVM_ARRAY_U8:
542
0
                if (kind == MVM_reg_int64)
543
0
                    value->i64 = (MVMint64)body->slots.u8[flat_index];
544
0
                else
545
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
546
0
                break;
547
0
            default:
548
0
                MVM_exception_throw_adhoc(tc, "MultiDimArray: Unhandled slot type");
549
64
        }
550
64
    }
551
6
    else {
552
6
        MVM_exception_throw_adhoc(tc,
553
6
            "Cannot access %"PRId64" dimension array with %"PRId64" indices",
554
6
            repr_data->num_dimensions, num_indices);
555
6
    }
556
70
}
557
558
64
static void bind_pos_multidim(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_indices, MVMint64 *indices, MVMRegister value, MVMuint16 kind) {
559
64
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
560
64
    if (num_indices == repr_data->num_dimensions) {
561
58
        MVMMultiDimArrayBody *body = (MVMMultiDimArrayBody *)data;
562
58
        size_t flat_index = indices_to_flat_index(tc, repr_data->num_dimensions, body->dimensions, indices);
563
58
        switch (repr_data->slot_type) {
564
30
            case MVM_ARRAY_OBJ:
565
30
                if (kind == MVM_reg_obj) {
566
30
                    MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[flat_index], value.o);
567
30
                }
568
0
                else {
569
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected object register");
570
0
                }
571
30
                break;
572
0
            case MVM_ARRAY_STR:
573
0
                if (kind == MVM_reg_str) {
574
0
                    MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[flat_index], value.s);
575
0
                }
576
0
                else {
577
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected string register");
578
0
                }
579
0
                break;
580
16
            case MVM_ARRAY_I64:
581
16
                if (kind == MVM_reg_int64)
582
16
                    body->slots.i64[flat_index] = value.i64;
583
16
                else
584
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
585
16
                break;
586
0
            case MVM_ARRAY_I32:
587
0
                if (kind == MVM_reg_int64)
588
0
                    body->slots.i32[flat_index] = (MVMint32)value.i64;
589
0
                else
590
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
591
0
                break;
592
0
            case MVM_ARRAY_I16:
593
0
                if (kind == MVM_reg_int64)
594
0
                    body->slots.i16[flat_index] = (MVMint16)value.i64;
595
0
                else
596
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
597
0
                break;
598
0
            case MVM_ARRAY_I8:
599
0
                if (kind == MVM_reg_int64)
600
0
                    body->slots.i8[flat_index] = (MVMint8)value.i64;
601
0
                else
602
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
603
0
                break;
604
0
            case MVM_ARRAY_N64:
605
0
                if (kind == MVM_reg_num64)
606
0
                    body->slots.n64[flat_index] = value.n64;
607
0
                else
608
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected num register");
609
0
                break;
610
0
            case MVM_ARRAY_N32:
611
0
                if (kind == MVM_reg_num64)
612
0
                    body->slots.n32[flat_index] = (MVMnum32)value.n64;
613
0
                else
614
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected num register");
615
0
                break;
616
0
            case MVM_ARRAY_U64:
617
0
                if (kind == MVM_reg_int64)
618
0
                    body->slots.u64[flat_index] = value.i64;
619
0
                else
620
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
621
0
                break;
622
0
            case MVM_ARRAY_U32:
623
0
                if (kind == MVM_reg_int64)
624
0
                    body->slots.u32[flat_index] = (MVMuint32)value.i64;
625
0
                else
626
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
627
0
                break;
628
0
            case MVM_ARRAY_U16:
629
0
                if (kind == MVM_reg_int64)
630
0
                    body->slots.u16[flat_index] = (MVMuint16)value.i64;
631
0
                else
632
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
633
0
                break;
634
0
            case MVM_ARRAY_U8:
635
0
                if (kind == MVM_reg_int64)
636
0
                    body->slots.u8[flat_index] = (MVMuint8)value.i64;
637
0
                else
638
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
639
0
                break;
640
0
            default:
641
0
                MVM_exception_throw_adhoc(tc, "MultiDimArray: Unhandled slot type");
642
58
        }
643
58
    }
644
6
    else {
645
6
        MVM_exception_throw_adhoc(tc,
646
6
            "Cannot access %"PRId64" dimension array with %"PRId64" indices",
647
6
            repr_data->num_dimensions, num_indices);
648
6
    }
649
64
}
650
651
13
static void dimensions(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 *num_dimensions, MVMint64 **dimensions) {
652
13
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
653
13
    if (repr_data) {
654
13
        MVMMultiDimArrayBody *body = (MVMMultiDimArrayBody *)data;
655
13
        *num_dimensions = repr_data->num_dimensions;
656
13
        *dimensions = body->dimensions;
657
13
    }
658
0
    else {
659
0
        MVM_exception_throw_adhoc(tc,
660
0
            "Cannot query a multi-dim array's dimensionality before it is composed");
661
0
    }
662
13
}
663
664
27
static void set_dimensions(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_dimensions, MVMint64 *dimensions) {
665
27
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
666
27
    if (num_dimensions == repr_data->num_dimensions) {
667
21
        /* Note that we use an atomic operation at the point of allocation.
668
21
         * This means we can be leak-free and memory safe in the face of
669
21
         * multiple threads competing to set dimensions (unlikely in any
670
21
         * real world use case, but we should ensure the VM is memory safe).
671
21
         */
672
21
        MVMMultiDimArrayBody *body = (MVMMultiDimArrayBody *)data;
673
21
        size_t size = flat_size(repr_data, dimensions);
674
21
        void *storage = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, size);
675
21
        if (MVM_trycas(&(body->slots.any), NULL, storage)) {
676
18
            /* Now memory is in place, safe to un-zero dimensions. */
677
18
            memcpy(body->dimensions, dimensions, num_dimensions * sizeof(MVMint64));
678
18
        }
679
3
        else {
680
3
            MVM_exception_throw_adhoc(tc, "MultiDimArray: can only set dimensions once");
681
3
        }
682
21
    }
683
6
    else {
684
6
        MVM_exception_throw_adhoc(tc,
685
6
            "Array type of %"PRId64" dimensions cannot be initialized with %"PRId64" dimensions",
686
6
            repr_data->num_dimensions, num_dimensions);
687
6
    }
688
27
}
689
690
6
static void at_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister *value, MVMuint16 kind) {
691
6
    at_pos_multidim(tc, st, root, data, 1, &index, value, kind);
692
6
}
693
694
6
static void bind_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister value, MVMuint16 kind) {
695
6
    bind_pos_multidim(tc, st, root, data, 1, &index, value, kind);
696
6
}
697
698
3
static void set_elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMuint64 count) {
699
3
    set_dimensions(tc, st, root, data, 1, (MVMint64 *)&count);
700
3
}
701
702
2
static MVMuint64 elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) {
703
2
    MVMint64  _;
704
2
    MVMint64 *dims;
705
2
    dimensions(tc, st, root, data, &_, &dims);
706
2
    return (MVMuint64)dims[0];
707
2
}
708
709
0
static MVMStorageSpec get_elem_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
710
0
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
711
0
    MVMStorageSpec spec;
712
0
713
0
    /* initialise storage spec to default values */
714
0
    spec.bits            = 0;
715
0
    spec.align           = 0;
716
0
    spec.is_unsigned     = 0;
717
0
718
0
    switch (repr_data->slot_type) {
719
0
        case MVM_ARRAY_STR:
720
0
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
721
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_STR;
722
0
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_STR;
723
0
            break;
724
0
        case MVM_ARRAY_I64:
725
0
        case MVM_ARRAY_I32:
726
0
        case MVM_ARRAY_I16:
727
0
        case MVM_ARRAY_I8:
728
0
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
729
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_INT;
730
0
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_INT;
731
0
            break;
732
0
        case MVM_ARRAY_N64:
733
0
        case MVM_ARRAY_N32:
734
0
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
735
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NUM;
736
0
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_NUM;
737
0
            break;
738
0
        case MVM_ARRAY_U64:
739
0
        case MVM_ARRAY_U32:
740
0
        case MVM_ARRAY_U16:
741
0
        case MVM_ARRAY_U8:
742
0
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
743
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_INT;
744
0
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_INT;
745
0
            spec.is_unsigned     = 1;
746
0
            break;
747
0
        default:
748
0
            spec.inlineable      = MVM_STORAGE_SPEC_REFERENCE;
749
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NONE;
750
0
            spec.can_box         = 0;
751
0
            break;
752
0
    }
753
0
    return spec;
754
0
}
755
756
/* Initializes the representation. */
757
130
const MVMREPROps * MVMMultiDimArray_initialize(MVMThreadContext *tc) {
758
130
    return &MultiDimArray_this_repr;
759
130
}
760
761
static const MVMREPROps MultiDimArray_this_repr = {
762
    type_object_for,
763
    allocate,
764
    NULL, /* initialize */
765
    copy_to,
766
    MVM_REPR_DEFAULT_ATTR_FUNCS,
767
    MVM_REPR_DEFAULT_BOX_FUNCS,
768
    {
769
        at_pos,
770
        bind_pos,
771
        set_elems,
772
        push,
773
        pop,
774
        unshift,
775
        shift,
776
        asplice,
777
        at_pos_multidim,
778
        bind_pos_multidim,
779
        dimensions,
780
        set_dimensions,
781
        get_elem_storage_spec
782
    },
783
    MVM_REPR_DEFAULT_ASS_FUNCS,
784
    elems,
785
    get_storage_spec,
786
    NULL, /* change_type */
787
    serialize,
788
    deserialize,
789
    serialize_repr_data,
790
    deserialize_repr_data,
791
    deserialize_stable_size,
792
    gc_mark,
793
    gc_free,
794
    NULL, /* gc_cleanup */
795
    gc_mark_repr_data,
796
    gc_free_repr_data,
797
    compose,
798
    NULL, /* spesh */
799
    "MultiDimArray", /* name */
800
    MVM_REPR_ID_MultiDimArray,
801
    NULL, /* unmanaged_size */
802
    NULL, /* describe_refs */
803
};