Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/6model/reprs/VMArray.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
#include "limits.h"
3
4
/* This representation's function pointer table. */
5
static const MVMREPROps VMArray_this_repr;
6
7
26.2M
MVM_STATIC_INLINE void enter_single_user(MVMThreadContext *tc, MVMArrayBody *arr) {
8
26.2M
#if MVM_ARRAY_CONC_DEBUG
9
    if (!MVM_trycas(&(arr->in_use), 0, 1)) {
10
        MVM_dump_backtrace(tc);
11
        MVM_exception_throw_adhoc(tc, "Array may not be used concurrently");
12
    }
13
#endif
14
26.2M
}
15
26.2M
static void exit_single_user(MVMThreadContext *tc, MVMArrayBody *arr) {
16
26.2M
#if MVM_ARRAY_CONC_DEBUG
17
    arr->in_use = 0;
18
#endif
19
26.2M
}
20
21
/* Creates a new type object of this representation, and associates it with
22
 * the given HOW. */
23
743
static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
24
743
    MVMSTable        *st = MVM_gc_allocate_stable(tc, &VMArray_this_repr, HOW);
25
743
26
743
    MVMROOT(tc, st, {
27
743
        MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
28
743
        MVMArrayREPRData *repr_data = (MVMArrayREPRData *)MVM_malloc(sizeof(MVMArrayREPRData));
29
743
30
743
        repr_data->slot_type = MVM_ARRAY_OBJ;
31
743
        repr_data->elem_size = sizeof(MVMObject *);
32
743
        repr_data->elem_type = NULL;
33
743
34
743
        MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj);
35
743
        st->size = sizeof(MVMArray);
36
743
        st->REPR_data = repr_data;
37
743
    });
38
743
39
743
    return st->WHAT;
40
743
}
41
42
/* Copies the body of one object to another. The result has the space
43
 * needed for the current number of elements, which may not be the
44
 * entire allocated slot size. */
45
5.87k
static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) {
46
5.87k
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
47
5.87k
    MVMArrayBody     *src_body  = (MVMArrayBody *)src;
48
5.87k
    MVMArrayBody     *dest_body = (MVMArrayBody *)dest;
49
5.87k
    dest_body->elems = src_body->elems;
50
5.87k
    dest_body->ssize = src_body->elems;
51
5.87k
    dest_body->start = 0;
52
5.87k
    if (dest_body->elems > 0) {
53
5.85k
        size_t  mem_size     = dest_body->ssize * repr_data->elem_size;
54
5.85k
        size_t  start_pos    = src_body->start * repr_data->elem_size;
55
5.85k
        char   *copy_start   = ((char *)src_body->slots.any) + start_pos;
56
5.85k
        dest_body->slots.any = MVM_malloc(mem_size);
57
5.85k
        memcpy(dest_body->slots.any, copy_start, mem_size);
58
5.85k
    }
59
24
    else {
60
24
        dest_body->slots.any = NULL;
61
24
    }
62
5.87k
}
63
64
/* Adds held objects to the GC worklist. */
65
469k
static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) {
66
469k
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
67
469k
    MVMArrayBody     *body      = (MVMArrayBody *)data;
68
469k
    MVMuint64         elems     = body->elems;
69
469k
    MVMuint64         start     = body->start;
70
469k
    MVMuint64         i         = 0;
71
469k
    switch (repr_data->slot_type) {
72
448k
        case MVM_ARRAY_OBJ: {
73
448k
            MVMObject **slots = body->slots.o;
74
448k
            slots += start;
75
1.50M
            while (i < elems) {
76
1.05M
                MVM_gc_worklist_add(tc, worklist, &slots[i]);
77
1.05M
                i++;
78
1.05M
            }
79
448k
            break;
80
448k
        }
81
8.57k
        case MVM_ARRAY_STR: {
82
8.57k
            MVMString **slots = body->slots.s;
83
8.57k
            slots += start;
84
80.2k
            while (i < elems) {
85
71.6k
                MVM_gc_worklist_add(tc, worklist, &slots[i]);
86
71.6k
                i++;
87
71.6k
            }
88
8.57k
            break;
89
448k
        }
90
469k
    }
91
469k
}
92
93
/* Called by the VM in order to free memory associated with this object. */
94
1.96M
static void gc_free(MVMThreadContext *tc, MVMObject *obj) {
95
1.96M
    MVMArray *arr = (MVMArray *)obj;
96
1.96M
    MVM_free(arr->body.slots.any);
97
1.96M
}
98
99
/* Marks the representation data in an STable.*/
100
358
static void gc_mark_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMGCWorklist *worklist) {
101
358
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
102
358
    if (repr_data == NULL)
103
0
        return;
104
358
    MVM_gc_worklist_add(tc, worklist, &repr_data->elem_type);
105
358
}
106
107
/* Frees the representation data in an STable.*/
108
0
static void gc_free_repr_data(MVMThreadContext *tc, MVMSTable *st) {
109
0
    MVM_free(st->REPR_data);
110
0
}
111
112
113
static const MVMStorageSpec storage_spec = {
114
    MVM_STORAGE_SPEC_REFERENCE, /* inlineable */
115
    0,                          /* bits */
116
    0,                          /* align */
117
    MVM_STORAGE_SPEC_BP_NONE,   /* boxed_primitive */
118
    0,                          /* can_box */
119
    0,                          /* is_unsigned */
120
};
121
122
123
/* Gets the storage specification for this representation. */
124
245k
static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
125
245k
    return &storage_spec;
126
245k
}
127
128
22.0M
static void at_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister *value, MVMuint16 kind) {
129
22.0M
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
130
22.0M
    MVMArrayBody     *body      = (MVMArrayBody *)data;
131
22.0M
132
22.0M
    /* Handle negative indexes. */
133
22.0M
    if (index < 0) {
134
68.9k
        index += body->elems;
135
68.9k
        if (index < 0)
136
0
            MVM_exception_throw_adhoc(tc, "MVMArray: Index out of bounds");
137
68.9k
    }
138
22.0M
139
22.0M
    /* Go by type. */
140
22.0M
    switch (repr_data->slot_type) {
141
12.4M
        case MVM_ARRAY_OBJ:
142
12.4M
            if (kind != MVM_reg_obj)
143
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected object register");
144
12.4M
            if (index >= body->elems) {
145
41.5k
                value->o = tc->instance->VMNull;
146
41.5k
            }
147
12.4M
            else {
148
12.4M
                MVMObject *found = body->slots.o[body->start + index];
149
12.4M
                value->o = found ? found : tc->instance->VMNull;
150
12.4M
            }
151
12.4M
            break;
152
62.6k
        case MVM_ARRAY_STR:
153
62.6k
            if (kind != MVM_reg_str)
154
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected string register");
155
62.6k
            if (index >= body->elems)
156
1
                value->s = NULL;
157
62.6k
            else
158
62.6k
                value->s = body->slots.s[body->start + index];
159
62.6k
            break;
160
9.51M
        case MVM_ARRAY_I64:
161
9.51M
            if (kind != MVM_reg_int64)
162
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register");
163
9.51M
            if (index >= body->elems)
164
1.63M
                value->i64 = 0;
165
9.51M
            else
166
7.87M
                value->i64 = (MVMint64)body->slots.i64[body->start + index];
167
9.51M
            break;
168
0
        case MVM_ARRAY_I32:
169
0
            if (kind != MVM_reg_int64)
170
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register");
171
0
            if (index >= body->elems)
172
0
                value->i64 = 0;
173
0
            else
174
0
                value->i64 = (MVMint64)body->slots.i32[body->start + index];
175
0
            break;
176
0
        case MVM_ARRAY_I16:
177
0
            if (kind != MVM_reg_int64)
178
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register");
179
0
            if (index >= body->elems)
180
0
                value->i64 = 0;
181
0
            else
182
0
                value->i64 = (MVMint64)body->slots.i16[body->start + index];
183
0
            break;
184
9
        case MVM_ARRAY_I8:
185
9
            if (kind != MVM_reg_int64)
186
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register");
187
9
            if (index >= body->elems)
188
0
                value->i64 = 0;
189
9
            else
190
9
                value->i64 = (MVMint64)body->slots.i8[body->start + index];
191
9
            break;
192
17
        case MVM_ARRAY_N64:
193
17
            if (kind != MVM_reg_num64)
194
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected num register");
195
17
            if (index >= body->elems)
196
1
                value->n64 = 0.0;
197
17
            else
198
16
                value->n64 = (MVMnum64)body->slots.n64[body->start + index];
199
17
            break;
200
0
        case MVM_ARRAY_N32:
201
0
            if (kind != MVM_reg_num64)
202
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected num register");
203
0
            if (index >= body->elems)
204
0
                value->n64 = 0.0;
205
0
            else
206
0
                value->n64 = (MVMnum64)body->slots.n32[body->start + index];
207
0
            break;
208
0
        case MVM_ARRAY_U64:
209
0
            if (kind != MVM_reg_int64)
210
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register");
211
0
            if (index >= body->elems)
212
0
                value->i64 = 0;
213
0
            else
214
0
                value->i64 = (MVMint64)body->slots.u64[body->start + index];
215
0
            break;
216
6
        case MVM_ARRAY_U32:
217
6
            if (kind != MVM_reg_int64)
218
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register");
219
6
            if (index >= body->elems)
220
0
                value->i64 = 0;
221
6
            else
222
6
                value->i64 = (MVMint64)body->slots.u32[body->start + index];
223
6
            break;
224
0
        case MVM_ARRAY_U16:
225
0
            if (kind != MVM_reg_int64)
226
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register");
227
0
            if (index >= body->elems)
228
0
                value->i64 = 0;
229
0
            else
230
0
                value->i64 = (MVMint64)body->slots.u16[body->start + index];
231
0
            break;
232
75
        case MVM_ARRAY_U8:
233
75
            if (kind != MVM_reg_int64)
234
0
                MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register");
235
75
            if (index >= body->elems)
236
0
                value->i64 = 0;
237
75
            else
238
75
                value->i64 = (MVMint64)body->slots.u8[body->start + index];
239
75
            break;
240
0
        default:
241
0
            MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type, got '%s'", MVM_reg_get_debug_name(tc, repr_data->slot_type));
242
22.0M
    }
243
22.0M
}
244
9.85M
void MVM_VMArray_at_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister *value, MVMuint16 kind) {
245
9.85M
    return at_pos(tc, st, root, data, index, value, kind);
246
9.85M
}
247
248
static MVMuint64 zero_slots(MVMThreadContext *tc, MVMArrayBody *body,
249
7.54M
        MVMuint64 elems, MVMuint64 ssize, MVMuint8 slot_type) {
250
7.54M
    switch (slot_type) {
251
1.49M
        case MVM_ARRAY_OBJ:
252
14.1M
            while (elems < ssize)
253
12.6M
                body->slots.o[elems++] = NULL;
254
1.49M
            break;
255
20.5k
        case MVM_ARRAY_STR:
256
345k
            while (elems < ssize)
257
324k
                body->slots.s[elems++] = NULL;
258
20.5k
            break;
259
6.03M
        case MVM_ARRAY_I64:
260
27.2M
            while (elems < ssize)
261
21.1M
                body->slots.i64[elems++] = 0;
262
6.03M
            break;
263
0
        case MVM_ARRAY_I32:
264
0
            while (elems < ssize)
265
0
                body->slots.i32[elems++] = 0;
266
0
            break;
267
0
        case MVM_ARRAY_I16:
268
0
            while (elems < ssize)
269
0
                body->slots.i16[elems++] = 0;
270
0
            break;
271
1
        case MVM_ARRAY_I8:
272
9
            while (elems < ssize)
273
8
                body->slots.i8[elems++] = 0;
274
1
            break;
275
14
        case MVM_ARRAY_N64:
276
96
            while (elems < ssize)
277
82
                body->slots.n64[elems++] = 0.0;
278
14
            break;
279
0
        case MVM_ARRAY_N32:
280
0
            while (elems < ssize)
281
0
                body->slots.n32[elems++] = 0.0;
282
0
            break;
283
0
        case MVM_ARRAY_U64:
284
0
            while (elems < ssize)
285
0
                body->slots.u64[elems++] = 0;
286
0
            break;
287
4
        case MVM_ARRAY_U32:
288
36
            while (elems < ssize)
289
32
                body->slots.u32[elems++] = 0;
290
4
            break;
291
0
        case MVM_ARRAY_U16:
292
0
            while (elems < ssize)
293
0
                body->slots.u16[elems++] = 0;
294
0
            break;
295
7
        case MVM_ARRAY_U8:
296
63
            while (elems < ssize)
297
56
                body->slots.u8[elems++] = 0;
298
7
            break;
299
0
        default:
300
0
            MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type");
301
7.54M
    }
302
7.54M
    return elems;
303
7.54M
}
304
305
19.9M
static void set_size_internal(MVMThreadContext *tc, MVMArrayBody *body, MVMuint64 n, MVMArrayREPRData *repr_data) {
306
19.9M
    MVMuint64   elems = body->elems;
307
19.9M
    MVMuint64   start = body->start;
308
19.9M
    MVMuint64   ssize = body->ssize;
309
19.9M
    void       *slots = body->slots.any;
310
19.9M
311
19.9M
    if (n == elems)
312
149k
        return;
313
19.9M
314
19.7M
    if (start > 0 && n + start > ssize) {
315
40
        /* if there aren't enough slots at the end, shift off empty slots
316
40
         * from the beginning first */
317
40
        if (elems > 0)
318
40
            memmove(slots,
319
40
                (char *)slots + start * repr_data->elem_size,
320
40
                elems * repr_data->elem_size);
321
40
        body->start = 0;
322
40
        /* fill out any unused slots with NULL pointers or zero values */
323
40
        zero_slots(tc, body, elems, start+elems, repr_data->slot_type);
324
40
        elems = ssize; /* we'll use this as a point to clear from later */
325
40
    }
326
19.7M
    else if (n < elems) {
327
815k
        /* we're downsizing; clear off extra slots */
328
815k
        zero_slots(tc, body, n+start, start+elems, repr_data->slot_type);
329
815k
    }
330
19.7M
331
19.7M
    if (n <= ssize) {
332
17.4M
        /* we already have n slots available, we can just return */
333
17.4M
        body->elems = n;
334
17.4M
        return;
335
17.4M
    }
336
19.7M
337
19.7M
    /* We need more slots.  If the current slot size is less
338
19.7M
     * than 8K, use the larger of twice the current slot size
339
19.7M
     * or the actual number of elements needed.  Otherwise,
340
19.7M
     * grow the slots to the next multiple of 4096 (0x1000). */
341
2.28M
    if (ssize < 8192) {
342
2.28M
        ssize *= 2;
343
2.28M
        if (n > ssize) ssize = n;
344
2.28M
        if (ssize < 8) ssize = 8;
345
2.28M
    }
346
18.4E
    else {
347
18.4E
        ssize = (n + 0x1000) & ~0xfffUL;
348
18.4E
    }
349
2.28M
    {
350
2.28M
        /* Our budget is 2^(
351
2.28M
         *     <number of bits in an array index>
352
2.28M
         *     - <number of bits to address individual bytes in an array element>
353
2.28M
         * ) */
354
2.28M
        size_t const elem_addr_size = repr_data->elem_size == 8 ? 4 :
355
18.4E
                                      repr_data->elem_size == 4 ? 3 :
356
18.4E
                                      repr_data->elem_size == 2 ? 2 :
357
18.4E
                                                                  1;
358
2.28M
        if (ssize > (1ULL << (CHAR_BIT * sizeof(size_t) - elem_addr_size)))
359
0
            MVM_exception_throw_adhoc(tc,
360
0
                "Unable to allocate an array of %"PRIu64" elements",
361
0
                ssize);
362
2.28M
    }
363
2.28M
364
2.28M
    /* now allocate the new slot buffer */
365
2.28M
    slots = (slots)
366
453k
            ? MVM_realloc(slots, ssize * repr_data->elem_size)
367
1.83M
            : MVM_malloc(ssize * repr_data->elem_size);
368
2.28M
369
2.28M
    /* fill out any unused slots with NULL pointers or zero values */
370
2.28M
    body->slots.any = slots;
371
2.28M
    zero_slots(tc, body, elems, ssize, repr_data->slot_type);
372
2.28M
373
2.28M
    body->ssize = ssize;
374
2.28M
    /* set elems last so no thread tries to access slots before they are available */
375
2.28M
    body->elems = n;
376
2.28M
}
377
378
2.84M
static void bind_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister value, MVMuint16 kind) {
379
2.84M
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
380
2.84M
    MVMArrayBody     *body      = (MVMArrayBody *)data;
381
2.84M
382
2.84M
    /* Handle negative indexes and resizing if needed. */
383
2.84M
    enter_single_user(tc, body);
384
2.84M
    if (index < 0) {
385
45.2k
        index += body->elems;
386
45.2k
        if (index < 0)
387
0
            MVM_exception_throw_adhoc(tc, "MVMArray: Index out of bounds");
388
45.2k
    }
389
2.80M
    else if (index >= body->elems)
390
978k
        set_size_internal(tc, body, index + 1, repr_data);
391
2.84M
392
2.84M
    /* Go by type. */
393
2.84M
    switch (repr_data->slot_type) {
394
2.00M
        case MVM_ARRAY_OBJ:
395
2.00M
            if (kind != MVM_reg_obj)
396
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected object register");
397
2.00M
            MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[body->start + index], value.o);
398
2.00M
            break;
399
161k
        case MVM_ARRAY_STR:
400
161k
            if (kind != MVM_reg_str)
401
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected string register");
402
161k
            MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[body->start + index], value.s);
403
161k
            break;
404
684k
        case MVM_ARRAY_I64:
405
684k
            if (kind != MVM_reg_int64)
406
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register");
407
684k
            body->slots.i64[body->start + index] = value.i64;
408
684k
            break;
409
0
        case MVM_ARRAY_I32:
410
0
            if (kind != MVM_reg_int64)
411
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register");
412
0
            body->slots.i32[body->start + index] = (MVMint32)value.i64;
413
0
            break;
414
0
        case MVM_ARRAY_I16:
415
0
            if (kind != MVM_reg_int64)
416
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register");
417
0
            body->slots.i16[body->start + index] = (MVMint16)value.i64;
418
0
            break;
419
0
        case MVM_ARRAY_I8:
420
0
            if (kind != MVM_reg_int64)
421
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register");
422
0
            body->slots.i8[body->start + index] = (MVMint8)value.i64;
423
0
            break;
424
10
        case MVM_ARRAY_N64:
425
10
            if (kind != MVM_reg_num64)
426
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected num register");
427
10
            body->slots.n64[body->start + index] = value.n64;
428
10
            break;
429
0
        case MVM_ARRAY_N32:
430
0
            if (kind != MVM_reg_num64)
431
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected num register");
432
0
            body->slots.n32[body->start + index] = (MVMnum32)value.n64;
433
0
            break;
434
0
        case MVM_ARRAY_U64:
435
0
            if (kind != MVM_reg_int64)
436
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register");
437
0
            body->slots.u64[body->start + index] = value.i64;
438
0
            break;
439
0
        case MVM_ARRAY_U32:
440
0
            if (kind != MVM_reg_int64)
441
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register");
442
0
            body->slots.u32[body->start + index] = (MVMuint32)value.i64;
443
0
            break;
444
0
        case MVM_ARRAY_U16:
445
0
            if (kind != MVM_reg_int64)
446
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register");
447
0
            body->slots.u16[body->start + index] = (MVMuint16)value.i64;
448
0
            break;
449
0
        case MVM_ARRAY_U8:
450
0
            if (kind != MVM_reg_int64)
451
0
                MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register");
452
0
            body->slots.u8[body->start + index] = (MVMuint8)value.i64;
453
0
            break;
454
0
        default:
455
0
            MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type");
456
2.84M
    }
457
2.84M
    exit_single_user(tc, body);
458
2.84M
}
459
460
11.7M
static MVMuint64 elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) {
461
11.7M
    MVMArrayBody *body = (MVMArrayBody *)data;
462
11.7M
    return body->elems;
463
11.7M
}
464
465
1.08M
static void set_elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMuint64 count) {
466
1.08M
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
467
1.08M
    MVMArrayBody     *body      = (MVMArrayBody *)data;
468
1.08M
    enter_single_user(tc, body);
469
1.08M
    set_size_internal(tc, body, count, repr_data);
470
1.08M
    exit_single_user(tc, body);
471
1.08M
}
472
473
17.7M
static void push(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister value, MVMuint16 kind) {
474
17.7M
    MVMArrayBody     *body      = (MVMArrayBody *)data;
475
17.7M
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
476
17.7M
    enter_single_user(tc, body);
477
17.7M
    set_size_internal(tc, body, body->elems + 1, repr_data);
478
17.7M
    switch (repr_data->slot_type) {
479
3.08M
        case MVM_ARRAY_OBJ:
480
3.08M
            if (kind != MVM_reg_obj)
481
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected object register");
482
3.08M
            MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[body->start + body->elems - 1], value.o);
483
3.08M
            break;
484
34.3k
        case MVM_ARRAY_STR:
485
34.3k
            if (kind != MVM_reg_str)
486
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected string register");
487
34.3k
            MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[body->start + body->elems - 1], value.s);
488
34.3k
            break;
489
14.6M
        case MVM_ARRAY_I64:
490
14.6M
            if (kind != MVM_reg_int64)
491
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register");
492
14.6M
            body->slots.i64[body->start + body->elems - 1] = value.i64;
493
14.6M
            break;
494
0
        case MVM_ARRAY_I32:
495
0
            if (kind != MVM_reg_int64)
496
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register");
497
0
            body->slots.i32[body->start + body->elems - 1] = (MVMint32)value.i64;
498
0
            break;
499
0
        case MVM_ARRAY_I16:
500
0
            if (kind != MVM_reg_int64)
501
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register");
502
0
            body->slots.i16[body->start + body->elems - 1] = (MVMint16)value.i64;
503
0
            break;
504
2
        case MVM_ARRAY_I8:
505
2
            if (kind != MVM_reg_int64)
506
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register");
507
2
            body->slots.i8[body->start + body->elems - 1] = (MVMint8)value.i64;
508
2
            break;
509
12
        case MVM_ARRAY_N64:
510
12
            if (kind != MVM_reg_num64)
511
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected num register");
512
12
            body->slots.n64[body->start + body->elems - 1] = value.n64;
513
12
            break;
514
0
        case MVM_ARRAY_N32:
515
0
            if (kind != MVM_reg_num64)
516
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected num register");
517
0
            body->slots.n32[body->start + body->elems - 1] = (MVMnum32)value.n64;
518
0
            break;
519
0
        case MVM_ARRAY_U64:
520
0
            if (kind != MVM_reg_int64)
521
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register");
522
0
            body->slots.u64[body->start + body->elems - 1] = (MVMuint64)value.i64;
523
0
            break;
524
9
        case MVM_ARRAY_U32:
525
9
            if (kind != MVM_reg_int64)
526
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register");
527
9
            body->slots.u32[body->start + body->elems - 1] = (MVMuint32)value.i64;
528
9
            break;
529
0
        case MVM_ARRAY_U16:
530
0
            if (kind != MVM_reg_int64)
531
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register");
532
0
            body->slots.u16[body->start + body->elems - 1] = (MVMuint16)value.i64;
533
0
            break;
534
18
        case MVM_ARRAY_U8:
535
18
            if (kind != MVM_reg_int64)
536
0
                MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register");
537
18
            body->slots.u8[body->start + body->elems - 1] = (MVMuint8)value.i64;
538
18
            break;
539
0
        default:
540
0
            MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type");
541
17.7M
    }
542
17.7M
    exit_single_user(tc, body);
543
17.7M
}
544
545
4.42M
static void pop(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) {
546
4.42M
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
547
4.42M
    MVMArrayBody     *body      = (MVMArrayBody *)data;
548
4.42M
    const MVMuint64 slot        = body->start + body->elems - 1;
549
4.42M
550
4.42M
    if (body->elems < 1)
551
0
        MVM_exception_throw_adhoc(tc,
552
0
            "MVMArray: Can't pop from an empty array");
553
4.42M
554
4.42M
    enter_single_user(tc, body);
555
4.42M
    body->elems--;
556
4.42M
    switch (repr_data->slot_type) {
557
166k
        case MVM_ARRAY_OBJ:
558
166k
            if (kind != MVM_reg_obj)
559
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected object register");
560
166k
            value->o = body->slots.o[slot];
561
166k
            break;
562
1
        case MVM_ARRAY_STR:
563
1
            if (kind != MVM_reg_str)
564
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected string register");
565
1
            value->s = body->slots.s[slot];
566
1
            break;
567
4.25M
        case MVM_ARRAY_I64:
568
4.25M
            if (kind != MVM_reg_int64)
569
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register");
570
4.25M
            value->i64 = (MVMint64)body->slots.i64[slot];
571
4.25M
            break;
572
0
        case MVM_ARRAY_I32:
573
0
            if (kind != MVM_reg_int64)
574
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register");
575
0
            value->i64 = (MVMint64)body->slots.i32[slot];
576
0
            break;
577
0
        case MVM_ARRAY_I16:
578
0
            if (kind != MVM_reg_int64)
579
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register");
580
0
            value->i64 = (MVMint64)body->slots.i16[slot];
581
0
            break;
582
0
        case MVM_ARRAY_I8:
583
0
            if (kind != MVM_reg_int64)
584
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register");
585
0
            value->i64 = (MVMint64)body->slots.i8[slot];
586
0
            break;
587
1
        case MVM_ARRAY_N64:
588
1
            if (kind != MVM_reg_num64)
589
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected num register");
590
1
            value->n64 = (MVMnum64)body->slots.n64[slot];
591
1
            break;
592
0
        case MVM_ARRAY_N32:
593
0
            if (kind != MVM_reg_num64)
594
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected num register");
595
0
            value->n64 = (MVMnum64)body->slots.n32[slot];
596
0
            break;
597
0
        case MVM_ARRAY_U64:
598
0
            if (kind != MVM_reg_int64)
599
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register");
600
0
            value->i64 = (MVMint64)body->slots.u64[slot];
601
0
            break;
602
0
        case MVM_ARRAY_U32:
603
0
            if (kind != MVM_reg_int64)
604
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register");
605
0
            value->i64 = (MVMint64)body->slots.u32[slot];
606
0
            break;
607
0
        case MVM_ARRAY_U16:
608
0
            if (kind != MVM_reg_int64)
609
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register");
610
0
            value->i64 = (MVMint64)body->slots.u16[slot];
611
0
            break;
612
0
        case MVM_ARRAY_U8:
613
0
            if (kind != MVM_reg_int64)
614
0
                MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register");
615
0
            value->i64 = (MVMint64)body->slots.u8[slot];
616
0
            break;
617
0
        default:
618
0
            MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type");
619
4.42M
    }
620
4.42M
    zero_slots(tc, body, slot, slot + 1, repr_data->slot_type);
621
4.42M
    exit_single_user(tc, body);
622
4.42M
}
623
624
39.0k
static void unshift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister value, MVMuint16 kind) {
625
39.0k
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
626
39.0k
    MVMArrayBody     *body      = (MVMArrayBody *)data;
627
39.0k
628
39.0k
    /* If we don't have room at the beginning of the slots,
629
39.0k
     * make some room (8 slots) for unshifting */
630
39.0k
    enter_single_user(tc, body);
631
39.0k
    if (body->start < 1) {
632
24.4k
        MVMuint64 n = 8;
633
24.4k
        MVMuint64 elems = body->elems;
634
24.4k
635
24.4k
        /* grow the array */
636
24.4k
        set_size_internal(tc, body, elems + n, repr_data);
637
24.4k
638
24.4k
        /* move elements and set start */
639
24.4k
        memmove(
640
24.4k
            (char *)body->slots.any + n * repr_data->elem_size,
641
24.4k
            body->slots.any,
642
24.4k
            elems * repr_data->elem_size);
643
24.4k
        body->start = n;
644
24.4k
        body->elems = elems;
645
24.4k
646
24.4k
        /* clear out beginning elements */
647
24.4k
        zero_slots(tc, body, 0, n, repr_data->slot_type);
648
24.4k
    }
649
39.0k
650
39.0k
    /* Now do the unshift */
651
39.0k
    body->start--;
652
39.0k
    switch (repr_data->slot_type) {
653
39.0k
        case MVM_ARRAY_OBJ:
654
39.0k
            if (kind != MVM_reg_obj)
655
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected object register");
656
39.0k
            MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[body->start], value.o);
657
39.0k
            break;
658
1
        case MVM_ARRAY_STR:
659
1
            if (kind != MVM_reg_str)
660
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected string register");
661
1
            MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[body->start], value.s);
662
1
            break;
663
1
        case MVM_ARRAY_I64:
664
1
            if (kind != MVM_reg_int64)
665
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register");
666
1
            body->slots.i64[body->start] = value.i64;
667
1
            break;
668
0
        case MVM_ARRAY_I32:
669
0
            if (kind != MVM_reg_int64)
670
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register");
671
0
            body->slots.i32[body->start] = (MVMint32)value.i64;
672
0
            break;
673
0
        case MVM_ARRAY_I16:
674
0
            if (kind != MVM_reg_int64)
675
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register");
676
0
            body->slots.i16[body->start] = (MVMint16)value.i64;
677
0
            break;
678
0
        case MVM_ARRAY_I8:
679
0
            if (kind != MVM_reg_int64)
680
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register");
681
0
            body->slots.i8[body->start] = (MVMint8)value.i64;
682
0
            break;
683
0
        case MVM_ARRAY_N64:
684
0
            if (kind != MVM_reg_num64)
685
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected num register");
686
0
            body->slots.n64[body->start] = value.n64;
687
0
            break;
688
0
        case MVM_ARRAY_N32:
689
0
            if (kind != MVM_reg_num64)
690
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected num register");
691
0
            body->slots.n32[body->start] = (MVMnum32)value.n64;
692
0
            break;
693
0
        case MVM_ARRAY_U64:
694
0
            if (kind != MVM_reg_int64)
695
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register");
696
0
            body->slots.u64[body->start] = (MVMuint64)value.i64;
697
0
            break;
698
0
        case MVM_ARRAY_U32:
699
0
            if (kind != MVM_reg_int64)
700
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register");
701
0
            body->slots.u32[body->start] = (MVMuint32)value.i64;
702
0
            break;
703
0
        case MVM_ARRAY_U16:
704
0
            if (kind != MVM_reg_int64)
705
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register");
706
0
            body->slots.u16[body->start] = (MVMuint16)value.i64;
707
0
            break;
708
0
        case MVM_ARRAY_U8:
709
0
            if (kind != MVM_reg_int64)
710
0
                MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register");
711
0
            body->slots.u8[body->start] = (MVMuint8)value.i64;
712
0
            break;
713
0
        default:
714
0
            MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type");
715
39.0k
    }
716
39.0k
    body->elems++;
717
39.0k
    exit_single_user(tc, body);
718
39.0k
}
719
720
15.9k
static void shift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) {
721
15.9k
    MVMArrayBody     *body      = (MVMArrayBody *)data;
722
15.9k
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
723
15.9k
724
15.9k
    if (body->elems < 1)
725
0
        MVM_exception_throw_adhoc(tc,
726
0
            "MVMArray: Can't shift from an empty array");
727
15.9k
728
15.9k
    enter_single_user(tc, body);
729
15.9k
    switch (repr_data->slot_type) {
730
15.9k
        case MVM_ARRAY_OBJ:
731
15.9k
            if (kind != MVM_reg_obj)
732
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected object register");
733
15.9k
            value->o = body->slots.o[body->start];
734
15.9k
            break;
735
2
        case MVM_ARRAY_STR:
736
2
            if (kind != MVM_reg_str)
737
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected string register");
738
2
            value->s = body->slots.s[body->start];
739
2
            break;
740
2
        case MVM_ARRAY_I64:
741
2
            if (kind != MVM_reg_int64)
742
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register");
743
2
            value->i64 = (MVMint64)body->slots.i64[body->start];
744
2
            break;
745
0
        case MVM_ARRAY_I32:
746
0
            if (kind != MVM_reg_int64)
747
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register");
748
0
            value->i64 = (MVMint64)body->slots.i32[body->start];
749
0
            break;
750
0
        case MVM_ARRAY_I16:
751
0
            if (kind != MVM_reg_int64)
752
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register");
753
0
            value->i64 = (MVMint64)body->slots.i16[body->start];
754
0
            break;
755
0
        case MVM_ARRAY_I8:
756
0
            if (kind != MVM_reg_int64)
757
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register");
758
0
            value->i64 = (MVMint64)body->slots.i8[body->start];
759
0
            break;
760
0
        case MVM_ARRAY_N64:
761
0
            if (kind != MVM_reg_num64)
762
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected num register");
763
0
            value->n64 = (MVMnum64)body->slots.n64[body->start];
764
0
            break;
765
0
        case MVM_ARRAY_N32:
766
0
            if (kind != MVM_reg_num64)
767
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected num register");
768
0
            value->n64 = (MVMnum64)body->slots.n32[body->start];
769
0
            break;
770
0
        case MVM_ARRAY_U64:
771
0
            if (kind != MVM_reg_int64)
772
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register");
773
0
            value->i64 = (MVMint64)body->slots.u64[body->start];
774
0
            break;
775
0
        case MVM_ARRAY_U32:
776
0
            if (kind != MVM_reg_int64)
777
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register");
778
0
            value->i64 = (MVMint64)body->slots.u32[body->start];
779
0
            break;
780
0
        case MVM_ARRAY_U16:
781
0
            if (kind != MVM_reg_int64)
782
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register");
783
0
            value->i64 = (MVMint64)body->slots.u16[body->start];
784
0
            break;
785
0
        case MVM_ARRAY_U8:
786
0
            if (kind != MVM_reg_int64)
787
0
                MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register");
788
0
            value->i64 = (MVMint64)body->slots.u8[body->start];
789
0
            break;
790
0
        default:
791
0
            MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type");
792
15.9k
    }
793
15.9k
    body->start++;
794
15.9k
    body->elems--;
795
15.9k
    exit_single_user(tc, body);
796
15.9k
}
797
798
108k
static void copy_elements(MVMThreadContext *tc, MVMObject *src, MVMObject *dest, MVMint64 s_offset, MVMint64 d_offset, MVMint64 elems) {
799
108k
    MVMArrayBody     *s_body      = (MVMArrayBody *)OBJECT_BODY(src);
800
108k
    MVMArrayBody     *d_body      = (MVMArrayBody *)OBJECT_BODY(dest);
801
108k
    MVMArrayREPRData *s_repr_data = REPR(src)->ID == MVM_REPR_ID_VMArray
802
108k
                                    ? (MVMArrayREPRData *)STABLE(src)->REPR_data  : NULL;
803
108k
    MVMArrayREPRData *d_repr_data = REPR(src)->ID == MVM_REPR_ID_VMArray
804
108k
                                    ? (MVMArrayREPRData *)STABLE(dest)->REPR_data : NULL;
805
108k
806
108k
    if (elems > 0) {
807
108k
        MVMint64  i;
808
108k
        MVMuint16 kind;
809
108k
        MVMuint8 d_needs_barrier = dest->header.flags & MVM_CF_SECOND_GEN;
810
108k
        if (s_repr_data && d_repr_data
811
108k
                && s_repr_data->slot_type == d_repr_data->slot_type
812
108k
                && s_repr_data->elem_size == d_repr_data->elem_size
813
108k
                && (d_repr_data->slot_type != MVM_ARRAY_OBJ || !d_needs_barrier)
814
108k
                && d_repr_data->slot_type  != MVM_ARRAY_STR) {
815
108k
            /* Optimized for copying from a VMArray with same slot type */
816
108k
            MVMint64 s_start = s_body->start;
817
108k
            MVMint64 d_start = d_body->start;
818
108k
            memcpy( d_body->slots.u8 + (d_start + d_offset) * d_repr_data->elem_size,
819
108k
                    s_body->slots.u8  + (s_start + s_offset) * s_repr_data->elem_size,
820
108k
                    d_repr_data->elem_size * elems
821
108k
            );
822
108k
        }
823
172
        else {
824
172
            switch (s_repr_data->slot_type) {
825
172
                case MVM_ARRAY_OBJ:
826
172
                    kind = MVM_reg_obj;
827
172
                    break;
828
0
                case MVM_ARRAY_STR:
829
0
                    kind = MVM_reg_str;
830
0
                    break;
831
0
                case MVM_ARRAY_I64:
832
0
                case MVM_ARRAY_I32:
833
0
                case MVM_ARRAY_I16:
834
0
                case MVM_ARRAY_I8:
835
0
                    kind = MVM_reg_int64;
836
0
                    break;
837
0
                case MVM_ARRAY_N64:
838
0
                case MVM_ARRAY_N32:
839
0
                    kind = MVM_reg_num64;
840
0
                    break;
841
0
                case MVM_ARRAY_U64:
842
0
                case MVM_ARRAY_U32:
843
0
                case MVM_ARRAY_U16:
844
0
                case MVM_ARRAY_U8:
845
0
                    kind = MVM_reg_int64;
846
0
                    break;
847
0
                default:
848
0
                    abort(); /* never reached, silence compiler warnings */
849
172
            }
850
643
            for (i = 0; i < elems; i++) {
851
471
                MVMRegister to_copy;
852
471
                REPR(src)->pos_funcs.at_pos(tc, STABLE(src), src, s_body, s_offset + i, &to_copy, kind);
853
471
                bind_pos(tc, STABLE(dest), dest, d_body, d_offset + i, to_copy, kind);
854
471
            }
855
172
        }
856
108k
    }
857
108k
}
858
859
18
static void aslice(MVMThreadContext *tc, MVMSTable *st, MVMObject *src, void *data, MVMObject *dest, MVMint64 start, MVMint64 end) {
860
18
    MVMArrayBody     *s_body      = (MVMArrayBody *)data;
861
18
    MVMArrayBody     *d_body      = (MVMArrayBody *)OBJECT_BODY(dest);
862
18
    MVMArrayREPRData *d_repr_data = REPR(dest)->ID == MVM_REPR_ID_VMArray
863
18
                                      ? STABLE(dest)->REPR_data : NULL;
864
18
865
18
    MVMint64 total_elems = REPR(src)->elems(tc, st, src, s_body);
866
18
    MVMint64 elems;
867
18
868
13
    start = start < 0 ? total_elems + start : start;
869
10
    end   = end   < 0 ? total_elems + end   : end;
870
18
    if ( end < start || start < 0 || end < 0 || total_elems <= start || total_elems <= end ) {
871
8
        MVM_exception_throw_adhoc(tc, "MVMArray: Slice index out of bounds");
872
8
    }
873
18
874
18
    elems = end - start + 1;
875
18
    if (d_repr_data) {
876
10
        set_size_internal(tc, d_body, elems, d_repr_data);
877
10
    }
878
18
879
18
    copy_elements(tc, src, dest, start, 0, elems);
880
18
}
881
882
/* This whole splice optimization can be optimized for the case we have two
883
 * MVMArray representation objects. */
884
135k
static void asplice(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *from, MVMint64 offset, MVMuint64 count) {
885
135k
    MVMArrayREPRData *repr_data   = (MVMArrayREPRData *)st->REPR_data;
886
135k
    MVMArrayBody     *body        = (MVMArrayBody *)data;
887
135k
888
135k
    MVMint64 elems0 = body->elems;
889
135k
    MVMint64 elems1 = REPR(from)->elems(tc, STABLE(from), from, OBJECT_BODY(from));
890
135k
    MVMint64 start;
891
135k
    MVMint64 tail;
892
135k
893
135k
    /* start from end? */
894
135k
    if (offset < 0) {
895
0
        offset += elems0;
896
0
897
0
        if (offset < 0)
898
0
            MVM_exception_throw_adhoc(tc,
899
0
                "MVMArray: Illegal splice offset");
900
0
    }
901
135k
902
135k
    enter_single_user(tc, body);
903
135k
904
135k
    /* When offset == 0, then we may be able to reduce the memmove
905
135k
     * calls and reallocs by adjusting SELF's start, elems0, and
906
135k
     * count to better match the incoming splice.  In particular,
907
135k
     * we're seeking to adjust C<count> to as close to C<elems1>
908
135k
     * as we can. */
909
135k
    if (offset == 0) {
910
61.2k
        MVMint64 n = elems1 - count;
911
61.2k
        start = body->start;
912
61.2k
        if (n > start)
913
48.9k
            n = start;
914
61.2k
        if (n <= -elems0) {
915
56.7k
            elems0 = 0;
916
56.7k
            count = 0;
917
56.7k
            body->start = 0;
918
56.7k
            body->elems = elems0;
919
56.7k
        }
920
4.52k
        else if (n != 0) {
921
0
            elems0 += n;
922
0
            count += n;
923
0
            body->start = start - n;
924
0
            body->elems = elems0;
925
0
        }
926
61.2k
    }
927
135k
928
135k
    /* if count == 0 and elems1 == 0, there's nothing left
929
135k
     * to copy or remove, so the splice is done! */
930
135k
    if (count == 0 && elems1 == 0) {
931
26.8k
        exit_single_user(tc, body);
932
26.8k
        return;
933
26.8k
    }
934
135k
935
135k
    /* number of elements to right of splice (the "tail") */
936
108k
    tail = elems0 - offset - count;
937
108k
    if (tail < 0)
938
1
        tail = 0;
939
108k
940
108k
    else if (tail > 0 && count > elems1) {
941
2
        /* We're shrinking the array, so first move the tail left */
942
2
        start = body->start;
943
2
        memmove(
944
2
            (char *)body->slots.any + (start + offset + elems1) * repr_data->elem_size,
945
2
            (char *)body->slots.any + (start + offset + count) * repr_data->elem_size,
946
2
            tail * repr_data->elem_size);
947
2
    }
948
108k
949
108k
    /* now resize the array */
950
108k
    set_size_internal(tc, body, offset + elems1 + tail, repr_data);
951
108k
952
108k
    start = body->start;
953
108k
    if (tail > 0 && count < elems1) {
954
4.53k
        /* The array grew, so move the tail to the right */
955
4.53k
        memmove(
956
4.53k
            (char *)body->slots.any + (start + offset + elems1) * repr_data->elem_size,
957
4.53k
            (char *)body->slots.any + (start + offset + count) * repr_data->elem_size,
958
4.53k
            tail * repr_data->elem_size);
959
4.53k
    }
960
108k
    exit_single_user(tc, body);
961
108k
962
108k
963
108k
    /* now copy C<from>'s elements into SELF */
964
108k
    copy_elements(tc, from, root, 0, offset, elems1);
965
108k
}
966
967
19
static void at_pos_multidim(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_indices, MVMint64 *indices, MVMRegister *result, MVMuint16 kind) {
968
19
    if (num_indices != 1)
969
10
        MVM_exception_throw_adhoc(tc, "A dynamic array can only be indexed with a single dimension");
970
19
    at_pos(tc, st, root, data, indices[0], result, kind);
971
19
}
972
973
19
static void bind_pos_multidim(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_indices, MVMint64 *indices, MVMRegister value, MVMuint16 kind) {
974
19
    if (num_indices != 1)
975
10
        MVM_exception_throw_adhoc(tc, "A dynamic array can only be indexed with a single dimension");
976
19
    bind_pos(tc, st, root, data, indices[0], value, kind);
977
19
}
978
979
6
static void dimensions(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 *num_dimensions, MVMint64 **dimensions) {
980
6
    MVMArrayBody *body = (MVMArrayBody *)data;
981
6
    *num_dimensions = 1;
982
6
    *dimensions = (MVMint64 *) &(body->elems);
983
6
}
984
985
4
static void set_dimensions(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_dimensions, MVMint64 *dimensions) {
986
4
    if (num_dimensions != 1)
987
3
        MVM_exception_throw_adhoc(tc, "A dynamic array can only have a single dimension");
988
4
    set_elems(tc, st, root, data, dimensions[0]);
989
4
}
990
991
343k
static MVMStorageSpec get_elem_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
992
343k
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
993
343k
    MVMStorageSpec spec;
994
343k
995
343k
    /* initialise storage spec to default values */
996
343k
    spec.bits            = 0;
997
343k
    spec.align           = 0;
998
343k
    spec.is_unsigned     = 0;
999
343k
1000
343k
    switch (repr_data->slot_type) {
1001
14.6k
        case MVM_ARRAY_STR:
1002
14.6k
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
1003
14.6k
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_STR;
1004
14.6k
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_STR;
1005
14.6k
            break;
1006
3
        case MVM_ARRAY_I64:
1007
3
        case MVM_ARRAY_I32:
1008
3
        case MVM_ARRAY_I16:
1009
3
        case MVM_ARRAY_I8:
1010
3
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
1011
3
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_INT;
1012
3
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_INT;
1013
3
            break;
1014
2
        case MVM_ARRAY_N64:
1015
2
        case MVM_ARRAY_N32:
1016
2
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
1017
2
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NUM;
1018
2
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_NUM;
1019
2
            break;
1020
0
        case MVM_ARRAY_U64:
1021
0
        case MVM_ARRAY_U32:
1022
0
        case MVM_ARRAY_U16:
1023
0
        case MVM_ARRAY_U8:
1024
0
            spec.inlineable      = MVM_STORAGE_SPEC_INLINED;
1025
0
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_INT;
1026
0
            spec.can_box         = MVM_STORAGE_SPEC_CAN_BOX_INT;
1027
0
            spec.is_unsigned     = 1;
1028
0
            break;
1029
328k
        default:
1030
328k
            spec.inlineable      = MVM_STORAGE_SPEC_REFERENCE;
1031
328k
            spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NONE;
1032
328k
            spec.can_box         = 0;
1033
328k
            break;
1034
343k
    }
1035
343k
    return spec;
1036
343k
}
1037
1038
static AO_t * pos_as_atomic(MVMThreadContext *tc, MVMSTable *st, MVMObject *root,
1039
0
                            void *data, MVMint64 index) {
1040
0
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
1041
0
    MVMArrayBody     *body      = (MVMArrayBody *)data;
1042
0
1043
0
    /* Handle negative indexes and require in bounds. */
1044
0
    if (index < 0)
1045
0
        index += body->elems;
1046
0
    if (index < 0 || index >= body->elems)
1047
0
        MVM_exception_throw_adhoc(tc, "Index out of bounds in atomic operation on array");
1048
0
1049
0
    if (sizeof(AO_t) == 8 && (repr_data->slot_type == MVM_ARRAY_I64 ||
1050
0
            repr_data->slot_type == MVM_ARRAY_U64))
1051
0
        return (AO_t *)&(body->slots.i64[body->start + index]);
1052
0
    if (sizeof(AO_t) == 4 && (repr_data->slot_type == MVM_ARRAY_I32 ||
1053
0
            repr_data->slot_type == MVM_ARRAY_U32))
1054
0
        return (AO_t *)&(body->slots.i32[body->start + index]);
1055
0
    MVM_exception_throw_adhoc(tc,
1056
0
        "Can only do integer atomic operation on native integer array element of atomic size");
1057
0
}
1058
1059
static AO_t * pos_as_atomic_multidim(MVMThreadContext *tc, MVMSTable *st, MVMObject *root,
1060
0
                                     void *data, MVMint64 num_indices, MVMint64 *indices) {
1061
0
    if (num_indices != 1)
1062
0
        MVM_exception_throw_adhoc(tc,
1063
0
            "A dynamic array can only be indexed with a single dimension");
1064
0
    return pos_as_atomic(tc, st, root, data, indices[0]);
1065
0
}
1066
1067
/* Compose the representation. */
1068
904
static void spec_to_repr_data(MVMThreadContext *tc, MVMArrayREPRData *repr_data, const MVMStorageSpec *spec) {
1069
904
    switch (spec->boxed_primitive) {
1070
615
        case MVM_STORAGE_SPEC_BP_INT:
1071
615
            if (spec->is_unsigned) {
1072
164
                switch (spec->bits) {
1073
0
                    case 64:
1074
0
                        repr_data->slot_type = MVM_ARRAY_U64;
1075
0
                        repr_data->elem_size = sizeof(MVMuint64);
1076
0
                        break;
1077
6
                    case 32:
1078
6
                        repr_data->slot_type = MVM_ARRAY_U32;
1079
6
                        repr_data->elem_size = sizeof(MVMuint32);
1080
6
                        break;
1081
1
                    case 16:
1082
1
                        repr_data->slot_type = MVM_ARRAY_U16;
1083
1
                        repr_data->elem_size = sizeof(MVMuint16);
1084
1
                        break;
1085
157
                    case 8:
1086
157
                        repr_data->slot_type = MVM_ARRAY_U8;
1087
157
                        repr_data->elem_size = sizeof(MVMuint8);
1088
157
                        break;
1089
0
                    case 4:
1090
0
                        repr_data->slot_type = MVM_ARRAY_U4;
1091
0
                        repr_data->elem_size = 0;
1092
0
                        break;
1093
0
                    case 2:
1094
0
                        repr_data->slot_type = MVM_ARRAY_U2;
1095
0
                        repr_data->elem_size = 0;
1096
0
                        break;
1097
0
                    case 1:
1098
0
                        repr_data->slot_type = MVM_ARRAY_U1;
1099
0
                        repr_data->elem_size = 0;
1100
0
                        break;
1101
0
                    default:
1102
0
                        MVM_exception_throw_adhoc(tc,
1103
0
                            "MVMArray: Unsupported uint size");
1104
164
                }
1105
164
            }
1106
451
            else {
1107
451
                switch (spec->bits) {
1108
449
                    case 64:
1109
449
                        repr_data->slot_type = MVM_ARRAY_I64;
1110
449
                        repr_data->elem_size = sizeof(MVMint64);
1111
449
                        break;
1112
0
                    case 32:
1113
0
                        repr_data->slot_type = MVM_ARRAY_I32;
1114
0
                        repr_data->elem_size = sizeof(MVMint32);
1115
0
                        break;
1116
0
                    case 16:
1117
0
                        repr_data->slot_type = MVM_ARRAY_I16;
1118
0
                        repr_data->elem_size = sizeof(MVMint16);
1119
0
                        break;
1120
2
                    case 8:
1121
2
                        repr_data->slot_type = MVM_ARRAY_I8;
1122
2
                        repr_data->elem_size = sizeof(MVMint8);
1123
2
                        break;
1124
0
                    case 4:
1125
0
                        repr_data->slot_type = MVM_ARRAY_I4;
1126
0
                        repr_data->elem_size = 0;
1127
0
                        break;
1128
0
                    case 2:
1129
0
                        repr_data->slot_type = MVM_ARRAY_I2;
1130
0
                        repr_data->elem_size = 0;
1131
0
                        break;
1132
0
                    case 1:
1133
0
                        repr_data->slot_type = MVM_ARRAY_I1;
1134
0
                        repr_data->elem_size = 0;
1135
0
                        break;
1136
0
                    default:
1137
0
                        MVM_exception_throw_adhoc(tc,
1138
0
                            "MVMArray: Unsupported int size");
1139
451
                }
1140
451
            }
1141
615
            break;
1142
145
        case MVM_STORAGE_SPEC_BP_NUM:
1143
145
            switch (spec->bits) {
1144
145
                case 64:
1145
145
                    repr_data->slot_type = MVM_ARRAY_N64;
1146
145
                    repr_data->elem_size = sizeof(MVMnum64);
1147
145
                    break;
1148
0
                case 32:
1149
0
                    repr_data->slot_type = MVM_ARRAY_N32;
1150
0
                    repr_data->elem_size = sizeof(MVMnum32);
1151
0
                    break;
1152
0
                default:
1153
0
                    MVM_exception_throw_adhoc(tc,
1154
0
                        "MVMArray: Unsupported num size");
1155
145
            }
1156
145
            break;
1157
144
        case MVM_STORAGE_SPEC_BP_STR:
1158
144
            repr_data->slot_type = MVM_ARRAY_STR;
1159
144
            repr_data->elem_size = sizeof(MVMString *);
1160
144
            break;
1161
904
    }
1162
904
}
1163
599
static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) {
1164
599
    MVMStringConsts         str_consts = tc->instance->str_consts;
1165
599
    MVMArrayREPRData * const repr_data = (MVMArrayREPRData *)st->REPR_data;
1166
599
1167
599
    MVMObject *info = MVM_repr_at_key_o(tc, info_hash, str_consts.array);
1168
599
    if (!MVM_is_null(tc, info)) {
1169
598
        MVMObject *type = MVM_repr_at_key_o(tc, info, str_consts.type);
1170
598
        if (!MVM_is_null(tc, type)) {
1171
598
            const MVMStorageSpec *spec = REPR(type)->get_storage_spec(tc, STABLE(type));
1172
598
            MVM_ASSIGN_REF(tc, &(st->header), repr_data->elem_type, type);
1173
598
            spec_to_repr_data(tc, repr_data, spec);
1174
598
        }
1175
598
    }
1176
599
}
1177
1178
/* Set the size of the STable. */
1179
450
static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
1180
450
    st->size = sizeof(MVMArray);
1181
450
}
1182
1183
/* Serializes the REPR data. */
1184
1
static void serialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationWriter *writer) {
1185
1
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data;
1186
1
    MVM_serialization_write_ref(tc, writer, repr_data->elem_type);
1187
1
}
1188
1189
/* Deserializes representation data. */
1190
450
static void deserialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
1191
450
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *)MVM_malloc(sizeof(MVMArrayREPRData));
1192
450
1193
450
    MVMObject *type = MVM_serialization_read_ref(tc, reader);
1194
450
    MVM_ASSIGN_REF(tc, &(st->header), repr_data->elem_type, type);
1195
450
    repr_data->slot_type = MVM_ARRAY_OBJ;
1196
450
    repr_data->elem_size = sizeof(MVMObject *);
1197
450
    st->REPR_data = repr_data;
1198
450
1199
450
    if (type) {
1200
306
        const MVMStorageSpec *spec;
1201
306
        MVM_serialization_force_stable(tc, reader, STABLE(type));
1202
306
        spec = REPR(type)->get_storage_spec(tc, STABLE(type));
1203
306
        spec_to_repr_data(tc, repr_data, spec);
1204
306
    }
1205
450
}
1206
1207
665k
static void deserialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMSerializationReader *reader) {
1208
665k
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *) st->REPR_data;
1209
665k
    MVMArrayBody     *body      = (MVMArrayBody *)data;
1210
665k
    MVMint64 i;
1211
665k
1212
665k
    body->elems = MVM_serialization_read_int(tc, reader);
1213
665k
    body->ssize = body->elems;
1214
665k
    if (body->ssize)
1215
601k
        body->slots.any = MVM_malloc(body->ssize * repr_data->elem_size);
1216
665k
1217
3.58M
    for (i = 0; i < body->elems; i++) {
1218
2.92M
        switch (repr_data->slot_type) {
1219
2.91M
            case MVM_ARRAY_OBJ:
1220
2.91M
                MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[i], MVM_serialization_read_ref(tc, reader));
1221
2.91M
                break;
1222
0
            case MVM_ARRAY_STR:
1223
0
                MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[i], MVM_serialization_read_str(tc, reader));
1224
0
                break;
1225
8.11k
            case MVM_ARRAY_I64:
1226
8.11k
                body->slots.i64[i] = MVM_serialization_read_int(tc, reader);
1227
8.11k
                break;
1228
0
            case MVM_ARRAY_I32:
1229
0
                body->slots.i32[i] = (MVMint32)MVM_serialization_read_int(tc, reader);
1230
0
                break;
1231
0
            case MVM_ARRAY_I16:
1232
0
                body->slots.i16[i] = (MVMint16)MVM_serialization_read_int(tc, reader);
1233
0
                break;
1234
0
            case MVM_ARRAY_I8:
1235
0
                body->slots.i8[i] = (MVMint8)MVM_serialization_read_int(tc, reader);
1236
0
                break;
1237
0
            case MVM_ARRAY_U64:
1238
0
                body->slots.i64[i] = MVM_serialization_read_int(tc, reader);
1239
0
                break;
1240
0
            case MVM_ARRAY_U32:
1241
0
                body->slots.i32[i] = (MVMuint32)MVM_serialization_read_int(tc, reader);
1242
0
                break;
1243
0
            case MVM_ARRAY_U16:
1244
0
                body->slots.i16[i] = (MVMuint16)MVM_serialization_read_int(tc, reader);
1245
0
                break;
1246
0
            case MVM_ARRAY_U8:
1247
0
                body->slots.i8[i] = (MVMuint8)MVM_serialization_read_int(tc, reader);
1248
0
                break;
1249
3
            case MVM_ARRAY_N64:
1250
3
                body->slots.n64[i] = MVM_serialization_read_num(tc, reader);
1251
3
                break;
1252
0
            case MVM_ARRAY_N32:
1253
0
                body->slots.n32[i] = (MVMnum32)MVM_serialization_read_num(tc, reader);
1254
0
                break;
1255
0
            default:
1256
0
                MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type");
1257
2.92M
        }
1258
2.92M
    }
1259
665k
}
1260
1261
188
static void serialize(MVMThreadContext *tc, MVMSTable *st, void *data, MVMSerializationWriter *writer) {
1262
188
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *) st->REPR_data;
1263
188
    MVMArrayBody     *body      = (MVMArrayBody *)data;
1264
188
    MVMint64 i;
1265
188
1266
188
    MVM_serialization_write_int(tc, writer, body->elems);
1267
1.54k
    for (i = 0; i < body->elems; i++) {
1268
1.35k
        switch (repr_data->slot_type) {
1269
1.35k
            case MVM_ARRAY_OBJ:
1270
1.35k
                MVM_serialization_write_ref(tc, writer, body->slots.o[body->start + i]);
1271
1.35k
                break;
1272
0
            case MVM_ARRAY_STR:
1273
0
                MVM_serialization_write_str(tc, writer, body->slots.s[body->start + i]);
1274
0
                break;
1275
0
            case MVM_ARRAY_I64:
1276
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i64[body->start + i]);
1277
0
                break;
1278
0
            case MVM_ARRAY_I32:
1279
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i32[body->start + i]);
1280
0
                break;
1281
0
            case MVM_ARRAY_I16:
1282
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i16[body->start + i]);
1283
0
                break;
1284
0
            case MVM_ARRAY_I8:
1285
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i8[body->start + i]);
1286
0
                break;
1287
0
            case MVM_ARRAY_U64:
1288
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u64[body->start + i]);
1289
0
                break;
1290
0
            case MVM_ARRAY_U32:
1291
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u32[body->start + i]);
1292
0
                break;
1293
0
            case MVM_ARRAY_U16:
1294
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u16[body->start + i]);
1295
0
                break;
1296
0
            case MVM_ARRAY_U8:
1297
0
                MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u8[body->start + i]);
1298
0
                break;
1299
3
            case MVM_ARRAY_N64:
1300
3
                MVM_serialization_write_num(tc, writer, (MVMnum64)body->slots.n64[body->start + i]);
1301
3
                break;
1302
0
            case MVM_ARRAY_N32:
1303
0
                MVM_serialization_write_num(tc, writer, (MVMnum64)body->slots.n32[body->start + i]);
1304
0
                break;
1305
0
            default:
1306
0
                MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type");
1307
1.35k
        }
1308
1.35k
    }
1309
188
}
1310
1311
/* Bytecode specialization for this REPR. */
1312
21.6k
static void spesh(MVMThreadContext *tc, MVMSTable *st, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) {
1313
21.6k
    switch (ins->info->opcode) {
1314
3.63k
    case MVM_OP_create: {
1315
3.63k
        if (!(st->mode_flags & MVM_FINALIZE_TYPE)) {
1316
3.63k
            MVMSpeshOperand target   = ins->operands[0];
1317
3.63k
            MVMSpeshOperand type     = ins->operands[1];
1318
3.63k
            ins->info                = MVM_op_get_op(MVM_OP_sp_fastcreate);
1319
3.63k
            ins->operands            = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
1320
3.63k
            ins->operands[0]         = target;
1321
3.63k
            ins->operands[1].lit_i16 = sizeof(MVMArray);
1322
3.63k
            ins->operands[2].lit_i16 = MVM_spesh_add_spesh_slot(tc, g, (MVMCollectable *)st);
1323
3.63k
            MVM_spesh_get_facts(tc, g, type)->usages--;
1324
3.63k
        }
1325
3.63k
        break;
1326
3.63k
    }
1327
21.6k
    }
1328
21.6k
}
1329
1330
/* Calculates the non-GC-managed memory we hold on to. */
1331
144k
static MVMuint64 unmanaged_size(MVMThreadContext *tc, MVMSTable *st, void *data) {
1332
144k
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *) st->REPR_data;
1333
144k
    MVMArrayBody     *body      = (MVMArrayBody *)data;
1334
144k
    return body->ssize * repr_data->elem_size;
1335
144k
}
1336
1337
0
static void describe_refs (MVMThreadContext *tc, MVMHeapSnapshotState *ss, MVMSTable *st, void *data) {
1338
0
    MVMArrayREPRData *repr_data = (MVMArrayREPRData *) st->REPR_data;
1339
0
    MVMArrayBody     *body      = (MVMArrayBody *)data;
1340
0
    MVMuint64         elems     = body->elems;
1341
0
    MVMuint64         start     = body->start;
1342
0
    MVMuint64         i         = 0;
1343
0
1344
0
    switch (repr_data->slot_type) {
1345
0
        case MVM_ARRAY_OBJ: {
1346
0
            MVMObject **slots = body->slots.o;
1347
0
            slots += start;
1348
0
            while (i < elems) {
1349
0
                MVM_profile_heap_add_collectable_rel_idx(tc, ss,
1350
0
                    (MVMCollectable *)slots[i], i);
1351
0
                i++;
1352
0
            }
1353
0
            break;
1354
0
        }
1355
0
        case MVM_ARRAY_STR: {
1356
0
            MVMString **slots = body->slots.s;
1357
0
            slots += start;
1358
0
            while (i < elems) {
1359
0
                MVM_profile_heap_add_collectable_rel_idx(tc, ss,
1360
0
                    (MVMCollectable *)slots[i], i);
1361
0
                i++;
1362
0
            }
1363
0
            break;
1364
0
        }
1365
0
    }
1366
0
}
1367
1368
/* Initializes the representation. */
1369
144
const MVMREPROps * MVMArray_initialize(MVMThreadContext *tc) {
1370
144
    return &VMArray_this_repr;
1371
144
}
1372
1373
static const MVMREPROps VMArray_this_repr = {
1374
    type_object_for,
1375
    MVM_gc_allocate_object,
1376
    NULL, /* initialize */
1377
    copy_to,
1378
    MVM_REPR_DEFAULT_ATTR_FUNCS,
1379
    MVM_REPR_DEFAULT_BOX_FUNCS,
1380
    {
1381
        at_pos,
1382
        bind_pos,
1383
        set_elems,
1384
        push,
1385
        pop,
1386
        unshift,
1387
        shift,
1388
        aslice,
1389
        asplice,
1390
        at_pos_multidim,
1391
        bind_pos_multidim,
1392
        dimensions,
1393
        set_dimensions,
1394
        get_elem_storage_spec,
1395
        pos_as_atomic,
1396
        pos_as_atomic_multidim
1397
    },    /* pos_funcs */
1398
    MVM_REPR_DEFAULT_ASS_FUNCS,
1399
    elems,
1400
    get_storage_spec,
1401
    NULL, /* change_type */
1402
    serialize,
1403
    deserialize,
1404
    serialize_repr_data,
1405
    deserialize_repr_data,
1406
    deserialize_stable_size,
1407
    gc_mark,
1408
    gc_free,
1409
    NULL, /* gc_cleanup */
1410
    gc_mark_repr_data,
1411
    gc_free_repr_data,
1412
    compose,
1413
    spesh,
1414
    "VMArray", /* name */
1415
    MVM_REPR_ID_VMArray,
1416
    unmanaged_size,
1417
    describe_refs,
1418
};