Coverage Report

Created: 2017-04-15 07:07

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