Coverage Report

Created: 2018-07-03 15:31

/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->extra || !install_on->extra->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
        MVM_frame_special_return(tc, install_on, finalize_handler_caller, NULL,
58
0
            NULL, NULL);
59
0
}
60
61
/* Walks through the per-thread finalize queues, identifying objects that
62
 * should be finalized, pushing them onto a finalize list, and then marking
63
 * that list entry. Assumes the world is stopped. */
64
0
static void add_to_finalizing(MVMThreadContext *tc, MVMObject *obj) {
65
0
    if (tc->num_finalizing == tc->alloc_finalizing) {
66
0
        if (tc->alloc_finalizing)
67
0
            tc->alloc_finalizing *= 2;
68
0
        else
69
0
            tc->alloc_finalizing = 64;
70
0
        tc->finalizing = MVM_realloc(tc->finalizing,
71
0
            sizeof(MVMCollectable **) * tc->alloc_finalizing);
72
0
    }
73
0
    tc->finalizing[tc->num_finalizing] = obj;
74
0
    tc->num_finalizing++;
75
0
}
76
750
static void walk_thread_finalize_queue(MVMThreadContext *tc, MVMuint8 gen) {
77
750
    MVMuint32 collapse_pos = 0;
78
750
    MVMuint32 i;
79
750
    for (i = 0; i < tc->num_finalize; i++) {
80
0
        /* See if it's dead, taking which generation we've marked into
81
0
         * account. */
82
0
        MVMuint32 flags   = tc->finalize[i]->header.flags;
83
0
        MVMuint32 in_gen2 = flags & MVM_CF_SECOND_GEN;
84
0
        if (gen == MVMGCGenerations_Both || !in_gen2) {
85
0
            MVMuint32 live = flags & (MVM_CF_GEN2_LIVE | MVM_CF_FORWARDER_VALID);
86
0
            if (live) {
87
0
                /* Alive, so just leave it in finalized queue, taking updated
88
0
                 * address if needed. */
89
0
                tc->finalize[collapse_pos++] = flags & MVM_CF_FORWARDER_VALID
90
0
                    ? (MVMObject *)tc->finalize[i]->header.sc_forward_u.forwarder
91
0
                    : tc->finalize[i];
92
0
            }
93
0
            else {
94
0
                /* Dead; needs finalizing, so pop it on the finalizing list. */
95
0
                add_to_finalizing(tc, tc->finalize[i]);
96
0
            }
97
0
        }
98
0
    }
99
750
    tc->num_finalize = collapse_pos;
100
750
}
101
338
void MVM_finalize_walk_queues(MVMThreadContext *tc, MVMuint8 gen) {
102
338
    MVMThread *cur_thread = (MVMThread *)MVM_load(&tc->instance->threads);
103
1.18k
    while (cur_thread) {
104
850
        if (cur_thread->body.tc) {
105
750
            walk_thread_finalize_queue(cur_thread->body.tc, gen);
106
750
            if (cur_thread->body.tc->num_finalizing > 0) {
107
0
                MVM_gc_collect(cur_thread->body.tc, MVMGCWhatToDo_Finalizing, gen);
108
0
                setup_finalize_handler_call(cur_thread->body.tc);
109
0
            }
110
750
        }
111
850
        cur_thread = cur_thread->body.next;
112
850
    }
113
338
}