Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/spesh/candidate.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Calculates the work and env sizes based on the number of locals and
4
 * lexicals. */
5
static void calculate_work_env_sizes(MVMThreadContext *tc, MVMStaticFrame *sf,
6
11.0k
                                     MVMSpeshCandidate *c) {
7
11.0k
    MVMuint32 max_callsite_size, jit_spill_size;
8
11.0k
    MVMint32 i;
9
11.0k
10
11.0k
    max_callsite_size = sf->body.cu->body.max_callsite_size;
11
10.6k
    jit_spill_size = (c->jitcode ? c->jitcode->spill_size: 0);
12
19.3k
    for (i = 0; i < c->num_inlines; i++) {
13
8.28k
        MVMuint32 cs = c->inlines[i].sf->body.cu->body.max_callsite_size;
14
8.28k
        if (cs > max_callsite_size)
15
1.19k
            max_callsite_size = cs;
16
8.28k
    }
17
11.0k
18
11.0k
    c->work_size = (c->num_locals + max_callsite_size + jit_spill_size) * sizeof(MVMRegister);
19
11.0k
    c->env_size = c->num_lexicals * sizeof(MVMRegister);
20
11.0k
}
21
22
/* Produces and installs a specialized version of the code, according to the
23
 * specified plan. */
24
11.1k
void MVM_spesh_candidate_add(MVMThreadContext *tc, MVMSpeshPlanned *p) {
25
11.1k
    MVMSpeshGraph *sg;
26
11.1k
    MVMSpeshCode *sc;
27
11.1k
    MVMSpeshCandidate *candidate;
28
11.1k
    MVMSpeshCandidate **new_candidate_list;
29
11.1k
    MVMStaticFrameSpesh *spesh;
30
11.1k
    MVMuint64 start_time;
31
11.1k
32
11.1k
    /* If we've reached our specialization limit, don't continue. */
33
11.1k
    if (tc->instance->spesh_limit)
34
0
        if (++tc->instance->spesh_produced > tc->instance->spesh_limit)
35
0
            return;
36
11.1k
37
11.1k
    /* Produce the specialization graph and, if we're logging, dump it out
38
11.1k
     * pre-transformation. */
39
11.1k
#if MVM_GC_DEBUG
40
    tc->in_spesh = 1;
41
#endif
42
11.1k
    if (MVM_spesh_debug_enabled(tc))
43
0
        start_time = uv_hrtime();
44
11.1k
    sg = MVM_spesh_graph_create(tc, p->sf, 0, 1);
45
11.1k
    if (MVM_spesh_debug_enabled(tc)) {
46
0
        char *c_name = MVM_string_utf8_encode_C_string(tc, p->sf->body.name);
47
0
        char *c_cuid = MVM_string_utf8_encode_C_string(tc, p->sf->body.cuuid);
48
0
        char *before = MVM_spesh_dump(tc, sg);
49
0
        MVM_spesh_debug_printf(tc,
50
0
            "Specialization of '%s' (cuid: %s)\n\n", c_name, c_cuid);
51
0
        MVM_spesh_debug_printf(tc, "Before:\n%s", before);
52
0
        MVM_free(c_name);
53
0
        MVM_free(c_cuid);
54
0
        MVM_free(before);
55
0
        fflush(tc->instance->spesh_log_fh);
56
0
    }
57
11.1k
58
11.1k
    /* Perform the optimization and, if we're logging, dump out the result. */
59
11.1k
    if (p->cs_stats->cs)
60
11.0k
        MVM_spesh_args(tc, sg, p->cs_stats->cs, p->type_tuple);
61
11.1k
    MVM_spesh_facts_discover(tc, sg, p);
62
11.1k
    MVM_spesh_optimize(tc, sg, p);
63
11.1k
64
11.1k
65
11.1k
    if (MVM_spesh_debug_enabled(tc)) {
66
0
        char *after = MVM_spesh_dump(tc, sg);
67
0
        MVM_spesh_debug_printf(tc, "After:\n%s", after);
68
0
        MVM_spesh_debug_printf(tc, "Specialization took %dus\n\n========\n\n",
69
0
            (int)((uv_hrtime() - start_time) / 1000));
70
0
        MVM_free(after);
71
0
        fflush(tc->instance->spesh_log_fh);
72
0
    }
73
11.1k
74
11.1k
    /* Generate code and install it into the candidate. */
75
11.1k
    sc = MVM_spesh_codegen(tc, sg);
76
11.1k
    candidate = MVM_calloc(1, sizeof(MVMSpeshCandidate));
77
11.1k
    candidate->bytecode      = sc->bytecode;
78
11.1k
    candidate->bytecode_size = sc->bytecode_size;
79
11.1k
    candidate->handlers      = sc->handlers;
80
11.1k
    candidate->num_handlers  = sg->num_handlers;
81
11.1k
    candidate->num_deopts    = sg->num_deopt_addrs;
82
11.1k
    candidate->deopts        = sg->deopt_addrs;
83
11.1k
    candidate->deopt_named_used_bit_field = sg->deopt_named_used_bit_field;
84
11.1k
    candidate->num_locals    = sg->num_locals;
85
11.1k
    candidate->num_lexicals  = sg->num_lexicals;
86
11.1k
    candidate->num_inlines   = sg->num_inlines;
87
11.1k
    candidate->inlines       = sg->inlines;
88
11.1k
    candidate->local_types   = sg->local_types;
89
11.1k
    candidate->lexical_types = sg->lexical_types;
90
11.1k
91
11.1k
    MVM_free(sc);
92
11.1k
93
11.1k
    /* Try to JIT compile the optimised graph. The JIT graph hangs from
94
11.1k
     * the spesh graph and can safely be deleted with it. */
95
11.1k
    if (tc->instance->jit_enabled) {
96
11.1k
        MVMJitGraph *jg;
97
11.1k
        if (tc->instance->spesh_log_fh)
98
0
            start_time = uv_hrtime();
99
11.1k
        jg = MVM_jit_try_make_graph(tc, sg);
100
11.1k
        if (jg != NULL) {
101
10.7k
            candidate->jitcode = MVM_jit_compile_graph(tc, jg);
102
10.7k
            MVM_jit_graph_destroy(tc, jg);
103
10.7k
        }
104
11.1k
        if (MVM_spesh_debug_enabled(tc)) {
105
0
            MVM_spesh_debug_printf(tc, "JIT was %s and compilation took %" PRIu64 "us\n",
106
0
                                   candidate->jitcode ? "successful" : "not successful",
107
0
                                   (uv_hrtime() - start_time) / 1000);
108
0
        }
109
11.1k
    }
110
11.1k
111
11.1k
    /* calculate work environment taking JIT spill area into account */
112
11.1k
    calculate_work_env_sizes(tc, sg->sf, candidate);
113
11.1k
114
11.1k
    /* Update spesh slots. */
115
11.1k
    candidate->num_spesh_slots = sg->num_spesh_slots;
116
11.1k
    candidate->spesh_slots     = sg->spesh_slots;
117
11.1k
118
11.1k
    /* Clean up after specialization work. */
119
11.1k
    if (candidate->num_inlines) {
120
3.22k
        MVMint32 i;
121
11.5k
        for (i = 0; i < candidate->num_inlines; i++)
122
8.28k
            if (candidate->inlines[i].g) {
123
7.33k
                MVM_spesh_graph_destroy(tc, candidate->inlines[i].g);
124
7.33k
                candidate->inlines[i].g = NULL;
125
7.33k
            }
126
3.22k
    }
127
11.1k
    MVM_spesh_graph_destroy(tc, sg);
128
11.1k
129
11.1k
    /* Create a new candidate list and copy any existing ones. Free memory
130
11.1k
     * using the FSA safepoint mechanism. */
131
11.1k
    spesh = p->sf->body.spesh;
132
11.1k
    new_candidate_list = MVM_fixed_size_alloc(tc, tc->instance->fsa,
133
11.1k
        (spesh->body.num_spesh_candidates + 1) * sizeof(MVMSpeshCandidate *));
134
11.1k
    if (spesh->body.num_spesh_candidates) {
135
2.29k
        size_t orig_size = spesh->body.num_spesh_candidates * sizeof(MVMSpeshCandidate *);
136
2.29k
        memcpy(new_candidate_list, spesh->body.spesh_candidates, orig_size);
137
2.29k
        MVM_fixed_size_free_at_safepoint(tc, tc->instance->fsa, orig_size,
138
2.29k
            spesh->body.spesh_candidates);
139
2.29k
    }
140
11.1k
    new_candidate_list[spesh->body.num_spesh_candidates] = candidate;
141
11.1k
    spesh->body.spesh_candidates = new_candidate_list;
142
11.1k
143
11.1k
    /* May now be referencing nursery objects, so barrier just in case. */
144
11.1k
    if (spesh->common.header.flags & MVM_CF_SECOND_GEN)
145
11.0k
        MVM_gc_write_barrier_hit(tc, (MVMCollectable *)spesh);
146
11.1k
147
11.1k
    /* Update the guards, and bump the candidate count. This means there is a
148
11.1k
     * period when we can read, in another thread, a candidate ahead of the
149
11.1k
     * count being updated. Since we set it up above, that's fine enough. The
150
11.1k
     * updating of the count *after* this, plus the barrier, is to make sure
151
11.1k
     * the guards are in place before the count is bumped, since OSR will
152
11.1k
     * watch the number of candidates to see if there's one for it to try and
153
11.1k
     * jump in to, and if the guards aren't in place first will see there is
154
11.1k
     * not, and not bother checking again. */
155
11.1k
    MVM_spesh_arg_guard_add(tc, &(spesh->body.spesh_arg_guard),
156
11.1k
        p->cs_stats->cs, p->type_tuple, spesh->body.num_spesh_candidates);
157
11.1k
    MVM_barrier();
158
11.1k
    spesh->body.num_spesh_candidates++;
159
11.1k
160
11.1k
    /* If we're logging, dump the upadated arg guards also. */
161
11.1k
    if (MVM_spesh_debug_enabled(tc)) {
162
0
        char *guard_dump = MVM_spesh_dump_arg_guard(tc, p->sf);
163
0
        MVM_spesh_debug_printf(tc, "%s========\n\n", guard_dump);
164
0
        fflush(tc->instance->spesh_log_fh);
165
0
        MVM_free(guard_dump);
166
0
    }
167
11.1k
168
11.1k
#if MVM_GC_DEBUG
169
    tc->in_spesh = 0;
170
#endif
171
11.1k
}
172
173
/* Frees the memory associated with a spesh candidate. */
174
0
void MVM_spesh_candidate_destroy(MVMThreadContext *tc, MVMSpeshCandidate *candidate) {
175
0
    MVM_free(candidate->bytecode);
176
0
    MVM_free(candidate->handlers);
177
0
    MVM_free(candidate->spesh_slots);
178
0
    MVM_free(candidate->deopts);
179
0
    MVM_free(candidate->inlines);
180
0
    MVM_free(candidate->local_types);
181
0
    MVM_free(candidate->lexical_types);
182
0
    if (candidate->jitcode)
183
0
        MVM_jit_code_destroy(tc, candidate->jitcode);
184
0
}