Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/6model/containers.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
0
MVMint64 MVM_6model_container_iscont_rw(MVMThreadContext *tc, MVMObject *cont) {
4
0
    if (cont && IS_CONCRETE(cont)) {
5
0
        const MVMContainerSpec *cs = STABLE(cont)->container_spec;
6
0
        if (cs && cs->can_store(tc, cont)) {
7
0
            return 1;
8
0
        }
9
0
    }
10
0
    return 0;
11
0
}
12
13
/* ***************************************************************************
14
 * CodePair container configuration: container with FETCH/STORE code refs
15
 * ***************************************************************************/
16
17
 typedef struct {
18
    MVMObject *fetch_code;
19
    MVMObject *store_code;
20
} CodePairContData;
21
22
15
static void code_pair_fetch_internal(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res, MVMReturnType res_type) {
23
15
    CodePairContData        *data = (CodePairContData *)STABLE(cont)->container_data;
24
15
    MVMObject               *code = MVM_frame_find_invokee(tc, data->fetch_code, NULL);
25
15
    MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG);
26
15
    MVM_args_setup_thunk(tc, res, res_type, inv_arg_callsite);
27
15
    tc->cur_frame->args[0].o      = cont;
28
15
    STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args);
29
15
}
30
31
15
static void code_pair_fetch(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
32
15
    code_pair_fetch_internal(tc, cont, res, MVM_RETURN_OBJ);
33
15
}
34
35
0
static void code_pair_fetch_i(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
36
0
    code_pair_fetch_internal(tc, cont, res, MVM_RETURN_INT);
37
0
}
38
39
0
static void code_pair_fetch_n(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
40
0
    code_pair_fetch_internal(tc, cont, res, MVM_RETURN_NUM);
41
0
}
42
43
0
static void code_pair_fetch_s(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
44
0
    code_pair_fetch_internal(tc, cont, res, MVM_RETURN_STR);
45
0
}
46
47
12
static void code_pair_store_internal(MVMThreadContext *tc, MVMObject *cont, MVMRegister value, MVMCallsite *cs) {
48
12
    CodePairContData         *data = (CodePairContData *)STABLE(cont)->container_data;
49
12
    MVMObject                *code = MVM_frame_find_invokee(tc, data->store_code, NULL);
50
12
    MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, cs);
51
12
    tc->cur_frame->args[0].o       = cont;
52
12
    tc->cur_frame->args[1]         = value;
53
12
    STABLE(code)->invoke(tc, code, cs, tc->cur_frame->args);
54
12
}
55
56
12
static void code_pair_store(MVMThreadContext *tc, MVMObject *cont, MVMObject *obj) {
57
12
    MVMRegister r;
58
12
    r.o = obj;
59
12
    code_pair_store_internal(tc, cont, r, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_TWO_OBJ));
60
12
}
61
62
0
static void code_pair_store_i(MVMThreadContext *tc, MVMObject *cont, MVMint64 value) {
63
0
    MVMRegister r;
64
0
    r.i64 = value;
65
0
    code_pair_store_internal(tc, cont, r, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_OBJ_INT));
66
0
}
67
68
0
static void code_pair_store_n(MVMThreadContext *tc, MVMObject *cont, MVMnum64 value) {
69
0
    MVMRegister r;
70
0
    r.n64 = value;
71
0
    code_pair_store_internal(tc, cont, r, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_OBJ_NUM));
72
0
}
73
74
0
static void code_pair_store_s(MVMThreadContext *tc, MVMObject *cont, MVMString *value) {
75
0
    MVMRegister r;
76
0
    r.s = value;
77
0
    code_pair_store_internal(tc, cont, r, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_OBJ_STR));
78
0
}
79
80
0
static void code_pair_gc_mark_data(MVMThreadContext *tc, MVMSTable *st, MVMGCWorklist *worklist) {
81
0
    CodePairContData *data = (CodePairContData *)st->container_data;
82
0
83
0
    MVM_gc_worklist_add(tc, worklist, &data->fetch_code);
84
0
    MVM_gc_worklist_add(tc, worklist, &data->store_code);
85
0
}
86
87
0
static void code_pair_gc_free_data(MVMThreadContext *tc, MVMSTable *st) {
88
0
    MVM_free_null(st->container_data);
89
0
}
90
91
0
static void code_pair_serialize(MVMThreadContext *tc, MVMSTable *st, MVMSerializationWriter *writer) {
92
0
    CodePairContData *data = (CodePairContData *)st->container_data;
93
0
94
0
    MVM_serialization_write_ref(tc, writer, data->fetch_code);
95
0
    MVM_serialization_write_ref(tc, writer, data->store_code);
96
0
}
97
98
0
static void code_pair_deserialize(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
99
0
    CodePairContData *data = (CodePairContData *)st->container_data;
100
0
101
0
    MVM_ASSIGN_REF(tc, &(st->header), data->fetch_code, MVM_serialization_read_ref(tc, reader));
102
0
    MVM_ASSIGN_REF(tc, &(st->header), data->store_code, MVM_serialization_read_ref(tc, reader));
103
0
}
104
105
1
static MVMint32 code_pair_can_store(MVMThreadContext *tc, MVMObject *cont) {
106
1
    return 1;
107
1
}
108
109
static const MVMContainerSpec code_pair_spec = {
110
    "code_pair",
111
    code_pair_fetch,
112
    code_pair_fetch_i,
113
    code_pair_fetch_n,
114
    code_pair_fetch_s,
115
    code_pair_store,
116
    code_pair_store_i,
117
    code_pair_store_n,
118
    code_pair_store_s,
119
    code_pair_store,
120
    NULL, /* spesh */
121
    code_pair_gc_mark_data,
122
    code_pair_gc_free_data,
123
    code_pair_serialize,
124
    code_pair_deserialize,
125
    code_pair_can_store,
126
    NULL, /* cas */
127
    NULL, /* atomic_load */
128
    NULL, /* atomic_store */
129
    0
130
};
131
132
3
static void code_pair_set_container_spec(MVMThreadContext *tc, MVMSTable *st) {
133
3
    CodePairContData *data = MVM_malloc(sizeof(CodePairContData));
134
3
135
3
    data->fetch_code   = NULL;
136
3
    data->store_code   = NULL;
137
3
    st->container_data = data;
138
3
    st->container_spec = &code_pair_spec;
139
3
}
140
141
3
static void code_pair_configure_container_spec(MVMThreadContext *tc, MVMSTable *st, MVMObject *config) {
142
3
    CodePairContData *data = (CodePairContData *)st->container_data;
143
3
144
3
    MVMROOT(tc, config, {
145
3
        MVMString *fetch = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "fetch");
146
3
        MVMString *store;
147
3
148
3
        if (!MVM_repr_exists_key(tc, config, fetch))
149
3
            MVM_exception_throw_adhoc(tc, "Container spec 'code_pair' must be configured with a fetch");
150
3
151
3
        MVM_ASSIGN_REF(tc, &(st->header), data->fetch_code, MVM_repr_at_key_o(tc, config, fetch));
152
3
153
3
        store = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "store");
154
3
155
3
        if (!MVM_repr_exists_key(tc, config, store))
156
3
            MVM_exception_throw_adhoc(tc, "Container spec 'code_pair' must be configured with a store");
157
3
158
3
        MVM_ASSIGN_REF(tc, &(st->header), data->store_code, MVM_repr_at_key_o(tc, config, store));
159
3
    });
160
3
}
161
162
static const MVMContainerConfigurer CodePairContainerConfigurer = {
163
    code_pair_set_container_spec,
164
    code_pair_configure_container_spec
165
};
166
167
/* ***************************************************************************
168
 * Native reference container configuration
169
 * ***************************************************************************/
170
171
9
static void native_ref_fetch_i(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
172
9
    MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)STABLE(cont)->REPR_data;
173
9
    if (repr_data->primitive_type != MVM_STORAGE_SPEC_BP_INT)
174
0
        MVM_exception_throw_adhoc(tc, "This container does not reference a native integer");
175
9
    switch (repr_data->ref_kind) {
176
5
        case MVM_NATIVEREF_LEX:
177
5
            res->i64 = MVM_nativeref_read_lex_i(tc, cont);
178
5
            break;
179
1
        case MVM_NATIVEREF_ATTRIBUTE:
180
1
            res->i64 = MVM_nativeref_read_attribute_i(tc, cont);
181
1
            break;
182
1
        case MVM_NATIVEREF_POSITIONAL:
183
1
            res->i64 = MVM_nativeref_read_positional_i(tc, cont);
184
1
            break;
185
2
        case MVM_NATIVEREF_MULTIDIM:
186
2
            res->i64 = MVM_nativeref_read_multidim_i(tc, cont);
187
2
            break;
188
0
        default:
189
0
            MVM_exception_throw_adhoc(tc, "Unknown native int reference kind");
190
9
    }
191
9
}
192
193
9
static void native_ref_fetch_n(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
194
9
    MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)STABLE(cont)->REPR_data;
195
9
    if (repr_data->primitive_type != MVM_STORAGE_SPEC_BP_NUM)
196
0
        MVM_exception_throw_adhoc(tc, "This container does not reference a native number");
197
9
    switch (repr_data->ref_kind) {
198
5
        case MVM_NATIVEREF_LEX:
199
5
            res->n64 = MVM_nativeref_read_lex_n(tc, cont);
200
5
            break;
201
1
        case MVM_NATIVEREF_ATTRIBUTE:
202
1
            res->n64 = MVM_nativeref_read_attribute_n(tc, cont);
203
1
            break;
204
1
        case MVM_NATIVEREF_POSITIONAL:
205
1
            res->n64 = MVM_nativeref_read_positional_n(tc, cont);
206
1
            break;
207
2
        case MVM_NATIVEREF_MULTIDIM:
208
2
            res->n64 = MVM_nativeref_read_multidim_n(tc, cont);
209
2
            break;
210
0
        default:
211
0
            MVM_exception_throw_adhoc(tc, "Unknown native num reference kind");
212
9
    }
213
9
}
214
215
9
static void native_ref_fetch_s(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
216
9
    MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)STABLE(cont)->REPR_data;
217
9
    if (repr_data->primitive_type != MVM_STORAGE_SPEC_BP_STR)
218
0
        MVM_exception_throw_adhoc(tc, "This container does not reference a native string");
219
9
    switch (repr_data->ref_kind) {
220
5
        case MVM_NATIVEREF_LEX:
221
5
            res->s = MVM_nativeref_read_lex_s(tc, cont);
222
5
            break;
223
1
        case MVM_NATIVEREF_ATTRIBUTE:
224
1
            res->s = MVM_nativeref_read_attribute_s(tc, cont);
225
1
            break;
226
1
        case MVM_NATIVEREF_POSITIONAL:
227
1
            res->s = MVM_nativeref_read_positional_s(tc, cont);
228
1
            break;
229
2
        case MVM_NATIVEREF_MULTIDIM:
230
2
            res->s = MVM_nativeref_read_multidim_s(tc, cont);
231
2
            break;
232
0
        default:
233
0
            MVM_exception_throw_adhoc(tc, "Unknown native str reference kind");
234
9
    }
235
9
}
236
237
12
static void native_ref_fetch(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
238
12
    MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)STABLE(cont)->REPR_data;
239
12
    MVMHLLConfig         *hll       = STABLE(cont)->hll_owner;
240
12
    MVMRegister           tmp;
241
12
    if (!hll)
242
11
        hll = MVM_hll_current(tc);
243
12
    switch (repr_data->primitive_type) {
244
4
        case MVM_STORAGE_SPEC_BP_INT:
245
4
            native_ref_fetch_i(tc, cont, &tmp);
246
4
            res->o = MVM_repr_box_int(tc, hll->int_box_type, tmp.i64);
247
4
            break;
248
4
        case MVM_STORAGE_SPEC_BP_NUM:
249
4
            native_ref_fetch_n(tc, cont, &tmp);
250
4
            res->o = MVM_repr_box_num(tc, hll->num_box_type, tmp.n64);
251
4
            break;
252
4
        case MVM_STORAGE_SPEC_BP_STR:
253
4
            native_ref_fetch_s(tc, cont, &tmp);
254
4
            res->o = MVM_repr_box_str(tc, hll->str_box_type, tmp.s);
255
4
            break;
256
0
        default:
257
0
            MVM_exception_throw_adhoc(tc, "Unknown native reference primitive type");
258
12
    }
259
12
}
260
261
9
static void native_ref_store_i(MVMThreadContext *tc, MVMObject *cont, MVMint64 value) {
262
9
    MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)STABLE(cont)->REPR_data;
263
9
    if (repr_data->primitive_type != MVM_STORAGE_SPEC_BP_INT)
264
0
        MVM_exception_throw_adhoc(tc, "This container does not reference a native integer");
265
9
    switch (repr_data->ref_kind) {
266
2
        case MVM_NATIVEREF_LEX:
267
2
            MVM_nativeref_write_lex_i(tc, cont, value);
268
2
            break;
269
4
        case MVM_NATIVEREF_ATTRIBUTE:
270
4
            MVM_nativeref_write_attribute_i(tc, cont, value);
271
4
            break;
272
1
        case MVM_NATIVEREF_POSITIONAL:
273
1
            MVM_nativeref_write_positional_i(tc, cont, value);
274
1
            break;
275
2
        case MVM_NATIVEREF_MULTIDIM:
276
2
            MVM_nativeref_write_multidim_i(tc, cont, value);
277
2
            break;
278
0
        default:
279
0
            MVM_exception_throw_adhoc(tc, "Unknown native int reference kind");
280
9
    }
281
9
}
282
283
7
static void native_ref_store_n(MVMThreadContext *tc, MVMObject *cont, MVMnum64 value) {
284
7
    MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)STABLE(cont)->REPR_data;
285
7
    if (repr_data->primitive_type != MVM_STORAGE_SPEC_BP_NUM)
286
0
        MVM_exception_throw_adhoc(tc, "This container does not reference a native number");
287
7
    switch (repr_data->ref_kind) {
288
2
        case MVM_NATIVEREF_LEX:
289
2
            MVM_nativeref_write_lex_n(tc, cont, value);
290
2
            break;
291
2
        case MVM_NATIVEREF_ATTRIBUTE:
292
2
            MVM_nativeref_write_attribute_n(tc, cont, value);
293
2
            break;
294
1
        case MVM_NATIVEREF_POSITIONAL:
295
1
            MVM_nativeref_write_positional_n(tc, cont, value);
296
1
            break;
297
2
        case MVM_NATIVEREF_MULTIDIM:
298
2
            MVM_nativeref_write_multidim_n(tc, cont, value);
299
2
            break;
300
0
        default:
301
0
            MVM_exception_throw_adhoc(tc, "Unknown native num reference kind");
302
7
    }
303
7
}
304
305
7
static void native_ref_store_s(MVMThreadContext *tc, MVMObject *cont, MVMString *value) {
306
7
    MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)STABLE(cont)->REPR_data;
307
7
    if (repr_data->primitive_type != MVM_STORAGE_SPEC_BP_STR)
308
0
        MVM_exception_throw_adhoc(tc, "This container does not reference a native string");
309
7
    switch (repr_data->ref_kind) {
310
2
        case MVM_NATIVEREF_LEX:
311
2
            MVM_nativeref_write_lex_s(tc, cont, value);
312
2
            break;
313
2
        case MVM_NATIVEREF_ATTRIBUTE:
314
2
            MVM_nativeref_write_attribute_s(tc, cont, value);
315
2
            break;
316
1
        case MVM_NATIVEREF_POSITIONAL:
317
1
            MVM_nativeref_write_positional_s(tc, cont, value);
318
1
            break;
319
2
        case MVM_NATIVEREF_MULTIDIM:
320
2
            MVM_nativeref_write_multidim_s(tc, cont, value);
321
2
            break;
322
0
        default:
323
0
            MVM_exception_throw_adhoc(tc, "Unknown native str reference kind");
324
7
    }
325
7
}
326
327
6
static void native_ref_store(MVMThreadContext *tc, MVMObject *cont, MVMObject *obj) {
328
6
    MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)STABLE(cont)->REPR_data;
329
6
    switch (repr_data->primitive_type) {
330
2
        case MVM_STORAGE_SPEC_BP_INT:
331
2
            native_ref_store_i(tc, cont, MVM_repr_get_int(tc, obj));
332
2
            break;
333
2
        case MVM_STORAGE_SPEC_BP_NUM:
334
2
            native_ref_store_n(tc, cont, MVM_repr_get_num(tc, obj));
335
2
            break;
336
2
        case MVM_STORAGE_SPEC_BP_STR:
337
2
            native_ref_store_s(tc, cont, MVM_repr_get_str(tc, obj));
338
2
            break;
339
0
        default:
340
0
            MVM_exception_throw_adhoc(tc, "Unknown native reference primitive type");
341
6
    }
342
6
}
343
344
0
static void native_ref_serialize(MVMThreadContext *tc, MVMSTable *st, MVMSerializationWriter *writer) {
345
0
    /* Nothing to do. */
346
0
}
347
348
0
static void native_ref_deserialize(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
349
0
    /* Nothing to do. */
350
0
}
351
352
0
static MVMint32 native_ref_can_store(MVMThreadContext *tc, MVMObject *cont) {
353
0
    return 1;
354
0
}
355
356
static const MVMContainerSpec native_ref_spec = {
357
    "native_ref",
358
    native_ref_fetch,
359
    native_ref_fetch_i,
360
    native_ref_fetch_n,
361
    native_ref_fetch_s,
362
    native_ref_store,
363
    native_ref_store_i,
364
    native_ref_store_n,
365
    native_ref_store_s,
366
    native_ref_store,
367
    NULL, /* spesh */
368
    NULL, /* gc_mark_data */
369
    NULL, /* gc_free_data */
370
    native_ref_serialize,
371
    native_ref_deserialize,
372
    native_ref_can_store,
373
    NULL, /* cas */
374
    NULL, /* atomic_load */
375
    NULL, /* atomic_store */
376
    1
377
};
378
379
19
static void native_ref_set_container_spec(MVMThreadContext *tc, MVMSTable *st) {
380
19
    st->container_spec = &native_ref_spec;
381
19
}
382
383
19
static void native_ref_configure_container_spec(MVMThreadContext *tc, MVMSTable *st, MVMObject *config) {
384
19
    /* Nothing to do. */
385
19
}
386
387
static const MVMContainerConfigurer NativeRefContainerConfigurer = {
388
    native_ref_set_container_spec,
389
    native_ref_configure_container_spec
390
};
391
392
/* ***************************************************************************
393
 * Container registry and configuration
394
 * ***************************************************************************/
395
396
/* Adds a container configurer to the registry. */
397
void MVM_6model_add_container_config(MVMThreadContext *tc, MVMString *name,
398
288
        const MVMContainerConfigurer *configurer) {
399
288
    MVMContainerRegistry *entry;
400
288
401
288
    uv_mutex_lock(&tc->instance->mutex_container_registry);
402
288
403
288
    MVM_HASH_GET(tc, tc->instance->container_registry, name, entry);
404
288
405
288
    if (!entry) {
406
288
        entry = MVM_malloc(sizeof(MVMContainerRegistry));
407
288
        entry->name = name;
408
288
        entry->configurer  = configurer;
409
288
        MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&entry->name,
410
288
            "Container configuration name");
411
288
        MVM_HASH_BIND(tc, tc->instance->container_registry, name, entry);
412
288
        MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&entry->hash_handle.key,
413
288
            "Container configuration hash key");
414
288
    }
415
288
416
288
    uv_mutex_unlock(&tc->instance->mutex_container_registry);
417
288
}
418
419
/* Gets a container configurer from the registry. */
420
22
const MVMContainerConfigurer * MVM_6model_get_container_config(MVMThreadContext *tc, MVMString *name) {
421
22
    MVMContainerRegistry *entry;
422
22
    MVM_HASH_GET(tc, tc->instance->container_registry, name, entry);
423
22
    return entry != NULL ? entry->configurer : NULL;
424
22
}
425
426
/* Does initial setup work of the container registry, including registering
427
 * the various built-in container types. */
428
144
void MVM_6model_containers_setup(MVMThreadContext *tc) {
429
144
    /* Add built-in configurations. */
430
144
    MVM_6model_add_container_config(tc,
431
144
        MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "code_pair"), &CodePairContainerConfigurer);
432
144
    MVM_6model_add_container_config(tc,
433
144
        MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "native_ref"), &NativeRefContainerConfigurer);
434
144
}
435
436
/* ***************************************************************************
437
 * Native container/reference operations
438
 * ***************************************************************************/
439
440
/* Check if this is a container referencing a given native. */
441
42
static MVMint64 get_container_primitive(MVMThreadContext *tc, MVMObject *cont) {
442
42
    if (cont && IS_CONCRETE(cont)) {
443
39
        const MVMContainerSpec *cs = STABLE(cont)->container_spec;
444
39
        if (cs == &native_ref_spec && REPR(cont)->ID == MVM_REPR_ID_NativeRef)
445
30
            return ((MVMNativeRefREPRData *)STABLE(cont)->REPR_data)->primitive_type;
446
39
    }
447
12
    return MVM_STORAGE_SPEC_BP_NONE;
448
42
}
449
14
MVMint64 MVM_6model_container_iscont_i(MVMThreadContext *tc, MVMObject *cont) {
450
14
    return get_container_primitive(tc, cont) == MVM_STORAGE_SPEC_BP_INT;
451
14
}
452
14
MVMint64 MVM_6model_container_iscont_n(MVMThreadContext *tc, MVMObject *cont) {
453
14
    return get_container_primitive(tc, cont) == MVM_STORAGE_SPEC_BP_NUM;
454
14
}
455
14
MVMint64 MVM_6model_container_iscont_s(MVMThreadContext *tc, MVMObject *cont) {
456
14
    return get_container_primitive(tc, cont) == MVM_STORAGE_SPEC_BP_STR;
457
14
}
458
459
/* If it's a container, do a fetch_i. Otherwise, try to unbox the received
460
 * value as a native integer. */
461
11
void MVM_6model_container_decont_i(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
462
11
    const MVMContainerSpec *cs = STABLE(cont)->container_spec;
463
11
    if (cs && IS_CONCRETE(cont))
464
5
        cs->fetch_i(tc, cont, res);
465
11
    else
466
6
        res->i64 = MVM_repr_get_int(tc, cont);
467
11
}
468
469
/* If it's a container, do a fetch_n. Otherwise, try to unbox the received
470
 * value as a native number. */
471
7
void MVM_6model_container_decont_n(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
472
7
    const MVMContainerSpec *cs = STABLE(cont)->container_spec;
473
7
    if (cs && IS_CONCRETE(cont))
474
5
        cs->fetch_n(tc, cont, res);
475
7
    else
476
2
        res->n64 = MVM_repr_get_num(tc, cont);
477
7
}
478
479
/* If it's a container, do a fetch_s. Otherwise, try to unbox the received
480
 * value as a native string. */
481
7
void MVM_6model_container_decont_s(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
482
7
    const MVMContainerSpec *cs = STABLE(cont)->container_spec;
483
7
    if (cs && IS_CONCRETE(cont))
484
5
        cs->fetch_s(tc, cont, res);
485
7
    else
486
2
        res->s = MVM_repr_get_str(tc, cont);
487
7
}
488
489
/* If it's a container, do a fetch_i. Otherwise, try to unbox the received
490
 * value as a native unsigned integer. */
491
0
void MVM_6model_container_decont_u(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) {
492
0
    const MVMContainerSpec *cs = STABLE(cont)->container_spec;
493
0
    if (cs && IS_CONCRETE(cont))
494
0
        /* XXX We need a fetch_u at some point. */
495
0
        cs->fetch_i(tc, cont, res);
496
0
    else
497
0
        res->u64 = MVM_repr_get_uint(tc, cont);
498
0
}
499
500
/* Checks we have a container, and provided we do, assigns an int into it. */
501
7
void MVM_6model_container_assign_i(MVMThreadContext *tc, MVMObject *cont, MVMint64 value) {
502
7
    const MVMContainerSpec *cs = STABLE(cont)->container_spec;
503
7
    if (cs && IS_CONCRETE(cont))
504
7
        cs->store_i(tc, cont, value);
505
7
    else
506
0
        MVM_exception_throw_adhoc(tc, "Cannot assign to an immutable value");
507
7
}
508
509
/* Checks we have a container, and provided we do, assigns a num into it. */
510
5
void MVM_6model_container_assign_n(MVMThreadContext *tc, MVMObject *cont, MVMnum64 value) {
511
5
    const MVMContainerSpec *cs = STABLE(cont)->container_spec;
512
5
    if (cs && IS_CONCRETE(cont))
513
5
        cs->store_n(tc, cont, value);
514
5
    else
515
0
        MVM_exception_throw_adhoc(tc, "Cannot assign to an immutable value");
516
5
}
517
518
/* Checks we have a container, and provided we do, assigns a str into it. */
519
5
void MVM_6model_container_assign_s(MVMThreadContext *tc, MVMObject *cont, MVMString *value) {
520
5
    const MVMContainerSpec *cs = STABLE(cont)->container_spec;
521
5
    if (cs && IS_CONCRETE(cont))
522
5
        cs->store_s(tc, cont, value);
523
5
    else
524
0
        MVM_exception_throw_adhoc(tc, "Cannot assign to an immutable value");
525
5
}
526
527
/* ***************************************************************************
528
 * Container atomic operations
529
 * ***************************************************************************/
530
531
void MVM_6model_container_cas(MVMThreadContext *tc, MVMObject *cont,
532
                              MVMObject *expected, MVMObject *value,
533
0
                              MVMRegister *result) {
534
0
    if (IS_CONCRETE(cont)) {
535
0
        MVMContainerSpec const *cs = cont->st->container_spec;
536
0
        if (cs) {
537
0
            if (cs->cas)
538
0
                cs->cas(tc, cont, expected, value, result);
539
0
            else
540
0
                MVM_exception_throw_adhoc(tc,
541
0
                    "A %s container does not know how to do atomic compare and swap",
542
0
                     MVM_6model_get_stable_debug_name(tc, cont->st));
543
0
        }
544
0
        else {
545
0
            MVM_exception_throw_adhoc(tc,
546
0
                "Cannot perform atomic compare and swap on non-container value of type %s",
547
0
                 MVM_6model_get_stable_debug_name(tc, cont->st));
548
0
        }
549
0
    }
550
0
    else {
551
0
        MVM_exception_throw_adhoc(tc,
552
0
            "Cannot perform atomic compare and swap on %s type object",
553
0
             MVM_6model_get_stable_debug_name(tc, cont->st));
554
0
    }
555
0
}
556
557
0
MVMObject * MVM_6model_container_atomic_load(MVMThreadContext *tc, MVMObject *cont) {
558
0
    if (IS_CONCRETE(cont)) {
559
0
        MVMContainerSpec const *cs = cont->st->container_spec;
560
0
        if (cs) {
561
0
            if (cs->atomic_load)
562
0
                return cs->atomic_load(tc, cont);
563
0
            else
564
0
                MVM_exception_throw_adhoc(tc,
565
0
                    "A %s container does not know how to do an atomic load",
566
0
                     MVM_6model_get_stable_debug_name(tc, cont->st));
567
0
        }
568
0
        else {
569
0
            MVM_exception_throw_adhoc(tc,
570
0
                "Cannot perform atomic load from a non-container value of type %s",
571
0
                 MVM_6model_get_stable_debug_name(tc, cont->st));
572
0
        }
573
0
    }
574
0
    else {
575
0
        MVM_exception_throw_adhoc(tc,
576
0
            "Cannot perform atomic load from %s type object",
577
0
             MVM_6model_get_stable_debug_name(tc, cont->st));
578
0
    }
579
0
}
580
581
0
void MVM_6model_container_atomic_store(MVMThreadContext *tc, MVMObject *cont, MVMObject *value) {
582
0
    if (IS_CONCRETE(cont)) {
583
0
        MVMContainerSpec const *cs = cont->st->container_spec;
584
0
        if (cs) {
585
0
            if (cs->atomic_store)
586
0
                cs->atomic_store(tc, cont, value);
587
0
            else
588
0
                MVM_exception_throw_adhoc(tc,
589
0
                    "A %s container does not know how to do an atomic store",
590
0
                     MVM_6model_get_stable_debug_name(tc, cont->st));
591
0
        }
592
0
        else {
593
0
            MVM_exception_throw_adhoc(tc,
594
0
                "Cannot perform atomic store to a non-container value of type %s",
595
0
                 MVM_6model_get_stable_debug_name(tc, cont->st));
596
0
        }
597
0
    }
598
0
    else {
599
0
        MVM_exception_throw_adhoc(tc,
600
0
            "Cannot perform atomic store to %s type object",
601
0
             MVM_6model_get_stable_debug_name(tc, cont->st));
602
0
    }
603
0
}
604
605
0
static AO_t * native_ref_as_atomic_i(MVMThreadContext *tc, MVMObject *cont) {
606
0
    if (REPR(cont)->ID == MVM_REPR_ID_NativeRef && IS_CONCRETE(cont)) {
607
0
        MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)STABLE(cont)->REPR_data;
608
0
        if (repr_data->primitive_type == MVM_STORAGE_SPEC_BP_INT) {
609
0
            switch (repr_data->ref_kind) {
610
0
                case MVM_NATIVEREF_LEX:
611
0
                    return MVM_nativeref_as_atomic_lex_i(tc, cont);
612
0
                case MVM_NATIVEREF_ATTRIBUTE:
613
0
                    return MVM_nativeref_as_atomic_attribute_i(tc, cont);
614
0
                case MVM_NATIVEREF_POSITIONAL:
615
0
                    return MVM_nativeref_as_atomic_positional_i(tc, cont);
616
0
                case MVM_NATIVEREF_MULTIDIM:
617
0
                    return MVM_nativeref_as_atomic_multidim_i(tc, cont);
618
0
                default:
619
0
                    MVM_exception_throw_adhoc(tc, "Unknown native int reference kind");
620
0
            }
621
0
        }
622
0
    }
623
0
    MVM_exception_throw_adhoc(tc,
624
0
        "Can only do integer atomic operations on a container referencing a native integer");
625
0
}
626
627
MVMint64 MVM_6model_container_cas_i(MVMThreadContext *tc, MVMObject *cont,
628
0
                                    MVMint64 expected, MVMint64 value) {
629
0
    return (MVMint64)MVM_cas(native_ref_as_atomic_i(tc, cont), (AO_t)expected, (AO_t)value);
630
0
}
631
632
0
MVMint64 MVM_6model_container_atomic_load_i(MVMThreadContext *tc, MVMObject *cont) {
633
0
    return (MVMint64)MVM_load(native_ref_as_atomic_i(tc, cont));
634
0
}
635
636
0
void MVM_6model_container_atomic_store_i(MVMThreadContext *tc, MVMObject *cont, MVMint64 value) {
637
0
    MVM_store(native_ref_as_atomic_i(tc, cont), value);
638
0
}
639
640
0
MVMint64 MVM_6model_container_atomic_inc(MVMThreadContext *tc, MVMObject *cont) {
641
0
    return (MVMint64)MVM_incr(native_ref_as_atomic_i(tc, cont));
642
0
}
643
644
0
MVMint64 MVM_6model_container_atomic_dec(MVMThreadContext *tc, MVMObject *cont) {
645
0
    return (MVMint64)MVM_decr(native_ref_as_atomic_i(tc, cont));
646
0
}
647
648
0
MVMint64 MVM_6model_container_atomic_add(MVMThreadContext *tc, MVMObject *cont, MVMint64 value) {
649
0
    return (MVMint64)MVM_add(native_ref_as_atomic_i(tc, cont), (AO_t)value);
650
0
}