/home/travis/build/MoarVM/MoarVM/src/spesh/osr.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | /* Writes to stderr about each OSR that we perform. */ |
4 | | #define MVM_LOG_OSR 0 |
5 | | |
6 | | /* Locates deopt index matching OSR point. */ |
7 | 17.7k | static MVMint32 get_osr_deopt_index(MVMThreadContext *tc, MVMSpeshCandidate *cand) { |
8 | 17.7k | /* Calculate offset. */ |
9 | 17.7k | MVMint32 offset = (*(tc->interp_cur_op) - *(tc->interp_bytecode_start)); |
10 | 17.7k | |
11 | 17.7k | /* Locate it in the deopt table. */ |
12 | 17.7k | MVMint32 i; |
13 | 174k | for (i = 0; i < cand->num_deopts; i++) |
14 | 174k | if (cand->deopts[2 * i] == offset) |
15 | 17.7k | return i; |
16 | 17.7k | |
17 | 17.7k | /* If we couldn't locate it, something is really very wrong. */ |
18 | 0 | MVM_oops(tc, "Spesh: get_osr_deopt_index failed"); |
19 | 0 | } |
20 | | |
21 | | /* Does the jump into the optimized code. */ |
22 | 17.7k | void perform_osr(MVMThreadContext *tc, MVMSpeshCandidate *specialized) { |
23 | 17.7k | MVMJitCode *jit_code; |
24 | 17.7k | MVMint32 num_locals; |
25 | 17.7k | /* Work out the OSR deopt index, to locate the entry point. */ |
26 | 17.7k | MVMint32 osr_index = get_osr_deopt_index(tc, specialized); |
27 | 17.7k | #if MVM_LOG_OSR |
28 | | fprintf(stderr, "Performing OSR of frame '%s' (cuid: %s) at index %d\n", |
29 | | MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), |
30 | | MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid), |
31 | | osr_index); |
32 | | #endif |
33 | 17.7k | |
34 | 17.7k | jit_code = specialized->jitcode; |
35 | 17.7k | num_locals = jit_code && jit_code->local_types ? |
36 | 17.7k | jit_code->num_locals : specialized->num_locals; |
37 | 17.7k | |
38 | 17.7k | /* Resize work area if needed. */ |
39 | 17.7k | if (specialized->work_size > tc->cur_frame->allocd_work) { |
40 | 16.9k | /* Resize work area. */ |
41 | 16.9k | MVMRegister *new_work = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, |
42 | 16.9k | specialized->work_size); |
43 | 16.9k | MVMRegister *new_args = new_work + num_locals; |
44 | 16.9k | memcpy(new_work, tc->cur_frame->work, |
45 | 16.9k | tc->cur_frame->static_info->body.num_locals * sizeof(MVMRegister)); |
46 | 16.9k | memcpy(new_args, tc->cur_frame->args, |
47 | 16.9k | tc->cur_frame->static_info->body.cu->body.max_callsite_size * sizeof(MVMRegister)); |
48 | 16.9k | |
49 | 16.9k | MVM_fixed_size_free(tc, tc->instance->fsa, tc->cur_frame->allocd_work, |
50 | 16.9k | tc->cur_frame->work); |
51 | 16.9k | tc->cur_frame->work = new_work; |
52 | 16.9k | tc->cur_frame->allocd_work = specialized->work_size; |
53 | 16.9k | tc->cur_frame->args = new_args; |
54 | 16.9k | #if MVM_LOG_OSR |
55 | | fprintf(stderr, "OSR resized work area of frame '%s' (cuid: %s)\n", |
56 | | MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), |
57 | | MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid)); |
58 | | #endif |
59 | 16.9k | } |
60 | 811 | else if (specialized->work_size > tc->cur_frame->static_info->body.work_size) { |
61 | 809 | size_t keep_bytes = tc->cur_frame->static_info->body.num_locals * sizeof(MVMRegister); |
62 | 809 | size_t to_null = specialized->work_size - keep_bytes; |
63 | 809 | memset((char *)tc->cur_frame->work + keep_bytes, 0, to_null); |
64 | 809 | } |
65 | 17.7k | |
66 | 17.7k | /* Resize environment if needed. */ |
67 | 17.7k | if (specialized->num_lexicals > tc->cur_frame->static_info->body.num_lexicals) { |
68 | 18 | MVMRegister *new_env = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, |
69 | 18 | specialized->env_size); |
70 | 18 | if (tc->cur_frame->allocd_env) { |
71 | 16 | memcpy(new_env, tc->cur_frame->env, |
72 | 16 | tc->cur_frame->static_info->body.num_lexicals * sizeof(MVMRegister)); |
73 | 16 | MVM_fixed_size_free(tc, tc->instance->fsa, tc->cur_frame->allocd_env, |
74 | 16 | tc->cur_frame->env); |
75 | 16 | } |
76 | 18 | tc->cur_frame->env = new_env; |
77 | 18 | tc->cur_frame->allocd_env = specialized->env_size; |
78 | 18 | #if MVM_LOG_OSR |
79 | | fprintf(stderr, "OSR resized environment of frame '%s' (cuid: %s)\n", |
80 | | MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), |
81 | | MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid)); |
82 | | #endif |
83 | 18 | } |
84 | 17.7k | else if (specialized->env_size > tc->cur_frame->static_info->body.env_size) { |
85 | 0 | size_t keep_bytes = tc->cur_frame->static_info->body.num_lexicals * sizeof(MVMRegister); |
86 | 0 | size_t to_null = specialized->env_size - keep_bytes; |
87 | 0 | memset((char *)tc->cur_frame->env + keep_bytes, 0, to_null); |
88 | 0 | } |
89 | 17.7k | |
90 | 17.7k | /* Set up frame to point to spesh candidate/slots. */ |
91 | 17.7k | tc->cur_frame->effective_spesh_slots = specialized->spesh_slots; |
92 | 17.7k | tc->cur_frame->spesh_cand = specialized; |
93 | 17.7k | |
94 | 17.7k | /* Move into the optimized (and maybe JIT-compiled) code. */ |
95 | 17.7k | |
96 | 17.7k | if (jit_code && jit_code->num_deopts) { |
97 | 17.7k | MVMint32 i; |
98 | 17.7k | *(tc->interp_bytecode_start) = jit_code->bytecode; |
99 | 17.7k | *(tc->interp_cur_op) = jit_code->bytecode; |
100 | 40.9k | for (i = 0; i < jit_code->num_deopts; i++) { |
101 | 40.9k | if (jit_code->deopts[i].idx == osr_index) { |
102 | 17.7k | tc->cur_frame->jit_entry_label = jit_code->labels[jit_code->deopts[i].label]; |
103 | 17.7k | break; |
104 | 17.7k | } |
105 | 40.9k | } |
106 | 17.7k | |
107 | 17.7k | if (i == jit_code->num_deopts) |
108 | 0 | MVM_oops(tc, "JIT: Could not find OSR label"); |
109 | 17.7k | if (tc->instance->profiling) |
110 | 0 | MVM_profiler_log_osr(tc, 1); |
111 | 3 | } else { |
112 | 3 | *(tc->interp_bytecode_start) = specialized->bytecode; |
113 | 3 | *(tc->interp_cur_op) = specialized->bytecode + |
114 | 3 | specialized->deopts[2 * osr_index + 1]; |
115 | 3 | if (tc->instance->profiling) |
116 | 0 | MVM_profiler_log_osr(tc, 0); |
117 | 3 | } |
118 | 17.7k | *(tc->interp_reg_base) = tc->cur_frame->work; |
119 | 17.7k | } |
120 | | |
121 | | /* Polls for an optimization and, when one is produced, jumps into it. */ |
122 | 1.09M | void MVM_spesh_osr_poll_for_result(MVMThreadContext *tc) { |
123 | 1.09M | MVMStaticFrameSpesh *spesh = tc->cur_frame->static_info->body.spesh; |
124 | 1.09M | MVMint32 num_cands = spesh->body.num_spesh_candidates; |
125 | 1.09M | MVMint32 seq_nr = tc->cur_frame->sequence_nr; |
126 | 1.09M | if (seq_nr != tc->osr_hunt_frame_nr || num_cands != tc->osr_hunt_num_spesh_candidates) { |
127 | 416k | /* Provided OSR is enabled... */ |
128 | 416k | if (tc->instance->spesh_osr_enabled) { |
129 | 416k | /* Check if there's a candidate available and install it if so. */ |
130 | 416k | MVMFrame *caller = tc->cur_frame->caller; |
131 | 416k | MVMCallsite *cs = caller |
132 | 416k | ? caller->cur_args_callsite |
133 | 3 | : MVM_callsite_get_common(tc, MVM_CALLSITE_ID_NULL_ARGS); |
134 | 416k | MVMint32 ag_result = MVM_spesh_arg_guard_run(tc, |
135 | 416k | spesh->body.spesh_arg_guard, |
136 | 416k | (cs && cs->is_interned ? cs : NULL), |
137 | 416k | (caller ? caller->args : NULL), |
138 | 416k | NULL); |
139 | 416k | if (ag_result >= 0) |
140 | 17.7k | perform_osr(tc, spesh->body.spesh_candidates[ag_result]); |
141 | 416k | } |
142 | 416k | |
143 | 416k | /* Update state for avoiding checks in the common case. */ |
144 | 416k | tc->osr_hunt_frame_nr = seq_nr; |
145 | 416k | tc->osr_hunt_num_spesh_candidates = num_cands; |
146 | 416k | } |
147 | 1.09M | } |