Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/6model/reprs/MVMIter.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 MVMIter_this_repr;
5
6
/* Creates a new type object of this representation, and associates it with
7
 * the given HOW. */
8
144
static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
9
144
    MVMSTable *st = MVM_gc_allocate_stable(tc, &MVMIter_this_repr, HOW);
10
144
11
144
    MVMROOT(tc, st, {
12
144
        MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
13
144
        MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj);
14
144
        st->size = sizeof(MVMIter);
15
144
    });
16
144
17
144
    return st->WHAT;
18
144
}
19
20
/* Copies the body of one object to another. */
21
0
static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) {
22
0
    MVM_exception_throw_adhoc(tc, "Cannot copy object with representation VMIter");
23
0
}
24
25
/* Adds held objects to the GC worklist. */
26
597
static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) {
27
597
    MVMIterBody  *body  = (MVMIterBody *)data;
28
597
    MVM_gc_worklist_add(tc, worklist, &body->target);
29
597
}
30
31
/* Called by the VM in order to free memory associated with this object. */
32
478k
static void gc_free(MVMThreadContext *tc, MVMObject *obj) {
33
478k
}
34
35
static const MVMStorageSpec storage_spec = {
36
    MVM_STORAGE_SPEC_REFERENCE, /* inlineable */
37
    0,                          /* bits */
38
    0,                          /* align */
39
    MVM_STORAGE_SPEC_BP_NONE,   /* boxed_primitive */
40
    0,                          /* can_box */
41
    0,                          /* is_unsigned */
42
};
43
44
/* Gets the storage specification for this representation. */
45
8.75k
static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
46
8.75k
    return &storage_spec;
47
8.75k
}
48
49
1.33M
static void shift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) {
50
1.33M
    MVMIterBody *body = (MVMIterBody *)data;
51
1.33M
    MVMObject *target = body->target;
52
1.33M
    switch (body->mode) {
53
463k
        case MVM_ITER_MODE_ARRAY:
54
463k
            body->array_state.index++;
55
463k
            if (body->array_state.index >= body->array_state.limit)
56
0
                MVM_exception_throw_adhoc(tc, "Iteration past end of iterator");
57
463k
            REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, value, kind);
58
463k
            return;
59
2
        case MVM_ITER_MODE_ARRAY_INT:
60
2
            body->array_state.index++;
61
2
            if (body->array_state.index >= body->array_state.limit)
62
0
                MVM_exception_throw_adhoc(tc, "Iteration past end of iterator");
63
2
            if (kind == MVM_reg_int64) {
64
0
                REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, value, kind);
65
0
            }
66
2
            else if (kind == MVM_reg_obj) {
67
2
                MVMRegister tmp;
68
2
                REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, &tmp, MVM_reg_int64);
69
2
                value->o = MVM_repr_box_int(tc, MVM_hll_current(tc)->int_box_type, tmp.i64);
70
2
            }
71
0
            else {
72
0
                MVM_exception_throw_adhoc(tc, "Wrong register kind in iteration");
73
0
            }
74
2
            return;
75
2
        case MVM_ITER_MODE_ARRAY_NUM:
76
2
            body->array_state.index++;
77
2
            if (body->array_state.index >= body->array_state.limit)
78
0
                MVM_exception_throw_adhoc(tc, "Iteration past end of iterator");
79
2
            if (kind == MVM_reg_num64) {
80
0
                REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, value, kind);
81
0
            }
82
2
            else if (kind == MVM_reg_obj) {
83
2
                MVMRegister tmp;
84
2
                REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, &tmp, MVM_reg_num64);
85
2
                value->o = MVM_repr_box_num(tc, MVM_hll_current(tc)->num_box_type, tmp.n64);
86
2
            }
87
0
            else {
88
0
                MVM_exception_throw_adhoc(tc, "Wrong register kind in iteration");
89
0
            }
90
2
            return;
91
2
        case MVM_ITER_MODE_ARRAY_STR:
92
2
            body->array_state.index++;
93
2
            if (body->array_state.index >= body->array_state.limit)
94
0
                MVM_exception_throw_adhoc(tc, "Iteration past end of iterator");
95
2
            if (kind == MVM_reg_str) {
96
0
                REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, value, kind);
97
0
            }
98
2
            else if (kind == MVM_reg_obj) {
99
2
                MVMRegister tmp;
100
2
                REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, &tmp, MVM_reg_str);
101
2
                value->o = MVM_repr_box_str(tc, MVM_hll_current(tc)->str_box_type, tmp.s);
102
2
            }
103
0
            else {
104
0
                MVM_exception_throw_adhoc(tc, "Wrong register kind in iteration");
105
0
            }
106
2
            return;
107
868k
        case MVM_ITER_MODE_HASH:
108
868k
            body->hash_state.curr = body->hash_state.next;
109
868k
            if (!body->hash_state.curr)
110
0
                MVM_exception_throw_adhoc(tc, "Iteration past end of iterator");
111
868k
            body->hash_state.next = HASH_ITER_NEXT_ITEM(
112
868k
                &(body->hash_state.next->hash_handle),
113
868k
                &(body->hash_state.bucket_state));
114
868k
            value->o = root;
115
868k
            return;
116
0
        default:
117
0
            MVM_exception_throw_adhoc(tc, "Unknown iteration mode");
118
1.33M
    }
119
1.33M
}
120
121
/* This whole splice optimization can be optimized for the case we have two
122
 * MVMIter representation objects. */
123
0
static void isplice(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *from, MVMint64 offset, MVMuint64 count) {
124
0
}
125
126
0
static MVMStorageSpec get_elem_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
127
0
    MVMStorageSpec spec;
128
0
    spec.inlineable      = MVM_STORAGE_SPEC_REFERENCE;
129
0
    spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NONE;
130
0
    spec.can_box         = 0;
131
0
    spec.bits            = 0;
132
0
    spec.align           = 0;
133
0
    spec.is_unsigned     = 0;
134
0
    return spec;
135
0
}
136
137
/* Compose the representation. */
138
0
static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info) {
139
0
    /* XXX element type supplied through this... */
140
0
}
141
142
/* Set the size of the STable. */
143
288
static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
144
288
    st->size = sizeof(MVMIter);
145
288
}
146
147
/* Initializes the representation. */
148
144
const MVMREPROps * MVMIter_initialize(MVMThreadContext *tc) {
149
144
    return &MVMIter_this_repr;
150
144
}
151
152
static const MVMREPROps MVMIter_this_repr = {
153
    type_object_for,
154
    MVM_gc_allocate_object,
155
    NULL, /* initialize */
156
    copy_to,
157
    MVM_REPR_DEFAULT_ATTR_FUNCS,
158
    MVM_REPR_DEFAULT_BOX_FUNCS,
159
    {
160
        MVM_REPR_DEFAULT_AT_POS,
161
        MVM_REPR_DEFAULT_BIND_POS,
162
        MVM_REPR_DEFAULT_SET_ELEMS,
163
        MVM_REPR_DEFAULT_PUSH,
164
        MVM_REPR_DEFAULT_POP,
165
        MVM_REPR_DEFAULT_UNSHIFT,
166
        shift,
167
        MVM_REPR_DEFAULT_SLICE,
168
        isplice,
169
        MVM_REPR_DEFAULT_AT_POS_MULTIDIM,
170
        MVM_REPR_DEFAULT_BIND_POS_MULTIDIM,
171
        MVM_REPR_DEFAULT_DIMENSIONS,
172
        MVM_REPR_DEFAULT_SET_DIMENSIONS,
173
        get_elem_storage_spec,
174
        MVM_REPR_DEFAULT_POS_AS_ATOMIC,
175
        MVM_REPR_DEFAULT_POS_AS_ATOMIC_MULTIDIM
176
    },    /* pos_funcs */
177
    MVM_REPR_DEFAULT_ASS_FUNCS,
178
    MVM_REPR_DEFAULT_ELEMS,
179
    get_storage_spec,
180
    NULL, /* change_type */
181
    NULL, /* serialize */
182
    NULL, /* deserialize */
183
    NULL, /* serialize_repr_data */
184
    NULL, /* deserialize_repr_data */
185
    deserialize_stable_size,
186
    gc_mark,
187
    gc_free,
188
    NULL, /* gc_cleanup */
189
    NULL, /* gc_mark_repr_data */
190
    NULL, /* gc_free_repr_data */
191
    compose,
192
    NULL, /* spesh */
193
    "VMIter", /* name */
194
    MVM_REPR_ID_MVMIter,
195
    NULL, /* unmanaged_size */
196
    NULL, /* describe_refs */
197
};
198
199
666k
MVMObject * MVM_iter(MVMThreadContext *tc, MVMObject *target) {
200
666k
    MVMIter *iterator;
201
666k
    if (!IS_CONCRETE(target)) {
202
0
        MVM_exception_throw_adhoc(tc, "Cannot iterate over a %s type object", MVM_6model_get_debug_name(tc, target));
203
0
    }
204
666k
    MVMROOT(tc, target, {
205
666k
        if (REPR(target)->ID == MVM_REPR_ID_VMArray) {
206
666k
            iterator = (MVMIter *)MVM_repr_alloc_init(tc,
207
666k
                MVM_hll_current(tc)->array_iterator_type);
208
666k
            iterator->body.array_state.index = -1;
209
666k
            iterator->body.array_state.limit = REPR(target)->elems(tc, STABLE(target), target, OBJECT_BODY(target));
210
666k
            MVM_ASSIGN_REF(tc, &(iterator->common.header), iterator->body.target, target);
211
666k
            switch (REPR(target)->pos_funcs.get_elem_storage_spec(tc, STABLE(target)).boxed_primitive) {
212
666k
                case MVM_STORAGE_SPEC_BP_INT: iterator->body.mode = MVM_ITER_MODE_ARRAY_INT; break;
213
666k
                case MVM_STORAGE_SPEC_BP_NUM: iterator->body.mode = MVM_ITER_MODE_ARRAY_NUM; break;
214
666k
                case MVM_STORAGE_SPEC_BP_STR: iterator->body.mode = MVM_ITER_MODE_ARRAY_STR; break;
215
666k
                default:                      iterator->body.mode = MVM_ITER_MODE_ARRAY; break;
216
666k
            }
217
666k
        }
218
666k
        else if (REPR(target)->ID == MVM_REPR_ID_MVMHash) {
219
666k
            iterator = (MVMIter *)MVM_repr_alloc_init(tc,
220
666k
                MVM_hll_current(tc)->hash_iterator_type);
221
666k
            iterator->body.mode = MVM_ITER_MODE_HASH;
222
666k
            iterator->body.hash_state.bucket_state = 0;
223
666k
            iterator->body.hash_state.curr         = NULL;
224
666k
            iterator->body.hash_state.next         = HASH_ITER_FIRST_ITEM(
225
666k
                ((MVMHash *)target)->body.hash_head
226
666k
                    ? ((MVMHash *)target)->body.hash_head->hash_handle.tbl
227
666k
                    : NULL,
228
666k
                &(iterator->body.hash_state.bucket_state));
229
666k
            MVM_ASSIGN_REF(tc, &(iterator->common.header), iterator->body.target, target);
230
666k
        }
231
666k
        else if (REPR(target)->ID == MVM_REPR_ID_MVMContext) {
232
666k
            /* Turn the context into a VMHash and then iterate that. */
233
666k
            MVMHLLConfig *hll = MVM_hll_current(tc);
234
666k
            MVMObject *ctx_hash = MVM_repr_alloc_init(tc, hll->slurpy_hash_type);
235
666k
            MVMROOT(tc, ctx_hash, {
236
666k
                MVMContext          *ctx    = (MVMContext *)target;
237
666k
                MVMFrame            *frame  = ctx->body.context;
238
666k
                MVMStaticFrame      *sf     = frame->static_info;
239
666k
                MVMLexicalRegistry **lexreg = sf->body.lexical_names_list;
240
666k
                MVMuint32 i;
241
666k
                MVMROOT2(tc, frame, sf, {
242
666k
                    for (i = 0; i < sf->body.num_lexicals; i++) {
243
666k
                        MVMuint32 idx  = lexreg[i]->value;
244
666k
                        MVMuint16 type = sf->body.lexical_types[idx];
245
666k
                        switch (type) {
246
666k
                            case MVM_reg_obj: {
247
666k
                                MVMObject *obj = frame->env[idx].o;
248
666k
                                if (!obj)
249
666k
                                    obj = MVM_frame_vivify_lexical(tc, frame, idx);
250
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, obj);
251
666k
                                break;
252
666k
                            }
253
666k
                            case MVM_reg_str: {
254
666k
                                MVMObject *bs = MVM_repr_box_str(tc, hll->str_box_type,
255
666k
                                    frame->env[idx].s);
256
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bs);
257
666k
                                break;
258
666k
                            }
259
666k
                            case MVM_reg_int8: {
260
666k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
261
666k
                                    frame->env[idx].i8);
262
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
263
666k
                                break;
264
666k
                            }
265
666k
                            case MVM_reg_uint8: {
266
666k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
267
666k
                                    frame->env[idx].u8);
268
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
269
666k
                                break;
270
666k
                            }
271
666k
                            case MVM_reg_int16: {
272
666k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
273
666k
                                    frame->env[idx].i16);
274
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
275
666k
                                break;
276
666k
                            }
277
666k
                            case MVM_reg_uint16: {
278
666k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
279
666k
                                    frame->env[idx].u16);
280
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
281
666k
                                break;
282
666k
                            }
283
666k
                            case MVM_reg_int32: {
284
666k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
285
666k
                                    frame->env[idx].i32);
286
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
287
666k
                                break;
288
666k
                            }
289
666k
                            case MVM_reg_uint32: {
290
666k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
291
666k
                                    frame->env[idx].u32);
292
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
293
666k
                                break;
294
666k
                            }
295
666k
                            case MVM_reg_int64: {
296
666k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
297
666k
                                    frame->env[idx].i64);
298
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
299
666k
                                break;
300
666k
                            }
301
666k
                            case MVM_reg_uint64: {
302
666k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
303
666k
                                    frame->env[idx].u64);
304
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
305
666k
                                break;
306
666k
                            }
307
666k
                            case MVM_reg_num32: {
308
666k
                                MVMObject *bn = MVM_repr_box_num(tc, hll->num_box_type,
309
666k
                                    frame->env[idx].n32);
310
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bn);
311
666k
                                break;
312
666k
                            }
313
666k
                            case MVM_reg_num64: {
314
666k
                                MVMObject *bn = MVM_repr_box_num(tc, hll->num_box_type,
315
666k
                                    frame->env[idx].n64);
316
666k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bn);
317
666k
                                break;
318
666k
                            }
319
666k
                            default:
320
666k
                                MVM_exception_throw_adhoc(tc,
321
666k
                                    "%s lexical type encountered while building context iterator", MVM_reg_get_debug_name(tc, type));
322
666k
                        }
323
666k
                    }
324
666k
                });
325
666k
            });
326
666k
327
666k
            /* Call ourselves recursively to get the iterator for this
328
666k
            * hash. */
329
666k
            iterator = (MVMIter *)MVM_iter(tc, ctx_hash);
330
666k
        }
331
666k
        else {
332
666k
            MVM_exception_throw_adhoc(tc, "Cannot iterate object with %s representation (%s)",
333
666k
                REPR(target)->name, MVM_6model_get_debug_name(tc, target));
334
666k
        }
335
666k
    });
336
666k
    return (MVMObject *)iterator;
337
666k
}
338
339
1.98M
MVMint64 MVM_iter_istrue(MVMThreadContext *tc, MVMIter *iter) {
340
1.98M
    switch (iter->body.mode) {
341
735k
        case MVM_ITER_MODE_ARRAY:
342
735k
        case MVM_ITER_MODE_ARRAY_INT:
343
735k
        case MVM_ITER_MODE_ARRAY_NUM:
344
735k
        case MVM_ITER_MODE_ARRAY_STR:
345
460k
            return iter->body.array_state.index + 1 < iter->body.array_state.limit ? 1 : 0;
346
0
            break;
347
1.25M
        case MVM_ITER_MODE_HASH:
348
868k
            return iter->body.hash_state.next != NULL ? 1 : 0;
349
0
            break;
350
0
        default:
351
0
            MVM_exception_throw_adhoc(tc, "Invalid iteration mode used");
352
1.98M
    }
353
1.98M
}
354
355
871k
MVMString * MVM_iterkey_s(MVMThreadContext *tc, MVMIter *iterator) {
356
871k
    if (REPR(iterator)->ID != MVM_REPR_ID_MVMIter
357
871k
            || iterator->body.mode != MVM_ITER_MODE_HASH)
358
0
        MVM_exception_throw_adhoc(tc, "This is not a hash iterator, it's a %s (%s)", REPR(iterator)->name, MVM_6model_get_debug_name(tc, (MVMObject *)iterator));
359
871k
    if (!iterator->body.hash_state.curr)
360
0
        MVM_exception_throw_adhoc(tc, "You have not advanced to the first item of the hash iterator, or have gone past the end");
361
871k
    return MVM_HASH_KEY(iterator->body.hash_state.curr);
362
871k
}
363
364
848k
MVMObject * MVM_iterval(MVMThreadContext *tc, MVMIter *iterator) {
365
848k
    MVMIterBody *body;
366
848k
    MVMObject *target;
367
848k
    MVMRegister result;
368
848k
    if (REPR(iterator)->ID != MVM_REPR_ID_MVMIter)
369
0
        MVM_exception_throw_adhoc(tc, "This is not an iterator, it's a %s (%s)", REPR(iterator)->name, MVM_6model_get_debug_name(tc, (MVMObject *)iterator));
370
848k
    if (iterator->body.mode == MVM_ITER_MODE_ARRAY) {
371
0
        body = &iterator->body;
372
0
        if (body->array_state.index == -1)
373
0
            MVM_exception_throw_adhoc(tc, "You have not yet advanced in the array iterator");
374
0
        target = body->target;
375
0
        REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, &result, MVM_reg_obj);
376
0
    }
377
848k
    else if (iterator->body.mode == MVM_ITER_MODE_HASH) {
378
848k
        if (!iterator->body.hash_state.curr)
379
0
            MVM_exception_throw_adhoc(tc, "You have not advanced to the first item of the hash iterator, or have gone past the end");
380
848k
        result.o = iterator->body.hash_state.curr->value;
381
848k
        if (!result.o)
382
0
            result.o = tc->instance->VMNull;
383
848k
    }
384
0
    else {
385
0
        MVM_exception_throw_adhoc(tc, "Unknown iterator mode in iterval");
386
0
    }
387
848k
    return result.o;
388
848k
}