/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 | } |