Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/6model/reprs/CArray.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 CArray_this_repr;
5
6
/* Creates a new type object of this representation, and associates it with
7
 * the given HOW. */
8
0
static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
9
0
    MVMSTable *st = MVM_gc_allocate_stable(tc, &CArray_this_repr, HOW);
10
0
11
0
    MVMROOT(tc, st, {
12
0
        MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
13
0
        MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj);
14
0
        st->size = sizeof(MVMCArray);
15
0
    });
16
0
17
0
    return st->WHAT;
18
0
}
19
20
/* Composes the representation. */
21
0
static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) {
22
0
    MVMStringConsts str_consts = tc->instance->str_consts;
23
0
    MVMObject *info = MVM_repr_at_key_o(tc, info_hash, str_consts.array);
24
0
    if (!MVM_is_null(tc, info)) {
25
0
        MVMCArrayREPRData *repr_data = MVM_malloc(sizeof(MVMCArrayREPRData));
26
0
        MVMObject *type    = MVM_repr_at_key_o(tc, info, str_consts.type);
27
0
        const MVMStorageSpec *ss = REPR(type)->get_storage_spec(tc, STABLE(type));
28
0
        MVMint32 type_id   = REPR(type)->ID;
29
0
30
0
        MVM_ASSIGN_REF(tc, &(st->header), repr_data->elem_type, type);
31
0
        st->REPR_data = repr_data;
32
0
33
0
        if (ss->boxed_primitive == MVM_STORAGE_SPEC_BP_INT) {
34
0
            if (ss->bits == 8 || ss->bits == 16 || ss->bits == 32 || ss->bits == 64)
35
0
                repr_data->elem_size = ss->bits / 8;
36
0
            else
37
0
                MVM_exception_throw_adhoc(tc,
38
0
                    "CArray representation can only have 8, 16, 32 or 64 bit integer elements");
39
0
            repr_data->elem_kind = MVM_CARRAY_ELEM_KIND_NUMERIC;
40
0
        }
41
0
        else if (ss->boxed_primitive == MVM_STORAGE_SPEC_BP_NUM) {
42
0
            if (ss->bits == 32 || ss->bits == 64)
43
0
                repr_data->elem_size = ss->bits / 8;
44
0
            else
45
0
                MVM_exception_throw_adhoc(tc,
46
0
                    "CArray representation can only have 32 or 64 bit floating point elements");
47
0
            repr_data->elem_kind = MVM_CARRAY_ELEM_KIND_NUMERIC;
48
0
        }
49
0
        else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR) {
50
0
            repr_data->elem_size = sizeof(MVMObject *);
51
0
            repr_data->elem_kind = MVM_CARRAY_ELEM_KIND_STRING;
52
0
        }
53
0
        else if (type_id == MVM_REPR_ID_MVMCArray) {
54
0
            repr_data->elem_kind = MVM_CARRAY_ELEM_KIND_CARRAY;
55
0
            repr_data->elem_size = sizeof(void *);
56
0
        }
57
0
        else if (type_id == MVM_REPR_ID_MVMCStruct) {
58
0
            repr_data->elem_kind = MVM_CARRAY_ELEM_KIND_CSTRUCT;
59
0
            repr_data->elem_size = sizeof(void *);
60
0
        }
61
0
        else if (type_id == MVM_REPR_ID_MVMCPointer) {
62
0
            repr_data->elem_kind = MVM_CARRAY_ELEM_KIND_CPOINTER;
63
0
            repr_data->elem_size = sizeof(void *);
64
0
        }
65
0
        else {
66
0
            MVM_exception_throw_adhoc(tc,
67
0
                "CArray representation only handles attributes of type:\n"
68
0
                "  (u)int8, (u)int16, (u)int32, (u)int64, (u)long, (u)longlong, num32, num64, (s)size_t, bool, Str\n"
69
0
                "  and types with representation: CArray, CPointer, CStruct, CPPStruct and CUnion");
70
0
        }
71
0
    }
72
0
    else {
73
0
        MVM_exception_throw_adhoc(tc, "CArray representation requires a typed array");
74
0
    }
75
0
}
76
77
/* Initialize a new instance. */
78
0
static void initialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) {
79
0
    /* If we're initialized, presumably we're going to be
80
0
     * managing the memory in this array ourself. */
81
0
    MVMCArrayREPRData *repr_data = (MVMCArrayREPRData *)st->REPR_data;
82
0
    MVMCArrayBody     *body      = (MVMCArrayBody *)data;
83
0
84
0
    if (!repr_data)
85
0
        MVM_exception_throw_adhoc(tc, "CArray type must be composed before use");
86
0
87
0
    body->storage = MVM_calloc(4, repr_data->elem_size);
88
0
    body->managed = 1;
89
0
90
0
    /* Don't need child_objs for numerics. */
91
0
    if (repr_data->elem_kind == MVM_CARRAY_ELEM_KIND_NUMERIC)
92
0
        body->child_objs = NULL;
93
0
    else
94
0
        body->child_objs = (MVMObject **) MVM_calloc(4, sizeof(MVMObject *));
95
0
96
0
    body->allocated = 4;
97
0
    body->elems = 0;
98
0
}
99
100
/* Copies to the body of one object to another. */
101
0
static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) {
102
0
    MVMCArrayREPRData *repr_data = (MVMCArrayREPRData *)st->REPR_data;
103
0
    MVMCArrayBody     *src_body  = (MVMCArrayBody *)src;
104
0
    MVMCArrayBody     *dest_body = (MVMCArrayBody *)dest;
105
0
106
0
    if (src_body->managed) {
107
0
        MVMint32 alsize = src_body->allocated * repr_data->elem_size;
108
0
        dest_body->storage = MVM_malloc(alsize);
109
0
        memcpy(dest_body->storage, src_body->storage, alsize);
110
0
    }
111
0
    else {
112
0
        dest_body->storage = src_body->storage;
113
0
    }
114
0
    dest_body->managed = src_body->managed;
115
0
    dest_body->allocated = src_body->allocated;
116
0
    dest_body->elems = src_body->elems;
117
0
}
118
119
/* This is called to do any cleanup of resources when an object gets
120
 * embedded inside another one. Never called on a top-level object. */
121
0
static void gc_cleanup(MVMThreadContext *tc, MVMSTable *st, void *data) {
122
0
    MVMCArrayBody *body = (MVMCArrayBody *)data;
123
0
124
0
    if (body->managed) {
125
0
        MVM_free(body->storage);
126
0
127
0
        if (body->child_objs)
128
0
            MVM_free(body->child_objs);
129
0
    }
130
0
}
131
132
0
static void gc_free(MVMThreadContext *tc, MVMObject *obj) {
133
0
    gc_cleanup(tc, STABLE(obj), OBJECT_BODY(obj));
134
0
}
135
136
0
static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) {
137
0
    MVMCArrayBody *body = (MVMCArrayBody *)data;
138
0
    const MVMint32 elems = body->elems;
139
0
    MVMint32 i;
140
0
141
0
    /* Don't traverse child_objs list if there isn't one. */
142
0
    if (!body->child_objs) return;
143
0
144
0
    for (i = 0; i < elems; i++)
145
0
        if (body->child_objs[i])
146
0
            MVM_gc_worklist_add(tc, worklist, &body->child_objs[i]);
147
0
}
148
149
/* Marks the representation data in an STable.*/
150
0
static void gc_mark_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMGCWorklist *worklist) {
151
0
    MVMCArrayREPRData *repr_data = (MVMCArrayREPRData *)st->REPR_data;
152
0
    if (repr_data)
153
0
        MVM_gc_worklist_add(tc, worklist, &repr_data->elem_type);
154
0
}
155
156
/* Free representation data. */
157
0
static void gc_free_repr_data(MVMThreadContext *tc, MVMSTable *st) {
158
0
    MVM_free(st->REPR_data);
159
0
}
160
161
static const MVMStorageSpec storage_spec = {
162
    MVM_STORAGE_SPEC_REFERENCE, /* inlineable */
163
    sizeof(void *) * 8,         /* bits */
164
    ALIGNOF(void *),            /* align */
165
    MVM_STORAGE_SPEC_BP_NONE,   /* boxed_primitive */
166
    0,                          /* can_box */
167
    0,                          /* is_unsigned */
168
};
169
170
171
/* Gets the storage specification for this representation. */
172
0
static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
173
0
    return &storage_spec;
174
0
}
175
176
177
MVM_NO_RETURN static void die_pos_nyi(MVMThreadContext *tc) MVM_NO_RETURN_GCC;
178
0
static void die_pos_nyi(MVMThreadContext *tc) {
179
0
    MVM_exception_throw_adhoc(tc,
180
0
        "CArray representation does not fully positional storage yet");
181
0
}
182
183
184
0
static void expand(MVMThreadContext *tc, MVMCArrayREPRData *repr_data, MVMCArrayBody *body, MVMint32 min_size) {
185
0
    MVMint8 is_complex;
186
0
    MVMint32 next_size = body->allocated? 2 * body->allocated: 4;
187
0
188
0
    if (min_size > next_size)
189
0
        next_size = min_size;
190
0
191
0
    if (body->managed) {
192
0
        const size_t old_size = body->allocated * repr_data->elem_size;
193
0
        const size_t new_size = next_size * repr_data->elem_size;
194
0
195
0
        body->storage = MVM_realloc(body->storage, new_size);
196
0
        memset((char *)body->storage + old_size, 0, new_size - old_size);
197
0
    }
198
0
199
0
    is_complex = (repr_data->elem_kind == MVM_CARRAY_ELEM_KIND_CARRAY
200
0
               || repr_data->elem_kind == MVM_CARRAY_ELEM_KIND_CPOINTER
201
0
               || repr_data->elem_kind == MVM_CARRAY_ELEM_KIND_CSTRUCT
202
0
               || repr_data->elem_kind == MVM_CARRAY_ELEM_KIND_STRING);
203
0
204
0
    if (is_complex) {
205
0
        const size_t old_size = body->allocated * sizeof(MVMObject *);
206
0
        const size_t new_size = next_size * sizeof(MVMObject *);
207
0
208
0
        body->child_objs = (MVMObject **) MVM_realloc(body->child_objs, new_size);
209
0
        memset((char *)body->child_objs + old_size, 0, new_size - old_size);
210
0
    }
211
0
212
0
    body->allocated = next_size;
213
0
}
214
215
0
static MVMObject * make_wrapper(MVMThreadContext *tc, MVMSTable *st, void *data) {
216
0
    MVMCArrayREPRData *repr_data = (MVMCArrayREPRData *)st->REPR_data;
217
0
    switch (repr_data->elem_kind) {
218
0
        case MVM_CARRAY_ELEM_KIND_STRING: {
219
0
            MVMString *str = MVM_string_utf8_decode(tc, tc->instance->VMString,
220
0
                (char *)data, strlen((char *)data));
221
0
            return MVM_repr_box_str(tc, repr_data->elem_type, str);
222
0
        }
223
0
        case MVM_CARRAY_ELEM_KIND_CPOINTER:
224
0
            return MVM_nativecall_make_cpointer(tc, repr_data->elem_type, data);
225
0
        case MVM_CARRAY_ELEM_KIND_CARRAY:
226
0
            return MVM_nativecall_make_carray(tc, repr_data->elem_type, data);
227
0
        case MVM_CARRAY_ELEM_KIND_CSTRUCT:
228
0
            return MVM_nativecall_make_cstruct(tc, repr_data->elem_type, data);
229
0
        default:
230
0
            MVM_exception_throw_adhoc(tc, "Unknown element type in CArray");
231
0
    }
232
0
}
233
0
static void at_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister *value, MVMuint16 kind) {
234
0
    MVMCArrayREPRData *repr_data = (MVMCArrayREPRData *)st->REPR_data;
235
0
    MVMCArrayBody     *body      = (MVMCArrayBody *)data;
236
0
    void              *ptr       = ((char *)body->storage) + index * repr_data->elem_size;
237
0
    switch (repr_data->elem_kind) {
238
0
        case MVM_CARRAY_ELEM_KIND_NUMERIC:
239
0
            if (kind == MVM_reg_int64)
240
0
                value->i64 = body->managed && index >= body->elems
241
0
                    ? 0
242
0
                    : REPR(repr_data->elem_type)->box_funcs.get_int(tc,
243
0
                        STABLE(repr_data->elem_type), root, ptr);
244
0
            else if (kind == MVM_reg_num64)
245
0
                value->n64 = body->managed && index >= body->elems
246
0
                    ? 0.0
247
0
                    : REPR(repr_data->elem_type)->box_funcs.get_num(tc,
248
0
                        STABLE(repr_data->elem_type), root, ptr);
249
0
            else
250
0
                MVM_exception_throw_adhoc(tc, "Wrong kind of access to numeric CArray");
251
0
            break;
252
0
        case MVM_CARRAY_ELEM_KIND_STRING:
253
0
        case MVM_CARRAY_ELEM_KIND_CPOINTER:
254
0
        case MVM_CARRAY_ELEM_KIND_CARRAY:
255
0
        case MVM_CARRAY_ELEM_KIND_CSTRUCT: {
256
0
            if (kind != MVM_reg_obj)
257
0
                MVM_exception_throw_adhoc(tc, "Wrong kind of access to object CArray");
258
0
            if (body->managed) {
259
0
                /* We manage this array. If we're out of range, just use type object. */
260
0
                if (index >= body->elems) {
261
0
                    value->o = repr_data->elem_type;
262
0
                }
263
0
264
0
                /* Otherwise we may have a cached object result. */
265
0
                else if (body->child_objs[index]) {
266
0
                    value->o = body->child_objs[index];
267
0
                }
268
0
269
0
                /* If not, we need to produce and cache it. */
270
0
                else {
271
0
                    void **storage = (void **)body->storage;
272
0
                    MVMROOT(tc, root, {
273
0
                        MVMObject **child_objs = body->child_objs;
274
0
                        MVMObject *wrapped = make_wrapper(tc, st, storage[index]);
275
0
                        MVM_ASSIGN_REF(tc, &(root->header), child_objs[index], wrapped);
276
0
                        value->o = wrapped;
277
0
                    });
278
0
                }
279
0
            }
280
0
            else {
281
0
                void **storage;
282
0
283
0
                /* Array comes from C. Enlarge child_objs if needed. */
284
0
                if (index >= body->allocated)
285
0
                    expand(tc, repr_data, body, index + 1);
286
0
                if (index >= body->elems)
287
0
                    body->elems = index + 1;
288
0
289
0
                storage = (void **)body->storage;
290
0
291
0
                /* We've already fetched this object; use cached one. */
292
0
                if (storage[index] && body->child_objs[index]) {
293
0
                    value->o = body->child_objs[index];
294
0
                }
295
0
296
0
                /* No cached object, but non-NULL pointer in array. Construct object,
297
0
                 * put it in the cache and return it. */
298
0
                else if (storage[index]) {
299
0
                    MVMROOT(tc, root, {
300
0
                        MVMObject **child_objs = body->child_objs;
301
0
                        MVMObject *wrapped = make_wrapper(tc, st, storage[index]);
302
0
                        MVM_ASSIGN_REF(tc, &(root->header), child_objs[index], wrapped);
303
0
                        value->o = wrapped;
304
0
                    });
305
0
                }
306
0
307
0
                /* NULL pointer in the array; result is the type object. */
308
0
                else {
309
0
                    value->o = repr_data->elem_type;
310
0
                }
311
0
            }
312
0
            break;
313
0
        }
314
0
        default:
315
0
            MVM_exception_throw_adhoc(tc, "Unknown element type in CArray");
316
0
    }
317
0
}
318
319
static void bind_wrapper_and_ptr(MVMThreadContext *tc, MVMObject *root, MVMCArrayBody *body,
320
0
        MVMint64 index, MVMObject *wrapper, void *cptr) {
321
0
    if (index >= body->allocated)
322
0
        expand(tc, STABLE(root)->REPR_data, body, index + 1);
323
0
    if (index >= body->elems)
324
0
        body->elems = index + 1;
325
0
    MVM_ASSIGN_REF(tc, &(root->header), body->child_objs[index], wrapper);
326
0
    ((void **)body->storage)[index] = cptr;
327
0
}
328
0
static void bind_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister value, MVMuint16 kind) {
329
0
    MVMCArrayREPRData *repr_data = (MVMCArrayREPRData *)st->REPR_data;
330
0
    MVMCArrayBody     *body      = (MVMCArrayBody *)data;
331
0
    void *ptr;
332
0
333
0
    if (body->managed && index >= body->allocated)
334
0
        expand(tc, repr_data, body, index + 1);
335
0
    if (index >= body->elems)
336
0
        body->elems = index + 1;
337
0
338
0
    ptr = ((char *)body->storage) + index * repr_data->elem_size;
339
0
340
0
    switch (repr_data->elem_kind) {
341
0
        case MVM_CARRAY_ELEM_KIND_NUMERIC:
342
0
            if (kind == MVM_reg_int64)
343
0
                REPR(repr_data->elem_type)->box_funcs.set_int(tc,
344
0
                    STABLE(repr_data->elem_type), root, ptr, value.i64);
345
0
            else if (kind == MVM_reg_num64)
346
0
                REPR(repr_data->elem_type)->box_funcs.set_num(tc,
347
0
                    STABLE(repr_data->elem_type), root, ptr, value.n64);
348
0
            else
349
0
                MVM_exception_throw_adhoc(tc, "Wrong kind of access to numeric CArray");
350
0
            break;
351
0
        case MVM_CARRAY_ELEM_KIND_STRING: {
352
0
            char *string = IS_CONCRETE(value.o)
353
0
                         ? MVM_string_utf8_encode_C_string(tc, MVM_repr_get_str(tc, value.o))
354
0
                         : NULL;
355
0
            bind_wrapper_and_ptr(tc, root, body, index, value.o, string);
356
0
            break;
357
0
        }
358
0
        case MVM_CARRAY_ELEM_KIND_CPOINTER:
359
0
            if (REPR(value.o)->ID != MVM_REPR_ID_MVMCPointer)
360
0
                MVM_exception_throw_adhoc(tc, "CArray of CPointer passed non-CPointer object");
361
0
            bind_wrapper_and_ptr(tc, root, body, index, value.o,
362
0
                IS_CONCRETE(value.o) ? ((MVMCPointer *)value.o)->body.ptr : NULL);
363
0
            break;
364
0
        case MVM_CARRAY_ELEM_KIND_CARRAY:
365
0
            if (REPR(value.o)->ID != MVM_REPR_ID_MVMCArray)
366
0
                MVM_exception_throw_adhoc(tc, "CArray of CArray passed non-CArray object");
367
0
            bind_wrapper_and_ptr(tc, root, body, index, value.o,
368
0
                IS_CONCRETE(value.o) ? ((MVMCArray *)value.o)->body.storage : NULL);
369
0
            break;
370
0
        case MVM_CARRAY_ELEM_KIND_CSTRUCT:
371
0
            if (REPR(value.o)->ID != MVM_REPR_ID_MVMCStruct)
372
0
                MVM_exception_throw_adhoc(tc, "CArray of CStruct passed non-CStruct object");
373
0
            bind_wrapper_and_ptr(tc, root, body, index, value.o,
374
0
                IS_CONCRETE(value.o) ? ((MVMCStruct *)value.o)->body.cstruct : NULL);
375
0
            break;
376
0
        default:
377
0
            MVM_exception_throw_adhoc(tc, "Unknown element type in CArray");
378
0
    }
379
0
}
380
381
0
static void push(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister value, MVMuint16 kind) {
382
0
    die_pos_nyi(tc);
383
0
}
384
385
0
static void pop(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) {
386
0
    die_pos_nyi(tc);
387
0
}
388
389
0
static void unshift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister value, MVMuint16 kind) {
390
0
    die_pos_nyi(tc);
391
0
}
392
393
0
static void shift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) {
394
0
    die_pos_nyi(tc);
395
0
}
396
397
0
static MVMuint64 elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) {
398
0
    MVMCArrayBody *body = (MVMCArrayBody *)data;
399
0
400
0
    if (body->managed)
401
0
        return body->elems;
402
0
403
0
    MVM_exception_throw_adhoc(tc,
404
0
        "Don't know how many elements a C array returned from a library");
405
0
}
406
407
0
static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
408
0
    st->size = sizeof(MVMCArray);
409
0
}
410
411
/* Serializes the REPR data. */
412
0
static void serialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationWriter *writer) {
413
0
    MVMCArrayREPRData *repr_data = (MVMCArrayREPRData *)st->REPR_data;
414
0
    MVM_serialization_write_int(tc, writer, repr_data->elem_size);
415
0
    MVM_serialization_write_ref(tc, writer, repr_data->elem_type);
416
0
    MVM_serialization_write_int(tc, writer, repr_data->elem_kind);
417
0
}
418
419
/* Deserializes the REPR data. */
420
0
static void deserialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
421
0
    MVMCArrayREPRData *repr_data = (MVMCArrayREPRData *) MVM_malloc(sizeof(MVMCArrayREPRData));
422
0
423
0
    if (reader->root.version >= 19) {
424
0
        repr_data->elem_size = MVM_serialization_read_int(tc, reader);
425
0
    } else {
426
0
        repr_data->elem_size = MVM_serialization_read_int64(tc, reader);
427
0
    }
428
0
429
0
    repr_data->elem_type = MVM_serialization_read_ref(tc, reader);
430
0
431
0
    if (reader->root.version >= 19) {
432
0
        repr_data->elem_kind = MVM_serialization_read_int(tc, reader);
433
0
    } else {
434
0
        repr_data->elem_kind = MVM_serialization_read_int64(tc, reader);
435
0
    }
436
0
437
0
    st->REPR_data = repr_data;
438
0
}
439
440
/* Initializes the CArray representation. */
441
130
const MVMREPROps * MVMCArray_initialize(MVMThreadContext *tc) {
442
130
    return &CArray_this_repr;
443
130
}
444
445
static const MVMREPROps CArray_this_repr = {
446
    type_object_for,
447
    MVM_gc_allocate_object,
448
    initialize,
449
    copy_to,
450
    MVM_REPR_DEFAULT_ATTR_FUNCS,
451
    MVM_REPR_DEFAULT_BOX_FUNCS,
452
    {
453
        at_pos,
454
        bind_pos,
455
        MVM_REPR_DEFAULT_SET_ELEMS,
456
        push,
457
        pop,
458
        unshift,
459
        shift,
460
        MVM_REPR_DEFAULT_SPLICE,
461
        MVM_REPR_DEFAULT_AT_POS_MULTIDIM,
462
        MVM_REPR_DEFAULT_BIND_POS_MULTIDIM,
463
        MVM_REPR_DEFAULT_DIMENSIONS,
464
        MVM_REPR_DEFAULT_SET_DIMENSIONS,
465
        MVM_REPR_DEFAULT_GET_ELEM_STORAGE_SPEC
466
    },    /* pos_funcs */
467
    MVM_REPR_DEFAULT_ASS_FUNCS,
468
    elems,
469
    get_storage_spec,
470
    NULL, /* change_type */
471
    NULL, /* serialize */
472
    NULL, /* deserialize */
473
    serialize_repr_data,
474
    deserialize_repr_data,
475
    deserialize_stable_size,
476
    gc_mark,
477
    gc_free,
478
    gc_cleanup,
479
    gc_mark_repr_data,
480
    gc_free_repr_data,
481
    compose,
482
    NULL, /* spesh */
483
    "CArray", /* name */
484
    MVM_REPR_ID_MVMCArray,
485
    NULL, /* unmanaged_size */
486
    NULL, /* describe_refs */
487
};