Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/gc/finalize.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Turns finalization on or off for a type. */
4
0
void MVM_gc_finalize_set(MVMThreadContext *tc, MVMObject *type, MVMint64 finalize) {
5
0
    MVMSTable *st        = STABLE(type);
6
0
    MVMint64   new_flags = st->mode_flags & (~MVM_FINALIZE_TYPE);
7
0
    if (finalize)
8
0
        new_flags |= MVM_FINALIZE_TYPE;
9
0
    st->mode_flags = new_flags;
10
0
    MVM_SC_WB_ST(tc, st);
11
0
}
12
13
/* Adds an object we've just allocated to the queue of those with finalizers
14
 * that will need calling upon collection. */
15
0
void MVM_gc_finalize_add_to_queue(MVMThreadContext *tc, MVMObject *obj) {
16
0
    MVM_ASSERT_NOT_FROMSPACE(tc, obj);
17
0
    if (tc->num_finalize == tc->alloc_finalize) {
18
0
        if (tc->alloc_finalize)
19
0
            tc->alloc_finalize *= 2;
20
0
        else
21
0
            tc->alloc_finalize = 64;
22
0
        tc->finalize = MVM_realloc(tc->finalize,
23
0
            sizeof(MVMCollectable **) * tc->alloc_finalize);
24
0
    }
25
0
    tc->finalize[tc->num_finalize] = obj;
26
0
    tc->num_finalize++;
27
0
}
28
29
/* Sets the passed thread context's thread up so that we'll run a finalize
30
 * handler on it in the near future. */
31
0
static void finalize_handler_caller(MVMThreadContext *tc, void *sr_data) {
32
0
    MVMObject *handler = MVM_hll_current(tc)->finalize_handler;
33
0
    if (handler) {
34
0
        MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG);
35
0
36
0
        /* Drain the finalizing queue to an array. */
37
0
        MVMObject *drain = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray);
38
0
        while (tc->num_finalizing > 0)
39
0
            MVM_repr_push_o(tc, drain, tc->finalizing[--tc->num_finalizing]);
40
0
41
0
        /* Invoke the handler. */
42
0
        handler = MVM_frame_find_invokee(tc, handler, NULL);
43
0
        MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, inv_arg_callsite);
44
0
        tc->cur_frame->args[0].o = drain;
45
0
        STABLE(handler)->invoke(tc, handler, inv_arg_callsite, tc->cur_frame->args);
46
0
    }
47
0
}
48
0
static void setup_finalize_handler_call(MVMThreadContext *tc) {
49
0
    MVMFrame *install_on = tc->cur_frame;
50
0
    while (install_on) {
51
0
        if (!install_on->special_return)
52
0
            if (install_on->static_info->body.cu->body.hll_config)
53
0
                break;
54
0
        install_on = install_on->caller;
55
0
    }
56
0
    if (install_on)
57
0
        install_on->special_return = finalize_handler_caller;
58
0
}
59
60
/* Walks through the per-thread finalize queues, identifying objects that
61
 * should be finalized, pushing them onto a finalize list, and then marking
62
 * that list entry. Assumes the world is stopped. */
63
0
static void add_to_finalizing(MVMThreadContext *tc, MVMObject *obj) {
64
0
    if (tc->num_finalizing == tc->alloc_finalizing) {
65
0
        if (tc->alloc_finalizing)
66
0
            tc->alloc_finalizing *= 2;
67
0
        else
68
0
            tc->alloc_finalizing = 64;
69
0
        tc->finalizing = MVM_realloc(tc->finalizing,
70
0
            sizeof(MVMCollectable **) * tc->alloc_finalizing);
71
0
    }
72
0
    tc->finalizing[tc->num_finalizing] = obj;
73
0
    tc->num_finalizing++;
74
0
}
75
146
static void walk_thread_finalize_queue(MVMThreadContext *tc, MVMuint8 gen) {
76
146
    MVMuint32 collapse_pos = 0;
77
146
    MVMuint32 i;
78
146
    for (i = 0; i < tc->num_finalize; i++) {
79
0
        /* See if it's dead, taking which generation we've marked into
80
0
         * account. */
81
0
        MVMuint32 flags   = tc->finalize[i]->header.flags;
82
0
        MVMuint32 in_gen2 = flags & MVM_CF_SECOND_GEN;
83
0
        if (gen == MVMGCGenerations_Both || !in_gen2) {
84
0
            MVMuint32 live = flags & (MVM_CF_GEN2_LIVE | MVM_CF_FORWARDER_VALID);
85
0
            if (live) {
86
0
                /* Alive, so just leave it in finalized queue, taking updated
87
0
                 * address if needed. */
88
0
                tc->finalize[collapse_pos++] = flags & MVM_CF_FORWARDER_VALID
89
0
                    ? (MVMObject *)tc->finalize[i]->header.sc_forward_u.forwarder
90
0
                    : tc->finalize[i];
91
0
            }
92
0
            else {
93
0
                /* Dead; needs finalizing, so pop it on the finalizing list. */
94
0
                add_to_finalizing(tc, tc->finalize[i]);
95
0
            }
96
0
        }
97
0
    }
98
146
    tc->num_finalize = collapse_pos;
99
146
}
100
146
void MVM_finalize_walk_queues(MVMThreadContext *tc, MVMuint8 gen) {
101
146
    MVMThread *cur_thread = (MVMThread *)MVM_load(&tc->instance->threads);
102
292
    while (cur_thread) {
103
146
        if (cur_thread->body.tc) {
104
146
            walk_thread_finalize_queue(cur_thread->body.tc, gen);
105
146
            if (cur_thread->body.tc->num_finalizing > 0) {
106
0
                MVM_gc_collect(cur_thread->body.tc, MVMGCWhatToDo_Finalizing, gen);
107
0
                setup_finalize_handler_call(cur_thread->body.tc);
108
0
            }
109
146
        }
110
146
        cur_thread = cur_thread->body.next;
111
146
    }
112
146
}