Coverage Report

Created: 2018-07-03 15:31

/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
35
static MVMint64 flat_elements(MVMint64 num_dimensions, MVMint64 *dimensions) {
8
35
    MVMint64 result = dimensions[0];
9
35
    MVMint64 i;
10
57
    for (i = 1; i < num_dimensions; i++)
11
22
        result *= dimensions[i];
12
35
    return result;
13
35
}
14
15
/* Computes the flat size from representation data. */
16
33
static size_t flat_size(MVMMultiDimArrayREPRData *repr_data, MVMint64 *dimensions) {
17
33
    return repr_data->elem_size * flat_elements(repr_data->num_dimensions, dimensions);
18
33
}
19
20
/* Takes a number of dimensions, indices we were passed, and dimension sizes.
21
 * Computes the offset into flat space. */
22
153
MVM_STATIC_INLINE size_t indices_to_flat_index(MVMThreadContext *tc, MVMint64 num_dimensions, MVMint64 *dimensions, MVMint64 *indices) {
23
153
    MVMint64 multiplier = 1;
24
153
    size_t   result     = 0;
25
153
    MVMint64 i;
26
460
    for (i = num_dimensions - 1; i >= 0; i--) {
27
307
        MVMint64  dim_size = dimensions[i];
28
307
        MVMint64  index    = indices[i];
29
307
        if (index >= 0 && index < dim_size) {
30
283
            result += index * multiplier;
31
283
            multiplier *= dim_size;
32
283
        }
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
307
    }
39
153
    return result;
40
153
}
41
42
/* Creates a new type object of this representation, and associates it with
43
 * the given HOW. */
44
17
static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
45
17
    MVMSTable *st  = MVM_gc_allocate_stable(tc, &MultiDimArray_this_repr, HOW);
46
17
47
17
    MVMROOT(tc, st, {
48
17
        MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
49
17
        MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj);
50
17
        st->size = sizeof(MVMMultiDimArray);
51
17
    });
52
17
53
17
    return st->WHAT;
54
17
}
55
56
/* Allocates the mutli-dimensional array and sets up its dimensions array with
57
 * all zeroes, for later filling. */
58
42
static MVMObject * allocate(MVMThreadContext *tc, MVMSTable *st) {
59
42
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
60
42
    if (repr_data) {
61
42
        MVMObject *obj = MVM_gc_allocate_object(tc, st);
62
42
        ((MVMMultiDimArray *)obj)->body.dimensions = MVM_fixed_size_alloc_zeroed(tc,
63
42
            tc->instance->fsa, repr_data->num_dimensions * sizeof(MVMint64));
64
42
        return obj;
65
42
    }
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
42
}
71
72
/* Composes the representation. */
73
10
static void spec_to_repr_data(MVMThreadContext *tc, MVMMultiDimArrayREPRData *repr_data, const MVMStorageSpec *spec) {
74
10
    switch (spec->boxed_primitive) {
75
4
        case MVM_STORAGE_SPEC_BP_INT:
76
4
            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
4
            else {
112
4
                switch (spec->bits) {
113
4
                    case 64:
114
4
                        repr_data->slot_type = MVM_ARRAY_I64;
115
4
                        repr_data->elem_size = sizeof(MVMint64);
116
4
                        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
4
                }
145
4
            }
146
4
            break;
147
2
        case MVM_STORAGE_SPEC_BP_NUM:
148
2
            switch (spec->bits) {
149
2
                case 64:
150
2
                    repr_data->slot_type = MVM_ARRAY_N64;
151
2
                    repr_data->elem_size = sizeof(MVMnum64);
152
2
                    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
2
            }
161
2
            break;
162
2
        case MVM_STORAGE_SPEC_BP_STR:
163
2
            repr_data->slot_type = MVM_ARRAY_STR;
164
2
            repr_data->elem_size = sizeof(MVMString *);
165
2
            break;
166
2
        default:
167
2
            repr_data->slot_type = MVM_ARRAY_OBJ;
168
2
            repr_data->elem_size = sizeof(MVMObject *);
169
10
    }
170
10
}
171
16
static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *repr_info) {
172
16
    MVMStringConsts          *str_consts = &(tc->instance->str_consts);
173
16
    MVMMultiDimArrayREPRData *repr_data;
174
16
175
16
    MVMObject *info = MVM_repr_at_key_o(tc, repr_info, str_consts->array);
176
16
    if (!MVM_is_null(tc, info)) {
177
16
        MVMObject *dims = MVM_repr_at_key_o(tc, info, str_consts->dimensions);
178
16
        MVMObject *type = MVM_repr_at_key_o(tc, info, str_consts->type);
179
16
        MVMint64 dimensions;
180
16
        if (!MVM_is_null(tc, dims)) {
181
16
            dimensions = MVM_repr_get_int(tc, dims);
182
16
            if (dimensions < 1)
183
1
                MVM_exception_throw_adhoc(tc,
184
1
                    "MultiDimArray REPR must be composed with at least 1 dimension");
185
16
            repr_data = MVM_calloc(1, sizeof(MVMMultiDimArrayREPRData));
186
16
            repr_data->num_dimensions = dimensions;
187
16
        }
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
16
        if (!MVM_is_null(tc, type)) {
193
10
            const MVMStorageSpec *spec = REPR(type)->get_storage_spec(tc, STABLE(type));
194
10
            MVM_ASSIGN_REF(tc, &(st->header), repr_data->elem_type, type);
195
10
            spec_to_repr_data(tc, repr_data, spec);
196
10
        }
197
6
        else {
198
6
            repr_data->slot_type = MVM_ARRAY_OBJ;
199
6
            repr_data->elem_size = sizeof(MVMObject *);
200
6
        }
201
16
        st->REPR_data = repr_data;
202
16
    }
203
0
    else {
204
0
        MVM_exception_throw_adhoc(tc,
205
0
            "MultiDimArray REPR must be composed with array information");
206
0
    }
207
16
}
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
0
static void aslice(MVMThreadContext *tc, MVMSTable *st, MVMObject *src, void *data, MVMObject *dest, MVMint64 start, MVMint64 end) {
463
0
    MVM_exception_throw_adhoc(tc, "Cannot slice a multidim array");
464
0
}
465
1
static void asplice(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *from, MVMint64 offset, MVMuint64 count) {
466
1
    MVM_exception_throw_adhoc(tc, "Cannot splice a fixed dimension array");
467
1
}
468
469
90
static void at_pos_multidim(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_indices, MVMint64 *indices, MVMRegister *value, MVMuint16 kind) {
470
90
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
471
90
    if (num_indices == repr_data->num_dimensions) {
472
84
        MVMMultiDimArrayBody *body = (MVMMultiDimArrayBody *)data;
473
84
        size_t flat_index = indices_to_flat_index(tc, repr_data->num_dimensions, body->dimensions, indices);
474
84
        switch (repr_data->slot_type) {
475
35
            case MVM_ARRAY_OBJ:
476
35
                if (kind == MVM_reg_obj) {
477
35
                    MVMObject *found = body->slots.o[flat_index];
478
33
                    value->o = found ? found : tc->instance->VMNull;
479
35
                }
480
0
                else {
481
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected object register");
482
0
                }
483
35
                break;
484
5
            case MVM_ARRAY_STR:
485
5
                if (kind == MVM_reg_str)
486
5
                    value->s = body->slots.s[flat_index];
487
5
                else
488
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected string register");
489
5
                break;
490
27
            case MVM_ARRAY_I64:
491
27
                if (kind == MVM_reg_int64)
492
21
                    value->i64 = (MVMint64)body->slots.i64[flat_index];
493
27
                else
494
6
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
495
27
                break;
496
0
            case MVM_ARRAY_I32:
497
0
                if (kind == MVM_reg_int64)
498
0
                    value->i64 = (MVMint64)body->slots.i32[flat_index];
499
0
                else
500
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
501
0
                break;
502
0
            case MVM_ARRAY_I16:
503
0
                if (kind == MVM_reg_int64)
504
0
                    value->i64 = (MVMint64)body->slots.i16[flat_index];
505
0
                else
506
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
507
0
                break;
508
0
            case MVM_ARRAY_I8:
509
0
                if (kind == MVM_reg_int64)
510
0
                    value->i64 = (MVMint64)body->slots.i8[flat_index];
511
0
                else
512
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
513
0
                break;
514
5
            case MVM_ARRAY_N64:
515
5
                if (kind == MVM_reg_num64)
516
5
                    value->n64 = (MVMnum64)body->slots.n64[flat_index];
517
5
                else
518
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected num register");
519
5
                break;
520
0
            case MVM_ARRAY_N32:
521
0
                if (kind == MVM_reg_num64)
522
0
                    value->n64 = (MVMnum64)body->slots.n32[flat_index];
523
0
                else
524
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected num register");
525
0
                break;
526
0
            case MVM_ARRAY_U64:
527
0
                if (kind == MVM_reg_int64)
528
0
                    value->i64 = (MVMint64)body->slots.u64[flat_index];
529
0
                else
530
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
531
0
                break;
532
0
            case MVM_ARRAY_U32:
533
0
                if (kind == MVM_reg_int64)
534
0
                    value->i64 = (MVMint64)body->slots.u32[flat_index];
535
0
                else
536
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
537
0
                break;
538
0
            case MVM_ARRAY_U16:
539
0
                if (kind == MVM_reg_int64)
540
0
                    value->i64 = (MVMint64)body->slots.u16[flat_index];
541
0
                else
542
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
543
0
                break;
544
0
            case MVM_ARRAY_U8:
545
0
                if (kind == MVM_reg_int64)
546
0
                    value->i64 = (MVMint64)body->slots.u8[flat_index];
547
0
                else
548
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: atpos expected int register");
549
0
                break;
550
0
            default:
551
0
                MVM_exception_throw_adhoc(tc, "MultiDimArray: Unhandled slot type");
552
84
        }
553
84
    }
554
6
    else {
555
6
        MVM_exception_throw_adhoc(tc,
556
6
            "Cannot access %"PRId64" dimension array with %"PRId64" indices",
557
6
            repr_data->num_dimensions, num_indices);
558
6
    }
559
90
}
560
561
75
static void bind_pos_multidim(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_indices, MVMint64 *indices, MVMRegister value, MVMuint16 kind) {
562
75
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
563
75
    if (num_indices == repr_data->num_dimensions) {
564
69
        MVMMultiDimArrayBody *body = (MVMMultiDimArrayBody *)data;
565
69
        size_t flat_index = indices_to_flat_index(tc, repr_data->num_dimensions, body->dimensions, indices);
566
69
        switch (repr_data->slot_type) {
567
32
            case MVM_ARRAY_OBJ:
568
32
                if (kind == MVM_reg_obj) {
569
32
                    MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[flat_index], value.o);
570
32
                }
571
0
                else {
572
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected object register");
573
0
                }
574
32
                break;
575
3
            case MVM_ARRAY_STR:
576
3
                if (kind == MVM_reg_str) {
577
3
                    MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[flat_index], value.s);
578
3
                }
579
0
                else {
580
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected string register");
581
0
                }
582
3
                break;
583
19
            case MVM_ARRAY_I64:
584
19
                if (kind == MVM_reg_int64)
585
19
                    body->slots.i64[flat_index] = value.i64;
586
19
                else
587
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
588
19
                break;
589
0
            case MVM_ARRAY_I32:
590
0
                if (kind == MVM_reg_int64)
591
0
                    body->slots.i32[flat_index] = (MVMint32)value.i64;
592
0
                else
593
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
594
0
                break;
595
0
            case MVM_ARRAY_I16:
596
0
                if (kind == MVM_reg_int64)
597
0
                    body->slots.i16[flat_index] = (MVMint16)value.i64;
598
0
                else
599
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
600
0
                break;
601
0
            case MVM_ARRAY_I8:
602
0
                if (kind == MVM_reg_int64)
603
0
                    body->slots.i8[flat_index] = (MVMint8)value.i64;
604
0
                else
605
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
606
0
                break;
607
3
            case MVM_ARRAY_N64:
608
3
                if (kind == MVM_reg_num64)
609
3
                    body->slots.n64[flat_index] = value.n64;
610
3
                else
611
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected num register");
612
3
                break;
613
0
            case MVM_ARRAY_N32:
614
0
                if (kind == MVM_reg_num64)
615
0
                    body->slots.n32[flat_index] = (MVMnum32)value.n64;
616
0
                else
617
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected num register");
618
0
                break;
619
0
            case MVM_ARRAY_U64:
620
0
                if (kind == MVM_reg_int64)
621
0
                    body->slots.u64[flat_index] = value.i64;
622
0
                else
623
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
624
0
                break;
625
0
            case MVM_ARRAY_U32:
626
0
                if (kind == MVM_reg_int64)
627
0
                    body->slots.u32[flat_index] = (MVMuint32)value.i64;
628
0
                else
629
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
630
0
                break;
631
0
            case MVM_ARRAY_U16:
632
0
                if (kind == MVM_reg_int64)
633
0
                    body->slots.u16[flat_index] = (MVMuint16)value.i64;
634
0
                else
635
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
636
0
                break;
637
0
            case MVM_ARRAY_U8:
638
0
                if (kind == MVM_reg_int64)
639
0
                    body->slots.u8[flat_index] = (MVMuint8)value.i64;
640
0
                else
641
0
                    MVM_exception_throw_adhoc(tc, "MultiDimArray: bindpos expected int register");
642
0
                break;
643
0
            default:
644
0
                MVM_exception_throw_adhoc(tc, "MultiDimArray: Unhandled slot type");
645
69
        }
646
69
    }
647
6
    else {
648
6
        MVM_exception_throw_adhoc(tc,
649
6
            "Cannot access %"PRId64" dimension array with %"PRId64" indices",
650
6
            repr_data->num_dimensions, num_indices);
651
6
    }
652
75
}
653
654
13
static void dimensions(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 *num_dimensions, MVMint64 **dimensions) {
655
13
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
656
13
    if (repr_data) {
657
13
        MVMMultiDimArrayBody *body = (MVMMultiDimArrayBody *)data;
658
13
        *num_dimensions = repr_data->num_dimensions;
659
13
        *dimensions = body->dimensions;
660
13
    }
661
0
    else {
662
0
        MVM_exception_throw_adhoc(tc,
663
0
            "Cannot query a multi-dim array's dimensionality before it is composed");
664
0
    }
665
13
}
666
667
37
static void set_dimensions(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_dimensions, MVMint64 *dimensions) {
668
37
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
669
37
    if (num_dimensions == repr_data->num_dimensions) {
670
31
        /* Note that we use an atomic operation at the point of allocation.
671
31
         * This means we can be leak-free and memory safe in the face of
672
31
         * multiple threads competing to set dimensions (unlikely in any
673
31
         * real world use case, but we should ensure the VM is memory safe).
674
31
         */
675
31
        MVMMultiDimArrayBody *body = (MVMMultiDimArrayBody *)data;
676
31
        size_t size = flat_size(repr_data, dimensions);
677
31
        void *storage = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, size);
678
31
        if (MVM_trycas(&(body->slots.any), NULL, storage)) {
679
28
            /* Now memory is in place, safe to un-zero dimensions. */
680
28
            memcpy(body->dimensions, dimensions, num_dimensions * sizeof(MVMint64));
681
28
        }
682
3
        else {
683
3
            MVM_exception_throw_adhoc(tc, "MultiDimArray: can only set dimensions once");
684
3
        }
685
31
    }
686
6
    else {
687
6
        MVM_exception_throw_adhoc(tc,
688
6
            "Array type of %"PRId64" dimensions cannot be initialized with %"PRId64" dimensions",
689
6
            repr_data->num_dimensions, num_dimensions);
690
6
    }
691
37
}
692
693
10
static void at_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister *value, MVMuint16 kind) {
694
10
    at_pos_multidim(tc, st, root, data, 1, &index, value, kind);
695
10
}
696
697
6
static void bind_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister value, MVMuint16 kind) {
698
6
    bind_pos_multidim(tc, st, root, data, 1, &index, value, kind);
699
6
}
700
701
3
static void set_elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMuint64 count) {
702
3
    set_dimensions(tc, st, root, data, 1, (MVMint64 *)&count);
703
3
}
704
705
2
static MVMuint64 elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) {
706
2
    MVMint64  _;
707
2
    MVMint64 *dims;
708
2
    dimensions(tc, st, root, data, &_, &dims);
709
2
    return (MVMuint64)dims[0];
710
2
}
711
712
0
static MVMStorageSpec get_elem_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
713
0
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
714
0
    MVMStorageSpec spec;
715
0
716
0
    /* initialise storage spec to default values */
717
0
    spec.bits            = 0;
718
0
    spec.align           = 0;
719
0
    spec.is_unsigned     = 0;
720
0
721
0
    switch (repr_data->slot_type) {
722
0
        case MVM_ARRAY_STR:
723
0
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
724
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_STR;
725
0
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_STR;
726
0
            break;
727
0
        case MVM_ARRAY_I64:
728
0
        case MVM_ARRAY_I32:
729
0
        case MVM_ARRAY_I16:
730
0
        case MVM_ARRAY_I8:
731
0
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
732
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_INT;
733
0
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_INT;
734
0
            break;
735
0
        case MVM_ARRAY_N64:
736
0
        case MVM_ARRAY_N32:
737
0
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
738
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NUM;
739
0
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_NUM;
740
0
            break;
741
0
        case MVM_ARRAY_U64:
742
0
        case MVM_ARRAY_U32:
743
0
        case MVM_ARRAY_U16:
744
0
        case MVM_ARRAY_U8:
745
0
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
746
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_INT;
747
0
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_INT;
748
0
            spec.is_unsigned     = 1;
749
0
            break;
750
0
        default:
751
0
            spec.inlineable      = MVM_STORAGE_SPEC_REFERENCE;
752
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NONE;
753
0
            spec.can_box         = 0;
754
0
            break;
755
0
    }
756
0
    return spec;
757
0
}
758
759
AO_t * pos_as_atomic_multidim(MVMThreadContext *tc, MVMSTable *st,
760
                              MVMObject *root, void *data,
761
0
                              MVMint64 num_indices, MVMint64 *indices) {
762
0
    MVMMultiDimArrayREPRData *repr_data = (MVMMultiDimArrayREPRData *)st->REPR_data;
763
0
    if (num_indices == repr_data->num_dimensions) {
764
0
        MVMMultiDimArrayBody *body = (MVMMultiDimArrayBody *)data;
765
0
        size_t flat_index = indices_to_flat_index(tc, repr_data->num_dimensions,
766
0
            body->dimensions, indices);
767
0
        if (sizeof(AO_t) == 8 && (repr_data->slot_type == MVM_ARRAY_I64 ||
768
0
                repr_data->slot_type == MVM_ARRAY_U64))
769
0
            return (AO_t *)&(body->slots.i64[flat_index]);
770
0
        if (sizeof(AO_t) == 4 && (repr_data->slot_type == MVM_ARRAY_I32 ||
771
0
                repr_data->slot_type == MVM_ARRAY_U32))
772
0
            return (AO_t *)&(body->slots.i32[flat_index]);
773
0
        MVM_exception_throw_adhoc(tc,
774
0
            "Can only do integer atomic operation on native integer array element of atomic size");
775
0
    }
776
0
    else {
777
0
        MVM_exception_throw_adhoc(tc,
778
0
            "Cannot access %"PRId64" dimension array with %"PRId64" indices",
779
0
            repr_data->num_dimensions, num_indices);
780
0
    }
781
0
}
782
783
static AO_t * pos_as_atomic(MVMThreadContext *tc, MVMSTable *st, MVMObject *root,
784
0
                            void *data, MVMint64 index) {
785
0
    return pos_as_atomic_multidim(tc, st, root, data, 1, &index);
786
0
}
787
788
789
/* Initializes the representation. */
790
144
const MVMREPROps * MVMMultiDimArray_initialize(MVMThreadContext *tc) {
791
144
    return &MultiDimArray_this_repr;
792
144
}
793
794
static const MVMREPROps MultiDimArray_this_repr = {
795
    type_object_for,
796
    allocate,
797
    NULL, /* initialize */
798
    copy_to,
799
    MVM_REPR_DEFAULT_ATTR_FUNCS,
800
    MVM_REPR_DEFAULT_BOX_FUNCS,
801
    {
802
        at_pos,
803
        bind_pos,
804
        set_elems,
805
        push,
806
        pop,
807
        unshift,
808
        shift,
809
        aslice,
810
        asplice,
811
        at_pos_multidim,
812
        bind_pos_multidim,
813
        dimensions,
814
        set_dimensions,
815
        get_elem_storage_spec,
816
        pos_as_atomic,
817
        pos_as_atomic_multidim
818
    },
819
    MVM_REPR_DEFAULT_ASS_FUNCS,
820
    elems,
821
    get_storage_spec,
822
    NULL, /* change_type */
823
    serialize,
824
    deserialize,
825
    serialize_repr_data,
826
    deserialize_repr_data,
827
    deserialize_stable_size,
828
    gc_mark,
829
    gc_free,
830
    NULL, /* gc_cleanup */
831
    gc_mark_repr_data,
832
    gc_free_repr_data,
833
    compose,
834
    NULL, /* spesh */
835
    "MultiDimArray", /* name */
836
    MVM_REPR_ID_MultiDimArray,
837
    NULL, /* unmanaged_size */
838
    NULL, /* describe_refs */
839
};