Coverage Report

Created: 2017-04-15 07:07

/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
130
static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
9
130
    MVMSTable *st = MVM_gc_allocate_stable(tc, &MVMIter_this_repr, HOW);
10
130
11
130
    MVMROOT(tc, st, {
12
130
        MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
13
130
        MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj);
14
130
        st->size = sizeof(MVMIter);
15
130
    });
16
130
17
130
    return st->WHAT;
18
130
}
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
524
static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) {
27
524
    MVMIterBody  *body  = (MVMIterBody *)data;
28
524
    MVM_gc_worklist_add(tc, worklist, &body->target);
29
524
}
30
31
/* Called by the VM in order to free memory associated with this object. */
32
384k
static void gc_free(MVMThreadContext *tc, MVMObject *obj) {
33
384k
}
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
6.12k
static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
46
6.12k
    return &storage_spec;
47
6.12k
}
48
49
1.09M
static void shift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) {
50
1.09M
    MVMIterBody *body = (MVMIterBody *)data;
51
1.09M
    MVMObject *target = body->target;
52
1.09M
    switch (body->mode) {
53
386k
        case MVM_ITER_MODE_ARRAY:
54
386k
            body->array_state.index++;
55
386k
            if (body->array_state.index >= body->array_state.limit)
56
0
                MVM_exception_throw_adhoc(tc, "Iteration past end of iterator");
57
386k
            REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, value, kind);
58
386k
            return;
59
0
        case MVM_ITER_MODE_ARRAY_INT:
60
0
            body->array_state.index++;
61
0
            if (body->array_state.index >= body->array_state.limit)
62
0
                MVM_exception_throw_adhoc(tc, "Iteration past end of iterator");
63
0
            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
0
            else if (kind == MVM_reg_obj) {
67
0
                MVMRegister tmp;
68
0
                REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, &tmp, MVM_reg_int64);
69
0
                value->o = MVM_repr_box_int(tc, MVM_hll_current(tc)->int_box_type, tmp.i64);
70
0
            }
71
0
            else {
72
0
                MVM_exception_throw_adhoc(tc, "Wrong register kind in iteration");
73
0
            }
74
0
            return;
75
0
        case MVM_ITER_MODE_ARRAY_NUM:
76
0
            body->array_state.index++;
77
0
            if (body->array_state.index >= body->array_state.limit)
78
0
                MVM_exception_throw_adhoc(tc, "Iteration past end of iterator");
79
0
            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
0
            else if (kind == MVM_reg_obj) {
83
0
                MVMRegister tmp;
84
0
                REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, &tmp, MVM_reg_num64);
85
0
                value->o = MVM_repr_box_num(tc, MVM_hll_current(tc)->num_box_type, tmp.n64);
86
0
            }
87
0
            else {
88
0
                MVM_exception_throw_adhoc(tc, "Wrong register kind in iteration");
89
0
            }
90
0
            return;
91
0
        case MVM_ITER_MODE_ARRAY_STR:
92
0
            body->array_state.index++;
93
0
            if (body->array_state.index >= body->array_state.limit)
94
0
                MVM_exception_throw_adhoc(tc, "Iteration past end of iterator");
95
0
            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
0
            else if (kind == MVM_reg_obj) {
99
0
                MVMRegister tmp;
100
0
                REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, &tmp, MVM_reg_str);
101
0
                value->o = MVM_repr_box_str(tc, MVM_hll_current(tc)->str_box_type, tmp.s);
102
0
            }
103
0
            else {
104
0
                MVM_exception_throw_adhoc(tc, "Wrong register kind in iteration");
105
0
            }
106
0
            return;
107
709k
        case MVM_ITER_MODE_HASH:
108
709k
            body->hash_state.curr = body->hash_state.next;
109
709k
            if (!body->hash_state.curr)
110
0
                MVM_exception_throw_adhoc(tc, "Iteration past end of iterator");
111
709k
            body->hash_state.next = HASH_ITER_NEXT_ITEM(
112
709k
                &(body->hash_state.next->hash_handle),
113
709k
                &(body->hash_state.bucket_state));
114
709k
            value->o = root;
115
709k
            return;
116
0
        default:
117
0
            MVM_exception_throw_adhoc(tc, "Unknown iteration mode");
118
1.09M
    }
119
1.09M
}
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
260
static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) {
144
260
    st->size = sizeof(MVMIter);
145
260
}
146
147
/* Initializes the representation. */
148
130
const MVMREPROps * MVMIter_initialize(MVMThreadContext *tc) {
149
130
    return &MVMIter_this_repr;
150
130
}
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
        isplice,
168
        MVM_REPR_DEFAULT_AT_POS_MULTIDIM,
169
        MVM_REPR_DEFAULT_BIND_POS_MULTIDIM,
170
        MVM_REPR_DEFAULT_DIMENSIONS,
171
        MVM_REPR_DEFAULT_SET_DIMENSIONS,
172
        get_elem_storage_spec
173
    },    /* pos_funcs */
174
    MVM_REPR_DEFAULT_ASS_FUNCS,
175
    MVM_REPR_DEFAULT_ELEMS,
176
    get_storage_spec,
177
    NULL, /* change_type */
178
    NULL, /* serialize */
179
    NULL, /* deserialize */
180
    NULL, /* serialize_repr_data */
181
    NULL, /* deserialize_repr_data */
182
    deserialize_stable_size,
183
    gc_mark,
184
    gc_free,
185
    NULL, /* gc_cleanup */
186
    NULL, /* gc_mark_repr_data */
187
    NULL, /* gc_free_repr_data */
188
    compose,
189
    NULL, /* spesh */
190
    "VMIter", /* name */
191
    MVM_REPR_ID_MVMIter,
192
    NULL, /* unmanaged_size */
193
    NULL, /* describe_refs */
194
};
195
196
546k
MVMObject * MVM_iter(MVMThreadContext *tc, MVMObject *target) {
197
546k
    MVMIter *iterator;
198
546k
    MVMROOT(tc, target, {
199
546k
        if (REPR(target)->ID == MVM_REPR_ID_VMArray) {
200
546k
            iterator = (MVMIter *)MVM_repr_alloc_init(tc,
201
546k
                MVM_hll_current(tc)->array_iterator_type);
202
546k
            iterator->body.array_state.index = -1;
203
546k
            iterator->body.array_state.limit = REPR(target)->elems(tc, STABLE(target), target, OBJECT_BODY(target));
204
546k
            MVM_ASSIGN_REF(tc, &(iterator->common.header), iterator->body.target, target);
205
546k
            switch (REPR(target)->pos_funcs.get_elem_storage_spec(tc, STABLE(target)).boxed_primitive) {
206
546k
                case MVM_STORAGE_SPEC_BP_INT: iterator->body.mode = MVM_ITER_MODE_ARRAY_INT; break;
207
546k
                case MVM_STORAGE_SPEC_BP_NUM: iterator->body.mode = MVM_ITER_MODE_ARRAY_NUM; break;
208
546k
                case MVM_STORAGE_SPEC_BP_STR: iterator->body.mode = MVM_ITER_MODE_ARRAY_STR; break;
209
546k
                default:                      iterator->body.mode = MVM_ITER_MODE_ARRAY; break;
210
546k
            }
211
546k
        }
212
546k
        else if (REPR(target)->ID == MVM_REPR_ID_MVMHash) {
213
546k
            iterator = (MVMIter *)MVM_repr_alloc_init(tc,
214
546k
                MVM_hll_current(tc)->hash_iterator_type);
215
546k
            iterator->body.mode = MVM_ITER_MODE_HASH;
216
546k
            iterator->body.hash_state.bucket_state = 0;
217
546k
            iterator->body.hash_state.curr         = NULL;
218
546k
            iterator->body.hash_state.next         = HASH_ITER_FIRST_ITEM(
219
546k
                ((MVMHash *)target)->body.hash_head
220
546k
                    ? ((MVMHash *)target)->body.hash_head->hash_handle.tbl
221
546k
                    : NULL,
222
546k
                &(iterator->body.hash_state.bucket_state));
223
546k
            MVM_ASSIGN_REF(tc, &(iterator->common.header), iterator->body.target, target);
224
546k
        }
225
546k
        else if (REPR(target)->ID == MVM_REPR_ID_MVMContext) {
226
546k
            /* Turn the context into a VMHash and then iterate that. */
227
546k
            MVMHLLConfig *hll = MVM_hll_current(tc);
228
546k
            MVMObject *ctx_hash = MVM_repr_alloc_init(tc, hll->slurpy_hash_type);
229
546k
            MVMROOT(tc, ctx_hash, {
230
546k
                MVMContext          *ctx    = (MVMContext *)target;
231
546k
                MVMFrame            *frame  = ctx->body.context;
232
546k
                MVMStaticFrame      *sf     = frame->static_info;
233
546k
                MVMLexicalRegistry **lexreg = sf->body.lexical_names_list;
234
546k
                MVMuint32 i;
235
546k
                MVMROOT(tc, frame, {
236
546k
                MVMROOT(tc, sf, {
237
546k
                    for (i = 0; i < sf->body.num_lexicals; i++) {
238
546k
                        MVMuint32 idx  = lexreg[i]->value;
239
546k
                        MVMuint16 type = sf->body.lexical_types[idx];
240
546k
                        switch (type) {
241
546k
                            case MVM_reg_obj: {
242
546k
                                MVMObject *obj = frame->env[idx].o;
243
546k
                                if (!obj)
244
546k
                                    obj = MVM_frame_vivify_lexical(tc, frame, idx);
245
546k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, obj);
246
546k
                                break;
247
546k
                            }
248
546k
                            case MVM_reg_str: {
249
546k
                                MVMObject *bs = MVM_repr_box_str(tc, hll->str_box_type,
250
546k
                                    frame->env[idx].s);
251
546k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bs);
252
546k
                                break;
253
546k
                            }
254
546k
                            case MVM_reg_int8: {
255
546k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
256
546k
                                    frame->env[idx].i8);
257
546k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
258
546k
                                break;
259
546k
                            }
260
546k
                            case MVM_reg_int16: {
261
546k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
262
546k
                                    frame->env[idx].i16);
263
546k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
264
546k
                                break;
265
546k
                            }
266
546k
                            case MVM_reg_int32: {
267
546k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
268
546k
                                    frame->env[idx].i32);
269
546k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
270
546k
                                break;
271
546k
                            }
272
546k
                            case MVM_reg_int64: {
273
546k
                                MVMObject *bi = MVM_repr_box_int(tc, hll->int_box_type,
274
546k
                                    frame->env[idx].i64);
275
546k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bi);
276
546k
                                break;
277
546k
                            }
278
546k
                            case MVM_reg_num32: {
279
546k
                                MVMObject *bn = MVM_repr_box_num(tc, hll->num_box_type,
280
546k
                                    frame->env[idx].n32);
281
546k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bn);
282
546k
                                break;
283
546k
                            }
284
546k
                            case MVM_reg_num64: {
285
546k
                                MVMObject *bn = MVM_repr_box_num(tc, hll->num_box_type,
286
546k
                                    frame->env[idx].n64);
287
546k
                                MVM_repr_bind_key_o(tc, ctx_hash, lexreg[i]->key, bn);
288
546k
                                break;
289
546k
                            }
290
546k
                            default:
291
546k
                                MVM_exception_throw_adhoc(tc,
292
546k
                                    "Unknown lexical type encountered while building context iterator");
293
546k
                        }
294
546k
                    }
295
546k
                });
296
546k
                });
297
546k
            });
298
546k
299
546k
            /* Call ourselves recursively to get the iterator for this
300
546k
            * hash. */
301
546k
            iterator = (MVMIter *)MVM_iter(tc, ctx_hash);
302
546k
        }
303
546k
        else {
304
546k
            MVM_exception_throw_adhoc(tc, "Cannot iterate object with %s representation (%s)",
305
546k
                REPR(target)->name, STABLE(target)->debug_name);
306
546k
        }
307
546k
    });
308
546k
    return (MVMObject *)iterator;
309
546k
}
310
311
1.62M
MVMint64 MVM_iter_istrue(MVMThreadContext *tc, MVMIter *iter) {
312
1.62M
    switch (iter->body.mode) {
313
605k
        case MVM_ITER_MODE_ARRAY:
314
605k
        case MVM_ITER_MODE_ARRAY_INT:
315
605k
        case MVM_ITER_MODE_ARRAY_NUM:
316
605k
        case MVM_ITER_MODE_ARRAY_STR:
317
384k
            return iter->body.array_state.index + 1 < iter->body.array_state.limit ? 1 : 0;
318
0
            break;
319
1.02M
        case MVM_ITER_MODE_HASH:
320
709k
            return iter->body.hash_state.next != NULL ? 1 : 0;
321
0
            break;
322
0
        default:
323
0
            MVM_exception_throw_adhoc(tc, "Invalid iteration mode used");
324
1.62M
    }
325
1.62M
}
326
327
710k
MVMString * MVM_iterkey_s(MVMThreadContext *tc, MVMIter *iterator) {
328
710k
    if (REPR(iterator)->ID != MVM_REPR_ID_MVMIter
329
710k
            || iterator->body.mode != MVM_ITER_MODE_HASH)
330
0
        MVM_exception_throw_adhoc(tc, "This is not a hash iterator, it's a %s (%s)", REPR(iterator)->name, STABLE(iterator)->debug_name);
331
710k
    if (!iterator->body.hash_state.curr)
332
0
        MVM_exception_throw_adhoc(tc, "You have not advanced to the first item of the hash iterator, or have gone past the end");
333
710k
    return MVM_HASH_KEY(iterator->body.hash_state.curr);
334
710k
}
335
336
699k
MVMObject * MVM_iterval(MVMThreadContext *tc, MVMIter *iterator) {
337
699k
    MVMIterBody *body;
338
699k
    MVMObject *target;
339
699k
    MVMRegister result;
340
699k
    if (REPR(iterator)->ID != MVM_REPR_ID_MVMIter)
341
0
        MVM_exception_throw_adhoc(tc, "This is not an iterator, it's a %s (%s)", REPR(iterator)->name, STABLE(iterator)->debug_name);
342
699k
    if (iterator->body.mode == MVM_ITER_MODE_ARRAY) {
343
0
        body = &iterator->body;
344
0
        if (body->array_state.index == -1)
345
0
            MVM_exception_throw_adhoc(tc, "You have not yet advanced in the array iterator");
346
0
        target = body->target;
347
0
        REPR(target)->pos_funcs.at_pos(tc, STABLE(target), target, OBJECT_BODY(target), body->array_state.index, &result, MVM_reg_obj);
348
0
    }
349
699k
    else if (iterator->body.mode == MVM_ITER_MODE_HASH) {
350
699k
        if (!iterator->body.hash_state.curr)
351
0
            MVM_exception_throw_adhoc(tc, "You have not advanced to the first item of the hash iterator, or have gone past the end");
352
699k
        result.o = iterator->body.hash_state.curr->value;
353
699k
        if (!result.o)
354
0
            result.o = tc->instance->VMNull;
355
699k
    }
356
0
    else {
357
0
        MVM_exception_throw_adhoc(tc, "Unknown iterator mode in iterval");
358
0
    }
359
699k
    return result.o;
360
699k
}