Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/6model/reprs/MVMStaticFrame.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 MVMStaticFrame_this_repr;
5
6
/* Invocation protocol handler. */
7
0
static void invoke_handler(MVMThreadContext *tc, MVMObject *invokee, MVMCallsite *callsite, MVMRegister *args) {
8
0
    MVM_exception_throw_adhoc(tc, "Cannot invoke static frame object");
9
0
}
10
11
/* Creates a new type object of this representation, and associates it with
12
 * the given HOW. Also sets the invocation protocol handler in the STable. */
13
130
static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
14
130
    MVMSTable *st = MVM_gc_allocate_stable(tc, &MVMStaticFrame_this_repr, HOW);
15
130
16
130
    MVMROOT(tc, st, {
17
130
        MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
18
130
        MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj);
19
130
        st->invoke = invoke_handler;
20
130
        st->size = sizeof(MVMStaticFrame);
21
130
    });
22
130
23
130
    return st->WHAT;
24
130
}
25
26
/* Copies the body of one object to another. */
27
1.50k
static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) {
28
1.50k
    MVMStaticFrameBody *src_body  = (MVMStaticFrameBody *)src;
29
1.50k
    MVMStaticFrameBody *dest_body = (MVMStaticFrameBody *)dest;
30
1.50k
31
1.50k
    if (!src_body->fully_deserialized)
32
0
        MVM_exception_throw_adhoc(tc, "Can only clone a fully deserialized MVMFrame");
33
1.50k
34
1.50k
    dest_body->orig_bytecode = src_body->orig_bytecode;
35
1.50k
    dest_body->bytecode_size = src_body->bytecode_size;
36
1.50k
    if (src_body->bytecode == src_body->orig_bytecode) {
37
1.50k
        /* Easy - the source MVMStaticFrameBody doesn't own the memory. */
38
1.50k
        dest_body->bytecode = src_body->bytecode;
39
1.50k
    }
40
0
    else {
41
0
        /* We're going to need to make a copy, in case the source object gets
42
0
           GC'd before we do, and so they free memory we point to. */
43
0
        /* If this gets to be a resource hog, then implement something more
44
0
           sophisticated. The easiest thing would be to bump the allocated size
45
0
           and value stored in bytecode by sizeof(MVMuint64), and use the extra
46
0
           space to store a reference count. */
47
0
        dest_body->bytecode = MVM_malloc(src_body->bytecode_size);
48
0
        memcpy(dest_body->bytecode, src_body->bytecode, src_body->bytecode_size);
49
0
    }
50
1.50k
51
1.50k
    MVM_ASSIGN_REF(tc, &(dest_root->header), dest_body->cu, src_body->cu);
52
1.50k
    MVM_ASSIGN_REF(tc, &(dest_root->header), dest_body->cuuid, src_body->cuuid);
53
1.50k
    MVM_ASSIGN_REF(tc, &(dest_root->header), dest_body->name, src_body->name);
54
1.50k
    MVM_ASSIGN_REF(tc, &(dest_root->header), dest_body->static_code, src_body->static_code);
55
1.50k
56
1.50k
    dest_body->num_locals = src_body->num_locals;
57
1.50k
    dest_body->num_lexicals = src_body->num_lexicals;
58
1.50k
    {
59
1.50k
        MVMuint16 *local_types = MVM_malloc(sizeof(MVMuint16) * src_body->num_locals);
60
1.50k
        MVMuint16 *lexical_types = MVM_malloc(sizeof(MVMuint16) * src_body->num_lexicals);
61
1.50k
        memcpy(local_types, src_body->local_types, sizeof(MVMuint16) * src_body->num_locals);
62
1.50k
        memcpy(lexical_types, src_body->lexical_types, sizeof(MVMuint16) * src_body->num_lexicals);
63
1.50k
        dest_body->local_types = local_types;
64
1.50k
        dest_body->lexical_types = lexical_types;
65
1.50k
    }
66
1.50k
    {
67
1.50k
        MVMLexicalRegistry *current, *tmp;
68
1.50k
        unsigned bucket_tmp;
69
1.50k
70
1.50k
        /* NOTE: if we really wanted to, we could avoid rehashing... */
71
1.50k
        HASH_ITER(hash_handle, src_body->lexical_names, current, tmp, bucket_tmp) {
72
0
            MVMLexicalRegistry *new_entry = MVM_malloc(sizeof(MVMLexicalRegistry));
73
0
            /* don't need to clone the string */
74
0
            MVM_ASSIGN_REF(tc, &(dest_root->header), new_entry->key, current->key);
75
0
            new_entry->value = current->value;
76
0
            MVM_HASH_BIND(tc, dest_body->lexical_names, current->key, new_entry);
77
0
        }
78
1.50k
    }
79
1.50k
80
1.50k
    /* Static environment needs to be copied, and any objects WB'd. */
81
1.50k
    if (src_body->env_size) {
82
0
        MVMuint16 *type_map = src_body->lexical_types;
83
0
        MVMuint16  count    = src_body->num_lexicals;
84
0
        MVMuint16  i;
85
0
86
0
        dest_body->static_env = MVM_malloc(src_body->env_size);
87
0
        memcpy(dest_body->static_env, src_body->static_env, src_body->env_size);
88
0
        dest_body->static_env_flags = MVM_malloc(src_body->num_lexicals);
89
0
        memcpy(dest_body->static_env_flags, src_body->static_env_flags, src_body->num_lexicals);
90
0
91
0
        for (i = 0; i < count; i++) {
92
0
            if (type_map[i] == MVM_reg_str) {
93
0
                MVM_gc_write_barrier(tc, (MVMCollectable *)dest_root, (MVMCollectable *)dest_body->static_env[i].s);
94
0
            }
95
0
            else if (type_map[i] == MVM_reg_obj) {
96
0
                MVM_gc_write_barrier(tc, (MVMCollectable *)dest_root, (MVMCollectable *)dest_body->static_env[i].o);
97
0
            }
98
0
        }
99
0
    }
100
1.50k
    dest_body->env_size = src_body->env_size;
101
1.50k
    dest_body->work_size = src_body->work_size;
102
1.50k
103
1.50k
    if (src_body->outer)
104
1.50k
        MVM_ASSIGN_REF(tc, &(dest_root->header), dest_body->outer, src_body->outer);
105
1.50k
106
1.50k
    dest_body->num_handlers = src_body->num_handlers;
107
1.50k
    dest_body->handlers     = MVM_malloc(src_body->num_handlers * sizeof(MVMFrameHandler));
108
1.50k
    memcpy(dest_body->handlers, src_body->handlers, src_body->num_handlers * sizeof(MVMFrameHandler));
109
1.50k
    dest_body->instrumentation_level = 0;
110
1.50k
    dest_body->pool_index            = src_body->pool_index;
111
1.50k
    dest_body->num_annotations       = src_body->num_annotations;
112
1.50k
    dest_body->annotations_data      = src_body->annotations_data;
113
1.50k
    dest_body->fully_deserialized    = 1;
114
1.50k
}
115
116
/* Adds held objects to the GC worklist. */
117
8.73k
static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) {
118
8.73k
    MVMStaticFrameBody *body = (MVMStaticFrameBody *)data;
119
8.73k
    MVMLexicalRegistry *current, *tmp;
120
8.73k
    unsigned bucket_tmp;
121
8.73k
122
8.73k
    /* mvmobjects */
123
8.73k
    MVM_gc_worklist_add(tc, worklist, &body->cu);
124
8.73k
    MVM_gc_worklist_add(tc, worklist, &body->cuuid);
125
8.73k
    MVM_gc_worklist_add(tc, worklist, &body->name);
126
8.73k
    MVM_gc_worklist_add(tc, worklist, &body->outer);
127
8.73k
    MVM_gc_worklist_add(tc, worklist, &body->static_code);
128
8.73k
129
8.73k
    /* If it's not fully deserialized, none of the following can apply. */
130
8.73k
    if (!body->fully_deserialized)
131
0
        return;
132
8.73k
133
8.73k
    /* lexical names hash keys */
134
8.73k
    HASH_ITER(hash_handle, body->lexical_names, current, tmp, bucket_tmp) {
135
983
        MVM_gc_worklist_add(tc, worklist, &current->hash_handle.key);
136
983
        MVM_gc_worklist_add(tc, worklist, &current->key);
137
983
    }
138
8.73k
139
8.73k
    /* static env */
140
8.73k
    if (body->static_env) {
141
5.18k
        MVMuint16 *type_map = body->lexical_types;
142
5.18k
        MVMuint16  count    = body->num_lexicals;
143
5.18k
        MVMuint16  i;
144
6.16k
        for (i = 0; i < count; i++)
145
983
            if (type_map[i] == MVM_reg_str || type_map[i] == MVM_reg_obj)
146
908
                MVM_gc_worklist_add(tc, worklist, &body->static_env[i].o);
147
5.18k
    }
148
8.73k
149
8.73k
    /* Spesh slots. */
150
8.73k
    if (body->num_spesh_candidates) {
151
5.17k
        MVMint32 i, j;
152
15.0k
        for (i = 0; i < body->num_spesh_candidates; i++) {
153
25.3k
            for (j = 0; j < body->spesh_candidates[i].num_guards; j++)
154
15.4k
                MVM_gc_worklist_add(tc, worklist, &body->spesh_candidates[i].guards[j].match);
155
84.5k
            for (j = 0; j < body->spesh_candidates[i].num_spesh_slots; j++)
156
74.7k
                MVM_gc_worklist_add(tc, worklist, &body->spesh_candidates[i].spesh_slots[j]);
157
9.82k
            if (body->spesh_candidates[i].log_slots)
158
67.9k
                for (j = 0; j < body->spesh_candidates[i].num_log_slots * MVM_SPESH_LOG_RUNS; j++)
159
66.3k
                    MVM_gc_worklist_add(tc, worklist, &body->spesh_candidates[i].log_slots[j]);
160
12.4k
            for (j = 0; j < body->spesh_candidates[i].num_inlines; j++)
161
2.67k
                MVM_gc_worklist_add(tc, worklist, &body->spesh_candidates[i].inlines[j].code);
162
9.82k
            if (body->spesh_candidates[i].sg)
163
1.97k
                MVM_spesh_graph_mark(tc, body->spesh_candidates[i].sg, worklist);
164
9.82k
        }
165
5.17k
    }
166
8.73k
}
167
168
/* Called by the VM in order to free memory associated with this object. */
169
0
static void gc_free(MVMThreadContext *tc, MVMObject *obj) {
170
0
    MVMStaticFrame *sf = (MVMStaticFrame *)obj;
171
0
    MVMStaticFrameBody *body = &sf->body;
172
0
    MVMint32 i;
173
0
    if (body->orig_bytecode != body->bytecode) {
174
0
        MVM_free(body->bytecode);
175
0
        body->bytecode = body->orig_bytecode;
176
0
    }
177
0
178
0
179
0
    /* If it's not fully deserialized, none of the following can apply. */
180
0
    if (!body->fully_deserialized)
181
0
        return;
182
0
    MVM_free(body->handlers);
183
0
    MVM_free(body->work_initial);
184
0
    MVM_free(body->static_env);
185
0
    MVM_free(body->static_env_flags);
186
0
    MVM_free(body->local_types);
187
0
    MVM_free(body->lexical_types);
188
0
    MVM_free(body->lexical_names_list);
189
0
    MVM_HASH_DESTROY(hash_handle, MVMLexicalRegistry, body->lexical_names);
190
0
191
0
    for (i = 0; i < body->num_spesh_candidates; i++)
192
0
        MVM_spesh_candidate_destroy(tc, &body->spesh_candidates[i]);
193
0
    MVM_free(body->spesh_candidates);
194
0
}
195
196
static const MVMStorageSpec storage_spec = {
197
    MVM_STORAGE_SPEC_REFERENCE, /* inlineable */
198
    0,                          /* bits */
199
    0,                          /* align */
200
    MVM_STORAGE_SPEC_BP_NONE,   /* boxed_primitive */
201
    0,                          /* can_box */
202
    0,                          /* is_unsigned */
203
};
204
205
206
/* Gets the storage specification for this representation. */
207
0
static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
208
0
    /* XXX in the end we'll support inlining of this... */
209
0
    return &storage_spec;
210
0
}
211
212
/* Compose the representation. */
213
0
static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info) {
214
0
    /* Nothing to do for this REPR. */
215
0
}
216
217
/* Calculates the non-GC-managed memory we hold on to. */
218
1.16k
static MVMuint64 unmanaged_size(MVMThreadContext *tc, MVMSTable *st, void *data) {
219
1.16k
    MVMStaticFrameBody *body = (MVMStaticFrameBody *)data;
220
1.16k
    MVMuint64 size = 0;
221
1.16k
222
1.16k
    if (body->fully_deserialized) {
223
1.16k
        MVMuint32 spesh_idx;
224
1.16k
225
1.16k
        size += sizeof(MVMuint16) * body->num_locals;
226
1.16k
        size += sizeof(MVMuint16) * body->num_lexicals;
227
1.16k
228
1.16k
        if (body->bytecode != body->orig_bytecode)
229
0
            size += body->bytecode_size;
230
1.16k
231
1.16k
        size += sizeof(MVMLexicalRegistry *) * body->num_lexicals;
232
1.16k
233
1.16k
        size += sizeof(MVMLexicalRegistry) * HASH_CNT(hash_handle, body->lexical_names);
234
1.16k
235
1.16k
        size += sizeof(MVMFrameHandler) * body->num_handlers;
236
1.16k
237
1.16k
        /* XXX i *think* the annotations are just a pointer into the serialized
238
1.16k
         * blob, so don't actually count it towards the unmanaged size. */
239
1.16k
        /*
240
1.16k
        size += sizeof(MVMuint8) * body->num_annotations
241
1.16k
        */
242
1.16k
        size += body->env_size; /* static_env */
243
1.16k
        size += body->num_lexicals; /* static_env_flags */
244
1.16k
245
1.16k
        for (spesh_idx = 0; spesh_idx < body->num_spesh_candidates; spesh_idx++) {
246
0
            MVMSpeshCandidate *cand = &body->spesh_candidates[spesh_idx];
247
0
            size += sizeof(MVMSpeshGuard) * cand->num_guards;
248
0
249
0
            size += cand->bytecode_size;
250
0
251
0
            size += sizeof(MVMFrameHandler) * cand->num_handlers;
252
0
253
0
            size += sizeof(MVMCollectable *) * cand->num_spesh_slots;
254
0
255
0
            size += sizeof(MVMint32) * cand->num_deopts;
256
0
257
0
            if (cand->sg)
258
0
                /* XXX we ought to descend into the speshgraph, too. */
259
0
                size += sizeof(MVMSpeshGraph);
260
0
261
0
            size += sizeof(MVMCollectable *) * cand->num_log_slots;
262
0
263
0
            size += sizeof(MVMSpeshInline) * cand->num_inlines;
264
0
265
0
            size += sizeof(MVMuint16) * (cand->num_locals + cand->num_lexicals);
266
0
267
0
            /* XXX probably don't need to measure the bytecode size here,
268
0
             * as it's probably just a pointer to the same bytecode we have in
269
0
             * the static frame anyway. */
270
0
271
0
            /* Dive into the jit code */
272
0
            if (cand->jitcode) {
273
0
                MVMJitCode *code = cand->jitcode;
274
0
275
0
                size += sizeof(MVMJitCode);
276
0
277
0
                size += sizeof(void *) * code->num_labels;
278
0
279
0
                size += sizeof(MVMint32) * code->num_bbs;
280
0
                size += sizeof(MVMJitDeopt) * code->num_deopts;
281
0
                size += sizeof(MVMJitInline) * code->num_inlines;
282
0
                size += sizeof(MVMJitHandler) * code->num_handlers;
283
0
            }
284
0
        }
285
1.16k
286
1.16k
        if (body->instrumentation) {
287
0
            size += body->instrumentation->uninstrumented_bytecode_size;
288
0
            size += body->instrumentation->instrumented_bytecode_size;
289
0
290
0
            /* XXX not 100% sure if num_handlers from the body is also the
291
0
             * number of handlers in instrumented version. should be, though. */
292
0
            size += sizeof(MVMFrameHandler) * body->num_handlers * 2;
293
0
        }
294
1.16k
    }
295
1.16k
296
1.16k
    return size;
297
1.16k
}
298
299
0
static void describe_refs(MVMThreadContext *tc, MVMHeapSnapshotState *ss, MVMSTable *st, void *data) {
300
0
    MVMStaticFrameBody *body = (MVMStaticFrameBody *)data;
301
0
    MVMLexicalRegistry *current, *tmp;
302
0
    unsigned bucket_tmp;
303
0
304
0
    MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
305
0
        (MVMCollectable *)body->cu, "Compilation Unit");
306
0
    MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
307
0
        (MVMCollectable *)body->cuuid, "Compilation Unit Unique ID");
308
0
    MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
309
0
        (MVMCollectable *)body->name, "Name");
310
0
    MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
311
0
        (MVMCollectable *)body->outer, "Outer static frame");
312
0
    MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
313
0
        (MVMCollectable *)body->static_code, "Static code object");
314
0
315
0
    /* If it's not fully deserialized, none of the following can apply. */
316
0
    if (!body->fully_deserialized)
317
0
        return;
318
0
319
0
    /* lexical names hash keys */
320
0
    HASH_ITER(hash_handle, body->lexical_names, current, tmp, bucket_tmp) {
321
0
        MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
322
0
            (MVMCollectable *)current->key, "Lexical name");
323
0
    }
324
0
325
0
    /* static env */
326
0
    if (body->static_env) {
327
0
        MVMuint16 *type_map = body->lexical_types;
328
0
        MVMuint16  count    = body->num_lexicals;
329
0
        MVMuint16  i;
330
0
        for (i = 0; i < count; i++)
331
0
            if (type_map[i] == MVM_reg_str || type_map[i] == MVM_reg_obj)
332
0
                MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
333
0
                    (MVMCollectable *)body->static_env[i].o, "Static Environment Entry");
334
0
    }
335
0
336
0
    /* Spesh slots. */
337
0
    if (body->num_spesh_candidates) {
338
0
        MVMint32 i, j;
339
0
        for (i = 0; i < body->num_spesh_candidates; i++) {
340
0
            for (j = 0; j < body->spesh_candidates[i].num_guards; j++)
341
0
                MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
342
0
                    (MVMCollectable *)body->spesh_candidates[i].guards[j].match,
343
0
                    "Spesh guard match");
344
0
            for (j = 0; j < body->spesh_candidates[i].num_spesh_slots; j++)
345
0
                MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
346
0
                    (MVMCollectable *)body->spesh_candidates[i].spesh_slots[j],
347
0
                    "Spesh slot entry");
348
0
            if (body->spesh_candidates[i].log_slots)
349
0
                for (j = 0; j < body->spesh_candidates[i].num_log_slots * MVM_SPESH_LOG_RUNS; j++)
350
0
                MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
351
0
                    (MVMCollectable *)body->spesh_candidates[i].log_slots[j],
352
0
                    "Spesh log slots");
353
0
            for (j = 0; j < body->spesh_candidates[i].num_inlines; j++)
354
0
                MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss,
355
0
                    (MVMCollectable *)body->spesh_candidates[i].inlines[j].code,
356
0
                    "Spesh inlined code object");
357
0
            if (body->spesh_candidates[i].sg) {
358
0
                MVMCollectable **c_ptr;
359
0
                MVM_spesh_graph_mark(tc, body->spesh_candidates[i].sg, ss->gcwl);
360
0
                while (( c_ptr = MVM_gc_worklist_get(tc, ss->gcwl) )) {
361
0
                    MVMCollectable *c = *c_ptr;
362
0
                    MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, c,
363
0
                        "Object held by spesh graph");
364
0
                }
365
0
            }
366
0
        }
367
0
    }
368
0
}
369
370
/* Initializes the representation. */
371
130
const MVMREPROps * MVMStaticFrame_initialize(MVMThreadContext *tc) {
372
130
    return &MVMStaticFrame_this_repr;
373
130
}
374
375
static const MVMREPROps MVMStaticFrame_this_repr = {
376
    type_object_for,
377
    MVM_gc_allocate_object,
378
    NULL, /* initialize */
379
    copy_to,
380
    MVM_REPR_DEFAULT_ATTR_FUNCS,
381
    MVM_REPR_DEFAULT_BOX_FUNCS,
382
    MVM_REPR_DEFAULT_POS_FUNCS,
383
    MVM_REPR_DEFAULT_ASS_FUNCS,
384
    MVM_REPR_DEFAULT_ELEMS,
385
    get_storage_spec,
386
    NULL, /* change_type */
387
    NULL, /* serialize */
388
    NULL, /* deserialize */
389
    NULL, /* serialize_repr_data */
390
    NULL, /* deserialize_repr_data */
391
    NULL, /* deserialize_stable_size */
392
    gc_mark,
393
    gc_free,
394
    NULL, /* gc_cleanup */
395
    NULL, /* gc_mark_repr_data */
396
    NULL, /* gc_free_repr_data */
397
    compose,
398
    NULL, /* spesh */
399
    "MVMStaticFrame", /* name */
400
    MVM_REPR_ID_MVMStaticFrame,
401
    unmanaged_size, /* unmanaged_size */
402
    describe_refs,
403
};