Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/jit/graph.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
#include "math.h"
3
4
typedef struct {
5
    MVMSpeshGraph *sg;
6
    MVMSpeshBB    *cur_bb;
7
    MVMSpeshIns   *cur_ins;
8
9
    MVMJitNode    *first_node;
10
    MVMJitNode    *last_node;
11
12
    MVMint32      num_labels;
13
    void        **labeleds;
14
15
    MVMint32       num_bbs;
16
    MVMint32      *bb_labels;
17
18
    MVMint32       num_deopts;
19
    MVMint32       alloc_deopts;
20
    MVMJitDeopt   *deopts;
21
22
    MVMint32       num_handlers;
23
    MVMJitHandler *handlers;
24
25
    MVMint32       num_inlines;
26
    MVMJitInline  *inlines;
27
} JitGraphBuilder;
28
29
30
1.21M
static void jgb_append_node(JitGraphBuilder *jgb, MVMJitNode *node) {
31
1.21M
    if (jgb->last_node) {
32
1.20M
        jgb->last_node->next = node;
33
1.20M
        jgb->last_node = node;
34
13.8k
    } else {
35
13.8k
        jgb->first_node = node;
36
13.8k
        jgb->last_node = node;
37
13.8k
    }
38
1.21M
    node->next = NULL;
39
1.21M
}
40
41
static void jgb_append_primitive(MVMThreadContext *tc, JitGraphBuilder *jgb,
42
429k
                                 MVMSpeshIns * ins) {
43
429k
    MVMJitNode * node = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMJitNode));
44
429k
    node->type = MVM_JIT_NODE_PRIMITIVE;
45
429k
    node->u.prim.ins = ins;
46
429k
    jgb_append_node(jgb, node);
47
429k
}
48
49
static void jgb_append_call_c(MVMThreadContext *tc, JitGraphBuilder *jgb,
50
                              void * func_ptr, MVMint16 num_args,
51
                              MVMJitCallArg *call_args,
52
142k
                              MVMJitRVMode rv_mode, MVMint16 rv_idx) {
53
142k
    MVMJitNode * node = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMJitNode));
54
142k
    size_t args_size =  num_args * sizeof(MVMJitCallArg);
55
142k
    node->type             = MVM_JIT_NODE_CALL_C;
56
142k
    node->u.call.func_ptr  = func_ptr;
57
142k
    node->u.call.num_args  = num_args;
58
142k
    node->u.call.has_vargs = 0; /* don't support them yet */
59
142k
    /* Call argument array is typically stack allocated,
60
142k
     * so they need to be copied */
61
142k
    node->u.call.args      = MVM_spesh_alloc(tc, jgb->sg, args_size);
62
142k
    memcpy(node->u.call.args, call_args, args_size);
63
142k
    node->u.call.rv_mode   = rv_mode;
64
142k
    node->u.call.rv_idx    = rv_idx;
65
142k
    jgb_append_node(jgb, node);
66
142k
}
67
68
69
static MVMint32 get_label_for_obj(MVMThreadContext *tc, JitGraphBuilder *jgb,
70
366k
                                  void * obj) {
71
366k
    MVMint32 i;
72
13.8M
    for (i = 0; i < jgb->num_labels; i++) {
73
13.8M
        if (!jgb->labeleds[i])
74
205k
            break;
75
13.6M
        if (jgb->labeleds[i] == obj)
76
160k
            return i;
77
13.6M
    }
78
205k
    if (i == jgb->num_labels) {
79
0
        void **lblds = MVM_spesh_alloc(tc, jgb->sg, sizeof(void*) * jgb->num_labels * 2);
80
0
        memcpy(lblds, jgb->labeleds, jgb->num_labels * sizeof(void*));
81
0
        jgb->labeleds = lblds;
82
0
        jgb->num_labels *= 2;
83
0
    }
84
205k
    jgb->labeleds[i] = obj;
85
205k
    return i;
86
366k
}
87
88
static MVMint32 get_label_for_bb(MVMThreadContext *tc, JitGraphBuilder *jgb,
89
297k
                          MVMSpeshBB *bb) {
90
297k
    MVMint32 label = get_label_for_obj(tc, jgb, bb);
91
297k
    jgb->bb_labels[bb->idx] = label;
92
297k
    return label;
93
297k
}
94
95
/* This is the label that is appended at the very end */
96
static MVMint32 get_label_for_graph(MVMThreadContext *tc, JitGraphBuilder *jgb,
97
14.8k
                             MVMSpeshGraph *sg) {
98
14.8k
    return get_label_for_obj(tc, jgb, sg);
99
14.8k
}
100
101
/* The idea here is that labels are always - in principle - meant before a target. */
102
static MVMint32 get_label_for_ins(MVMThreadContext *tc, JitGraphBuilder *jgb,
103
56.7k
                           MVMSpeshBB *bb, MVMSpeshIns *ins, MVMint32 post) {
104
56.7k
    if (!post) {
105
15.3k
        /* Disregard PHI ops */
106
253k
        while (ins->prev && ins->prev->info->opcode == MVM_SSA_PHI)
107
237k
            ins = ins->prev;
108
15.3k
        if (ins == bb->first_ins) {
109
14.7k
            return get_label_for_obj(tc, jgb, bb);
110
14.7k
        }
111
594
        return get_label_for_obj(tc, jgb, ins);
112
15.3k
    }
113
41.4k
    else {
114
41.4k
        if (ins->next) {
115
154
            return get_label_for_obj(tc, jgb, ins->next);
116
154
        }
117
41.2k
        else if (bb->linear_next) {
118
38.7k
            return get_label_for_obj(tc, jgb, bb->linear_next);
119
38.7k
        }
120
2.47k
        else { /* end of graph label is identified by the graph itself */
121
2.47k
            return get_label_for_graph(tc, jgb, jgb->sg);
122
2.47k
        }
123
41.4k
    }
124
56.7k
}
125
126
127
23.3k
static void add_deopt_idx(MVMThreadContext *tc, JitGraphBuilder *jgb, MVMint32 label_name, MVMint32 deopt_idx) {
128
23.3k
    if (jgb->num_deopts == jgb->alloc_deopts) {
129
5.24k
        MVMJitDeopt *deopts = MVM_spesh_alloc(tc, jgb->sg, jgb->alloc_deopts * 2 * sizeof(MVMJitDeopt));
130
5.24k
        memcpy(deopts, jgb->deopts, jgb->num_deopts * sizeof(MVMJitDeopt));
131
5.24k
        jgb->deopts = deopts;
132
5.24k
        jgb->alloc_deopts *= 2;
133
5.24k
    }
134
23.3k
    jgb->deopts[jgb->num_deopts].label = label_name;
135
23.3k
    jgb->deopts[jgb->num_deopts].idx   = deopt_idx;
136
23.3k
    jgb->num_deopts++;
137
23.3k
}
138
139
140
static void jgb_append_branch(MVMThreadContext *tc, JitGraphBuilder *jgb,
141
115k
                              MVMint32 name, MVMSpeshIns *ins) {
142
115k
    MVMJitNode * node = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMJitNode));
143
115k
    node->type = MVM_JIT_NODE_BRANCH;
144
115k
    if (ins == NULL) {
145
12.7k
        node->u.branch.ins = NULL;
146
12.7k
        node->u.branch.dest = name;
147
12.7k
    }
148
102k
    else {
149
102k
        MVMSpeshBB *bb;
150
102k
        node->u.branch.ins = ins;
151
102k
        if (ins->info->opcode == MVM_OP_goto) {
152
43.9k
            bb = ins->operands[0].ins_bb;
153
43.9k
        }
154
58.2k
        else if (ins->info->opcode == MVM_OP_indexat ||
155
58.0k
                 ins->info->opcode == MVM_OP_indexnat) {
156
265
            bb = ins->operands[3].ins_bb;
157
265
        }
158
58.0k
        else {
159
58.0k
            bb = ins->operands[1].ins_bb;
160
58.0k
        }
161
102k
        node->u.branch.dest = get_label_for_bb(tc, jgb, bb);
162
102k
    }
163
115k
    jgb_append_node(jgb, node);
164
115k
}
165
166
256k
static void jgb_append_label(MVMThreadContext *tc, JitGraphBuilder *jgb, MVMint32 name) {
167
256k
    MVMJitNode *node;
168
256k
    if (jgb->last_node &&
169
242k
        jgb->last_node->type == MVM_JIT_NODE_LABEL &&
170
43.9k
        jgb->last_node->u.label.name == name)
171
43.9k
        return; /* don't double-add labels, even if it may be harmless */
172
212k
    node = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMJitNode));
173
212k
    node->type = MVM_JIT_NODE_LABEL;
174
212k
    node->u.label.name = name;
175
212k
    jgb_append_node(jgb, node);
176
212k
    MVM_jit_log(tc, "append label: %d\n", node->u.label.name);
177
212k
}
178
179
103k
static void * op_to_func(MVMThreadContext *tc, MVMint16 opcode) {
180
103k
    switch(opcode) {
181
327
    case MVM_OP_checkarity: return MVM_args_checkarity;
182
0
    case MVM_OP_say: return MVM_string_say;
183
0
    case MVM_OP_print: return MVM_string_print;
184
0
    case MVM_OP_isnull: return MVM_is_null;
185
0
    case MVM_OP_capturelex: return MVM_frame_capturelex;
186
682
    case MVM_OP_takeclosure: return MVM_frame_takeclosure;
187
0
    case MVM_OP_newlexotic: return MVM_exception_newlexotic_from_jit;
188
0
    case MVM_OP_usecapture: return MVM_args_use_capture;
189
0
    case MVM_OP_savecapture: return MVM_args_save_capture;
190
0
    case MVM_OP_captureposprimspec: return MVM_capture_pos_primspec;
191
4
    case MVM_OP_return: return MVM_args_assert_void_return_ok;
192
1.13k
    case MVM_OP_return_i: return MVM_args_set_result_int;
193
825
    case MVM_OP_return_s: return MVM_args_set_result_str;
194
10.7k
    case MVM_OP_return_o: return MVM_args_set_result_obj;
195
2
    case MVM_OP_return_n: return MVM_args_set_result_num;
196
47
    case MVM_OP_coerce_is: return MVM_coerce_i_s;
197
34
    case MVM_OP_coerce_ns: return MVM_coerce_n_s;
198
944
    case MVM_OP_coerce_si: return MVM_coerce_s_i;
199
0
    case MVM_OP_coerce_sn: return MVM_coerce_s_n;
200
0
    case MVM_OP_coerce_In: return MVM_bigint_to_num;
201
0
    case MVM_OP_coerce_nI: return MVM_bigint_from_num;
202
360
    case MVM_OP_iterkey_s: return MVM_iterkey_s;
203
921
    case MVM_OP_iter: return MVM_iter;
204
357
    case MVM_OP_iterval: return MVM_iterval;
205
1.80k
    case MVM_OP_die: return MVM_exception_die;
206
0
    case MVM_OP_throwdyn:
207
0
    case MVM_OP_throwlex:
208
0
    case MVM_OP_throwlexotic:
209
0
    case MVM_OP_rethrow: return MVM_exception_throwobj;
210
12
    case MVM_OP_throwcatdyn:
211
12
    case MVM_OP_throwcatlex:
212
12
    case MVM_OP_throwcatlexotic: return MVM_exception_throwcat;
213
0
    case MVM_OP_resume: return MVM_exception_resume;
214
0
    case MVM_OP_continuationreset: return MVM_continuation_reset;
215
0
    case MVM_OP_continuationcontrol: return MVM_continuation_control;
216
9.58k
    case MVM_OP_smrt_numify: return MVM_coerce_smart_numify;
217
3.46k
    case MVM_OP_smrt_strify: return MVM_coerce_smart_stringify;
218
9
    case MVM_OP_say_fhs: case MVM_OP_write_fhs: return MVM_io_write_string;
219
122
    case MVM_OP_gethow: return MVM_6model_get_how_obj;
220
7.51k
    case MVM_OP_box_i: return MVM_box_int;
221
1.63k
    case MVM_OP_box_s: return MVM_box_str;
222
264
    case MVM_OP_box_n: return MVM_box_num;
223
1.30k
    case MVM_OP_unbox_i: return MVM_repr_get_int;
224
2.09k
    case MVM_OP_unbox_s: return MVM_repr_get_str;
225
0
    case MVM_OP_unbox_n: return MVM_repr_get_num;
226
4.38k
    case MVM_OP_istrue: case MVM_OP_isfalse: return MVM_coerce_istrue;
227
1.12k
    case MVM_OP_istype: return MVM_6model_istype;
228
0
    case MVM_OP_isint: case MVM_OP_isnum: case MVM_OP_isstr: /* continued */
229
0
    case MVM_OP_islist: case MVM_OP_ishash: return MVM_repr_compare_repr_id;
230
23.1k
    case MVM_OP_wval: case MVM_OP_wval_wide: return MVM_sc_get_sc_object;
231
10
    case MVM_OP_scgetobjidx: return MVM_sc_find_object_idx_jit;
232
1.05k
    case MVM_OP_getdynlex: return MVM_frame_getdynlex;
233
18
    case MVM_OP_binddynlex: return MVM_frame_binddynlex;
234
0
    case MVM_OP_getlexouter: return MVM_frame_find_lexical_by_name_outer;
235
697
    case MVM_OP_findmeth: case MVM_OP_findmeth_s: return MVM_6model_find_method;
236
0
    case MVM_OP_multicacheadd: return MVM_multi_cache_add;
237
0
    case MVM_OP_multicachefind: return MVM_multi_cache_find;
238
496
    case MVM_OP_can: case MVM_OP_can_s: return MVM_6model_can_method;
239
148
    case MVM_OP_push_i: return MVM_repr_push_i;
240
0
    case MVM_OP_push_n: return MVM_repr_push_n;
241
9
    case MVM_OP_push_s: return MVM_repr_push_s;
242
1.80k
    case MVM_OP_push_o: return MVM_repr_push_o;
243
0
    case MVM_OP_unshift_i: return MVM_repr_unshift_i;
244
0
    case MVM_OP_unshift_n: return MVM_repr_unshift_n;
245
0
    case MVM_OP_unshift_s: return MVM_repr_unshift_s;
246
44
    case MVM_OP_unshift_o: return MVM_repr_unshift_o;
247
129
    case MVM_OP_pop_i: return MVM_repr_pop_i;
248
0
    case MVM_OP_pop_n: return MVM_repr_pop_n;
249
0
    case MVM_OP_pop_s: return MVM_repr_pop_s;
250
189
    case MVM_OP_pop_o: return MVM_repr_pop_o;
251
0
    case MVM_OP_shift_i: return MVM_repr_shift_i;
252
0
    case MVM_OP_shift_n: return MVM_repr_shift_n;
253
0
    case MVM_OP_shift_s: return MVM_repr_shift_s;
254
1.09k
    case MVM_OP_shift_o: return MVM_repr_shift_o;
255
417
    case MVM_OP_setelemspos: return MVM_repr_pos_set_elems;
256
131
    case MVM_OP_splice: return MVM_repr_pos_splice;
257
496
258
171
    case MVM_OP_existskey: return MVM_repr_exists_key;
259
168
    case MVM_OP_deletekey: return MVM_repr_delete_key;
260
496
261
140
    case MVM_OP_atpos_i: return MVM_repr_at_pos_i;
262
0
    case MVM_OP_atpos_n: return MVM_repr_at_pos_n;
263
0
    case MVM_OP_atpos_s: return MVM_repr_at_pos_s;
264
2.72k
    case MVM_OP_atpos_o: return MVM_repr_at_pos_o;
265
496
266
0
    case MVM_OP_existspos: return MVM_repr_exists_pos;
267
496
268
0
    case MVM_OP_atkey_i: return MVM_repr_at_key_i;
269
0
    case MVM_OP_atkey_n: return MVM_repr_at_key_n;
270
0
    case MVM_OP_atkey_s: return MVM_repr_at_key_s;
271
4.71k
    case MVM_OP_atkey_o: return MVM_repr_at_key_o;
272
496
273
9
    case MVM_OP_bindpos_i: return MVM_repr_bind_pos_i;
274
0
    case MVM_OP_bindpos_n: return MVM_repr_bind_pos_n;
275
0
    case MVM_OP_bindpos_s: return MVM_repr_bind_pos_s;
276
1.15k
    case MVM_OP_bindpos_o: return MVM_repr_bind_pos_o;
277
496
278
0
    case MVM_OP_bindkey_i: return MVM_repr_bind_key_i;
279
0
    case MVM_OP_bindkey_n: return MVM_repr_bind_key_n;
280
0
    case MVM_OP_bindkey_s: return MVM_repr_bind_key_s;
281
1.74k
    case MVM_OP_bindkey_o: return MVM_repr_bind_key_o;
282
496
283
529
    case MVM_OP_getattr_s: return MVM_repr_get_attr_s;
284
0
    case MVM_OP_getattr_n: return MVM_repr_get_attr_n;
285
1.15k
    case MVM_OP_getattr_i: return MVM_repr_get_attr_i;
286
729
    case MVM_OP_getattr_o: return MVM_repr_get_attr_o;
287
496
288
0
    case MVM_OP_getattrs_s: return MVM_repr_get_attr_s;
289
0
    case MVM_OP_getattrs_n: return MVM_repr_get_attr_n;
290
0
    case MVM_OP_getattrs_i: return MVM_repr_get_attr_i;
291
0
    case MVM_OP_getattrs_o: return MVM_repr_get_attr_o;
292
496
293
0
    case MVM_OP_attrinited: return MVM_repr_attribute_inited;
294
496
295
1.94k
    case MVM_OP_bindattr_i: case MVM_OP_bindattr_n: case MVM_OP_bindattr_s: case MVM_OP_bindattr_o: return MVM_repr_bind_attr_inso;
296
236
    case MVM_OP_bindattrs_i: case MVM_OP_bindattrs_n: case MVM_OP_bindattrs_s: case MVM_OP_bindattrs_o: return MVM_repr_bind_attr_inso;
297
236
298
1
    case MVM_OP_hintfor: return MVM_repr_hint_for;
299
236
300
10
    case MVM_OP_gt_s: case MVM_OP_ge_s: case MVM_OP_lt_s: case MVM_OP_le_s: case MVM_OP_cmp_s: return MVM_string_compare;
301
10
302
0
    case MVM_OP_eof_fh: return MVM_io_eof;
303
3
    case MVM_OP_readline_fh: case MVM_OP_readlinechomp_fh: return MVM_io_readline;
304
0
    case MVM_OP_read_fhs: return MVM_io_read_string;
305
3
306
1.42k
    case MVM_OP_elems: return MVM_repr_elems;
307
1.35k
    case MVM_OP_concat_s: return MVM_string_concatenate;
308
13
    case MVM_OP_repeat_s: return MVM_string_repeat;
309
0
    case MVM_OP_flip: return MVM_string_flip;
310
250
    case MVM_OP_split: return MVM_string_split;
311
2
    case MVM_OP_escape: return MVM_string_escape;
312
1
    case MVM_OP_uc: return MVM_string_uc;
313
0
    case MVM_OP_tc: return MVM_string_tc;
314
224
    case MVM_OP_lc: return MVM_string_lc;
315
2.11k
    case MVM_OP_eq_s: return MVM_string_equal;
316
455
    case MVM_OP_eqat_s: return MVM_string_equal_at;
317
632
    case MVM_OP_chars: case MVM_OP_graphs_s: return MVM_string_graphs;
318
0
    case MVM_OP_codes_s: return MVM_string_codes;
319
268
    case MVM_OP_index_s: return MVM_string_index;
320
390
    case MVM_OP_substr_s: return MVM_string_substring;
321
9
    case MVM_OP_join: return MVM_string_join;
322
0
    case MVM_OP_replace: return MVM_string_replace;
323
349
    case MVM_OP_iscclass: return MVM_string_is_cclass;
324
13
    case MVM_OP_findcclass: return MVM_string_find_cclass;
325
16
    case MVM_OP_findnotcclass: return MVM_string_find_not_cclass;
326
325
    case MVM_OP_nfarunalt: return MVM_nfa_run_alt;
327
110
    case MVM_OP_nfarunproto: return MVM_nfa_run_proto;
328
435
    case MVM_OP_nfafromstatelist: return MVM_nfa_from_statelist;
329
0
    case MVM_OP_hllize: return MVM_hll_map;
330
5
    case MVM_OP_gethllsym: return MVM_hll_sym_get;
331
248
    case MVM_OP_clone: return MVM_repr_clone;
332
404
    case MVM_OP_getcodeobj: return MVM_frame_get_code_object;
333
0
    case MVM_OP_isbig_I: return MVM_bigint_is_big;
334
0
    case MVM_OP_cmp_I: return MVM_bigint_cmp;
335
0
    case MVM_OP_add_I: return MVM_bigint_add;
336
0
    case MVM_OP_sub_I: return MVM_bigint_sub;
337
0
    case MVM_OP_mul_I: return MVM_bigint_mul;
338
0
    case MVM_OP_div_I: return MVM_bigint_div;
339
0
    case MVM_OP_bor_I: return MVM_bigint_or;
340
0
    case MVM_OP_band_I: return MVM_bigint_and;
341
0
    case MVM_OP_bxor_I: return MVM_bigint_xor;
342
0
    case MVM_OP_mod_I: return MVM_bigint_mod;
343
0
    case MVM_OP_lcm_I: return MVM_bigint_lcm;
344
0
    case MVM_OP_gcd_I: return MVM_bigint_gcd;
345
0
    case MVM_OP_bool_I: return MVM_bigint_bool;
346
0
    case MVM_OP_brshift_I: return MVM_bigint_shr;
347
0
    case MVM_OP_blshift_I: return MVM_bigint_shl;
348
0
    case MVM_OP_bnot_I: return MVM_bigint_not;
349
0
    case MVM_OP_div_In: return MVM_bigint_div_num;
350
0
    case MVM_OP_coerce_Is: case MVM_OP_base_I: return MVM_bigint_to_str;
351
9
    case MVM_OP_radix: return MVM_radix;
352
0
    case MVM_OP_radix_I: return MVM_bigint_radix;
353
0
    case MVM_OP_sqrt_n: return sqrt;
354
0
    case MVM_OP_sin_n: return sin;
355
0
    case MVM_OP_cos_n: return cos;
356
0
    case MVM_OP_tan_n: return tan;
357
0
    case MVM_OP_asin_n: return asin;
358
0
    case MVM_OP_acos_n: return acos;
359
0
    case MVM_OP_atan_n: return atan;
360
0
    case MVM_OP_atan2_n: return atan2;
361
0
    case MVM_OP_pow_n: return pow;
362
7
    case MVM_OP_time_n: return MVM_proc_time_n;
363
0
    case MVM_OP_randscale_n: return MVM_proc_randscale_n;
364
0
    case MVM_OP_isnanorinf: return MVM_num_isnanorinf;
365
0
    case MVM_OP_nativecallinvoke: return MVM_nativecall_invoke;
366
0
    case MVM_OP_typeparameterized: return MVM_6model_parametric_type_parameterized;
367
0
    case MVM_OP_typeparameters: return MVM_6model_parametric_type_parameters;
368
0
    case MVM_OP_typeparameterat: return MVM_6model_parametric_type_parameter_at;
369
0
    case MVM_OP_iscont_i: return MVM_6model_container_iscont_i;
370
0
    case MVM_OP_iscont_n: return MVM_6model_container_iscont_n;
371
0
    case MVM_OP_iscont_s: return MVM_6model_container_iscont_s;
372
0
    case MVM_OP_isrwcont: return MVM_6model_container_iscont_rw;
373
0
    case MVM_OP_assign_i: return MVM_6model_container_assign_i;
374
0
    case MVM_OP_assign_n: return MVM_6model_container_assign_n;
375
0
    case MVM_OP_assign_s: return MVM_6model_container_assign_s;
376
0
    case MVM_OP_decont_i: return MVM_6model_container_decont_i;
377
0
    case MVM_OP_decont_n: return MVM_6model_container_decont_n;
378
0
    case MVM_OP_decont_s: return MVM_6model_container_decont_s;
379
0
    case MVM_OP_getlexref_i32: case MVM_OP_getlexref_i16: case MVM_OP_getlexref_i8: case MVM_OP_getlexref_i: return MVM_nativeref_lex_i;
380
0
    case MVM_OP_getlexref_n32: case MVM_OP_getlexref_n: return MVM_nativeref_lex_n;
381
0
    case MVM_OP_getlexref_s: return MVM_nativeref_lex_s;
382
0
    case MVM_OP_getattrref_i: return MVM_nativeref_attr_i;
383
0
    case MVM_OP_getattrref_n: return MVM_nativeref_attr_n;
384
0
    case MVM_OP_getattrref_s: return MVM_nativeref_attr_s;
385
0
    case MVM_OP_getattrsref_i: return MVM_nativeref_attr_i;
386
0
    case MVM_OP_getattrsref_n: return MVM_nativeref_attr_n;
387
0
    case MVM_OP_getattrsref_s: return MVM_nativeref_attr_s;
388
0
    case MVM_OP_atposref_i: return MVM_nativeref_pos_i;
389
0
    case MVM_OP_atposref_n: return MVM_nativeref_pos_n;
390
0
    case MVM_OP_atposref_s: return MVM_nativeref_pos_s;
391
0
    case MVM_OP_indexingoptimized: return MVM_string_indexing_optimized;
392
0
    case MVM_OP_sp_boolify_iter: return MVM_iter_istrue;
393
0
    case MVM_OP_prof_allocated: return MVM_profile_log_allocated;
394
0
    case MVM_OP_prof_exit: return MVM_profile_log_exit;
395
0
    default:
396
0
        MVM_oops(tc, "JIT: No function for op %d in op_to_func (%s)", opcode, MVM_op_get_op(opcode)->name);
397
103k
    }
398
103k
}
399
400
static void jgb_append_guard(MVMThreadContext *tc, JitGraphBuilder *jgb,
401
16.5k
                             MVMSpeshIns *ins) {
402
16.5k
    MVMSpeshAnn   *ann = ins->annotations;
403
16.5k
    MVMJitNode   *node = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMJitNode));
404
16.5k
    MVMint32 deopt_idx;
405
16.5k
    node->type = MVM_JIT_NODE_GUARD;
406
16.5k
    node->u.guard.ins = ins;
407
16.5k
    while (ann) {
408
16.5k
        if (ann->type == MVM_SPESH_ANN_DEOPT_ONE_INS ||
409
16.5k
            ann->type == MVM_SPESH_ANN_DEOPT_INLINE) {
410
16.5k
            deopt_idx = ann->data.deopt_idx;
411
16.5k
            break;
412
16.5k
        }
413
0
        ann = ann->next;
414
0
    }
415
16.5k
    if (!ann) {
416
0
        MVM_oops(tc, "Can't find deopt idx annotation"
417
0
                                  " on spesh ins <%s>", ins->info->name);
418
0
    }
419
16.5k
    node->u.guard.deopt_target = jgb->sg->deopt_addrs[2 * deopt_idx];
420
16.5k
    node->u.guard.deopt_offset = jgb->sg->deopt_addrs[2 * deopt_idx + 1];
421
16.5k
    jgb_append_node(jgb, node);
422
16.5k
}
423
424
static MVMint32 jgb_consume_invoke(MVMThreadContext *tc, JitGraphBuilder *jgb,
425
17.7k
                                   MVMSpeshIns *ins) {
426
17.7k
    MVMCompUnit       *cu = jgb->sg->sf->body.cu;
427
17.7k
    MVMint16 callsite_idx = ins->operands[0].callsite_idx;
428
17.7k
    MVMCallsite       *cs = cu->body.callsites[callsite_idx];
429
17.7k
    MVMSpeshIns **arg_ins = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMSpeshIns*) * cs->arg_count);
430
17.7k
    MVMint16            i = 0;
431
17.7k
    MVMJitNode      *node;
432
17.7k
    MVMint32      reentry_label;
433
17.7k
    MVMReturnType return_type;
434
17.7k
    MVMint16      return_register;
435
17.7k
    MVMint16      code_register;
436
17.7k
    MVMint16      spesh_cand;
437
17.7k
    MVMint16      is_fast;
438
17.7k
439
57.3k
    while ((ins = ins->next)) {
440
57.3k
        switch(ins->info->opcode) {
441
39.5k
        case MVM_OP_arg_i:
442
39.5k
        case MVM_OP_arg_n:
443
39.5k
        case MVM_OP_arg_s:
444
39.5k
        case MVM_OP_arg_o:
445
39.5k
        case MVM_OP_argconst_i:
446
39.5k
        case MVM_OP_argconst_n:
447
39.5k
        case MVM_OP_argconst_s:
448
39.5k
            MVM_jit_log(tc, "Invoke arg: <%s>\n", ins->info->name);
449
39.5k
            arg_ins[i++] = ins;
450
39.5k
            break;
451
79
        case MVM_OP_invoke_v:
452
79
            return_type     = MVM_RETURN_VOID;
453
79
            return_register = -1;
454
79
            code_register   = ins->operands[0].reg.orig;
455
79
            spesh_cand      = -1;
456
79
            is_fast         = 0;
457
79
            goto checkargs;
458
0
        case MVM_OP_invoke_i:
459
0
            return_type     = MVM_RETURN_INT;
460
0
            return_register = ins->operands[0].reg.orig;
461
0
            code_register   = ins->operands[1].reg.orig;
462
0
            spesh_cand      = -1;
463
0
            is_fast         = 0;
464
0
            goto checkargs;
465
0
        case MVM_OP_invoke_n:
466
0
            return_type     = MVM_RETURN_NUM;
467
0
            return_register = ins->operands[0].reg.orig;
468
0
            code_register   = ins->operands[1].reg.orig;
469
0
            spesh_cand      = -1;
470
0
            is_fast         = 0;
471
0
            goto checkargs;
472
5
        case MVM_OP_invoke_s:
473
5
            return_type     = MVM_RETURN_STR;
474
5
            return_register = ins->operands[0].reg.orig;
475
5
            code_register   = ins->operands[1].reg.orig;
476
5
            spesh_cand      = -1;
477
5
            is_fast         = 0;
478
5
            goto checkargs;
479
14.6k
        case MVM_OP_invoke_o:
480
14.6k
            return_type     = MVM_RETURN_OBJ;
481
14.6k
            return_register = ins->operands[0].reg.orig;
482
14.6k
            code_register   = ins->operands[1].reg.orig;
483
14.6k
            spesh_cand      = -1;
484
14.6k
            is_fast         = 0;
485
14.6k
            goto checkargs;
486
204
        case MVM_OP_sp_fastinvoke_v:
487
204
            return_type     = MVM_RETURN_VOID;
488
204
            return_register = -1;
489
204
            code_register   = ins->operands[0].reg.orig;
490
204
            spesh_cand      = ins->operands[1].lit_i16;
491
204
            is_fast         = 1;
492
204
            goto checkargs;
493
2.85k
        case MVM_OP_sp_fastinvoke_o:
494
2.85k
            return_type     = MVM_RETURN_OBJ;
495
2.85k
            return_register = ins->operands[0].reg.orig;;
496
2.85k
            code_register   = ins->operands[1].reg.orig;
497
2.85k
            spesh_cand      = ins->operands[2].lit_i16;
498
2.85k
            is_fast         = 1;
499
2.85k
            goto checkargs;
500
0
        case MVM_OP_sp_fastinvoke_s:
501
0
            return_type     = MVM_RETURN_STR;
502
0
            return_register = ins->operands[0].reg.orig;;
503
0
            code_register   = ins->operands[1].reg.orig;
504
0
            spesh_cand      = ins->operands[2].lit_i16;
505
0
            is_fast         = 1;
506
0
            goto checkargs;
507
0
        case MVM_OP_sp_fastinvoke_i:
508
0
            return_type     = MVM_RETURN_INT;
509
0
            return_register = ins->operands[0].reg.orig;;
510
0
            code_register   = ins->operands[1].reg.orig;
511
0
            spesh_cand      = ins->operands[2].lit_i16;
512
0
            is_fast         = 1;
513
0
            goto checkargs;
514
0
        case MVM_OP_sp_fastinvoke_n:
515
0
            return_type     = MVM_RETURN_NUM;
516
0
            return_register = ins->operands[0].reg.orig;;
517
0
            code_register   = ins->operands[1].reg.orig;
518
0
            spesh_cand      = ins->operands[2].lit_i16;
519
0
            is_fast         = 1;
520
0
            goto checkargs;
521
0
        default:
522
0
            MVM_jit_log(tc, "Unexpected opcode in invoke sequence: <%s>\n",
523
0
                        ins->info->name);
524
0
            return 0;
525
57.3k
        }
526
57.3k
    }
527
17.7k
 checkargs:
528
17.7k
    if (!ins || i < cs->arg_count) {
529
0
        MVM_jit_log(tc, "Could not find invoke opcode or enough arguments\n"
530
0
                    "BAIL: op <%s>, expected args: %d, num of args: %d\n",
531
0
                    ins? ins->info->name : "NULL", i, cs->arg_count);
532
0
        return 0;
533
0
    }
534
17.7k
    MVM_jit_log(tc, "Invoke instruction: <%s>\n", ins->info->name);
535
17.7k
    /* get label /after/ current (invoke) ins, where we'll need to reenter the JIT */
536
17.7k
    reentry_label = get_label_for_ins(tc, jgb, jgb->cur_bb, ins, 1);
537
17.7k
    /* create invoke node */
538
17.7k
    node = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMJitNode));
539
17.7k
    node->type                     = MVM_JIT_NODE_INVOKE;
540
17.7k
    node->u.invoke.callsite_idx    = callsite_idx;
541
17.7k
    node->u.invoke.arg_count       = cs->arg_count;
542
17.7k
    node->u.invoke.arg_ins         = arg_ins;
543
17.7k
    node->u.invoke.return_type     = return_type;
544
17.7k
    node->u.invoke.return_register = return_register;
545
17.7k
    node->u.invoke.code_register   = code_register;
546
17.7k
    node->u.invoke.spesh_cand      = spesh_cand;
547
17.7k
    node->u.invoke.reentry_label   = reentry_label;
548
17.7k
    node->u.invoke.is_fast         = is_fast;
549
17.7k
    jgb_append_node(jgb, node);
550
17.7k
551
17.7k
    /* append reentry label */
552
17.7k
    jgb_append_label(tc, jgb, reentry_label);
553
17.7k
    /* move forward to invoke ins */
554
17.7k
    jgb->cur_ins = ins;
555
17.7k
    return 1;
556
17.7k
}
557
558
static void jgb_append_control(MVMThreadContext *tc, JitGraphBuilder *jgb,
559
285k
                                MVMSpeshIns *ins, MVMJitControlType ctrl) {
560
285k
    MVMJitNode *node = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMJitNode));
561
285k
    node->type = MVM_JIT_NODE_CONTROL;
562
285k
    node->u.control.ins  = ins;
563
285k
    node->u.control.type = ctrl;
564
285k
    jgb_append_node(jgb, node);
565
285k
}
566
567
static MVMint32 jgb_consume_jumplist(MVMThreadContext *tc, JitGraphBuilder *jgb,
568
406
                                     MVMSpeshIns *ins) {
569
406
    MVMint64 num_labels  = ins->operands[0].lit_i64;
570
406
    MVMint16 idx_reg     = ins->operands[1].reg.orig;
571
406
    MVMint32 *in_labels  = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMint32) * num_labels);
572
406
    MVMint32 *out_labels = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMint32) * num_labels);
573
406
    MVMSpeshBB *bb       = jgb->cur_bb;
574
406
    MVMJitNode *node;
575
406
    MVMint64 i;
576
4.22k
    for (i = 0; i < num_labels; i++) {
577
3.82k
        bb = bb->linear_next; /* take the next basic block */
578
3.82k
        if (!bb || bb->first_ins != bb->last_ins) return 0; /*  which must exist */
579
3.82k
        ins = bb->first_ins;  /*  and it's first and only entry */
580
3.82k
        if (ins->info->opcode != MVM_OP_goto)  /* which must be a goto */
581
0
            return 0;
582
3.82k
        in_labels[i]  = get_label_for_bb(tc, jgb, bb);
583
3.82k
        out_labels[i] = get_label_for_bb(tc, jgb, ins->operands[0].ins_bb);
584
3.82k
    }
585
406
    /* build the node */
586
406
    node = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMJitNode));
587
406
    node->type = MVM_JIT_NODE_JUMPLIST;
588
406
    node->u.jumplist.num_labels = num_labels;
589
406
    node->u.jumplist.reg = idx_reg;
590
406
    node->u.jumplist.in_labels = in_labels;
591
406
    node->u.jumplist.out_labels = out_labels;
592
406
    jgb_append_node(jgb, node);
593
406
    /* set cur_bb and cur_ins to the end of our jumplist */
594
406
    jgb->cur_bb = bb;
595
406
    jgb->cur_ins = ins;
596
406
    return 1;
597
406
}
598
599
0
static MVMint32 jgb_add_data_node(MVMThreadContext *tc, JitGraphBuilder *jgb, void *data, size_t size) {
600
0
    MVMJitNode *node = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMJitNode));
601
0
    MVMint32 label   = get_label_for_obj(tc, jgb, data);
602
0
    node->type         = MVM_JIT_NODE_DATA;
603
0
    node->u.data.data  = data;
604
0
    node->u.data.size  = size;
605
0
    node->u.data.label = label;
606
0
    jgb_append_node(jgb, node);
607
0
    return label;
608
0
}
609
610
0
static MVMuint16 * try_fake_extop_regs(MVMThreadContext *tc, MVMSpeshGraph *sg, MVMSpeshIns *ins, size_t *bufsize) {
611
0
    MVMuint16 *regs = MVM_spesh_alloc(tc, sg, (*bufsize = (ins->info->num_operands * sizeof(MVMuint16))));
612
0
    MVMuint16 i;
613
0
    for (i = 0; i < ins->info->num_operands; i++) {
614
0
        switch (ins->info->operands[i] & MVM_operand_rw_mask) {
615
0
        case MVM_operand_read_reg:
616
0
        case MVM_operand_write_reg:
617
0
            regs[i] = ins->operands[i].reg.orig;
618
0
            break;
619
0
        default:
620
0
            MVM_free(regs);
621
0
            return NULL;
622
0
        }
623
0
    }
624
0
    return regs;
625
0
}
626
627
0
static void log_inline(MVMThreadContext *tc, MVMSpeshGraph *sg, MVMint32 inline_idx, MVMint32 is_entry) {
628
0
    MVMStaticFrame *sf = sg->inlines[inline_idx].code->body.sf;
629
0
    char *name         = MVM_string_utf8_encode_C_string(tc, sf->body.name);
630
0
    char *cuuid        = MVM_string_utf8_encode_C_string(tc, sf->body.cuuid);
631
0
    MVM_jit_log(tc, "%s inline %d (name: %s, cuuid: %s)\n", is_entry ? "Entering" : "Leaving",
632
0
                inline_idx, name, cuuid);
633
0
    MVM_free(name);
634
0
    MVM_free(cuuid);
635
0
}
636
637
static void jgb_before_ins(MVMThreadContext *tc, JitGraphBuilder *jgb,
638
930k
                           MVMSpeshBB *bb, MVMSpeshIns *ins) {
639
930k
   MVMSpeshAnn *ann = ins->annotations;
640
930k
641
930k
    /* Search annotations for stuff that may need a label. */
642
991k
    while (ann) {
643
60.3k
        switch(ann->type) {
644
3.08k
        case MVM_SPESH_ANN_DEOPT_OSR: {
645
3.08k
            /* get label before our instruction */
646
3.08k
            MVMint32 label = get_label_for_ins(tc, jgb, bb, ins, 0);
647
3.08k
            jgb_append_label(tc, jgb, label);
648
3.08k
            add_deopt_idx(tc, jgb, label, ann->data.deopt_idx);
649
3.08k
            break;
650
3.08k
        }
651
3.52k
        case MVM_SPESH_ANN_FH_START: {
652
3.52k
            MVMint32 label = get_label_for_ins(tc, jgb, bb, ins, 0);
653
3.52k
            jgb_append_label(tc, jgb, label);
654
3.52k
            jgb->handlers[ann->data.frame_handler_index].start_label = label;
655
3.52k
            /* Load the current position into the jit entry label, so that
656
3.52k
             * when throwing we'll know which handler to use */
657
3.52k
            jgb_append_control(tc, jgb, ins, MVM_JIT_CONTROL_DYNAMIC_LABEL);
658
3.52k
            break;
659
3.08k
        }
660
2.66k
        case MVM_SPESH_ANN_FH_END: {
661
2.66k
            MVMint32 label = get_label_for_ins(tc, jgb, bb, ins, 0);
662
2.66k
            jgb_append_label(tc, jgb, label);
663
2.66k
            jgb->handlers[ann->data.frame_handler_index].end_label = label;
664
2.66k
            /* Same as above. Note that the dynamic label control
665
2.66k
             * actually loads a position a few bytes away from the
666
2.66k
             * label appended above. This is in this case intentional
667
2.66k
             * because the frame handler end is exclusive; once it is
668
2.66k
             * passed we should not use the same handler again.  If we
669
2.66k
             * loaded the exact same position, we would not be able to
670
2.66k
             * distinguish between the end of the basic block to which
671
2.66k
             * the handler applies and the start of the basic block to
672
2.66k
             * which it doesn't. */
673
2.66k
            jgb_append_control(tc, jgb, ins, MVM_JIT_CONTROL_DYNAMIC_LABEL);
674
2.66k
            break;
675
3.08k
        }
676
2.70k
        case MVM_SPESH_ANN_FH_GOTO: {
677
2.70k
            MVMint32 label = get_label_for_ins(tc, jgb, bb, ins, 0);
678
2.70k
            jgb_append_label(tc, jgb, label);
679
2.70k
            jgb->handlers[ann->data.frame_handler_index].goto_label = label;
680
2.70k
            break;
681
3.08k
        }
682
3.33k
        case MVM_SPESH_ANN_INLINE_START: {
683
3.33k
            MVMint32 label = get_label_for_ins(tc, jgb, bb, ins, 0);
684
3.33k
            jgb_append_label(tc, jgb, label);
685
3.33k
            jgb->inlines[ann->data.inline_idx].start_label = label;
686
3.33k
            if (tc->instance->jit_log_fh)
687
0
                log_inline(tc, jgb->sg, ann->data.inline_idx, 1);
688
3.33k
            break;
689
3.08k
        }
690
60.3k
        } /* switch */
691
60.3k
        ann = ann->next;
692
60.3k
    }
693
930k
694
930k
    if (ins->info->jittivity & (MVM_JIT_INFO_THROWISH | MVM_JIT_INFO_INVOKISH)) {
695
42.7k
        jgb_append_control(tc, jgb, ins, MVM_JIT_CONTROL_THROWISH_PRE);
696
42.7k
    }
697
930k
}
698
699
static void jgb_after_ins(MVMThreadContext *tc, JitGraphBuilder *jgb,
700
929k
                          MVMSpeshBB *bb, MVMSpeshIns *ins) {
701
929k
    MVMSpeshAnn *ann;
702
929k
703
929k
    /* If we've consumed an (or throwish) op, we should append a guard */
704
929k
    if (ins->info->jittivity & MVM_JIT_INFO_INVOKISH) {
705
40.1k
        MVM_jit_log(tc, "append invokish control guard\n");
706
40.1k
        jgb_append_control(tc, jgb, ins, MVM_JIT_CONTROL_INVOKISH);
707
40.1k
    }
708
889k
    else if (ins->info->jittivity & MVM_JIT_INFO_THROWISH) {
709
1.81k
        jgb_append_control(tc, jgb, ins, MVM_JIT_CONTROL_THROWISH_POST);
710
1.81k
    }
711
929k
    /* This order of processing is necessary to ensure that a label
712
929k
     * calculated by one of the control guards as well as the labels
713
929k
     * calculated below point to the exact same instruction. This is a
714
929k
     * relatively fragile construction! One could argue that the
715
929k
     * control guards should in fact use the same (dynamic) labels. */
716
929k
    ann = ins->annotations;
717
1.02M
    while (ann) {
718
91.2k
        if (ann->type == MVM_SPESH_ANN_INLINE_END) {
719
3.33k
            MVMint32 label = get_label_for_ins(tc, jgb, bb, ins, 1);
720
3.33k
            jgb_append_label(tc, jgb, label);
721
3.33k
            jgb->inlines[ann->data.inline_idx].end_label = label;
722
3.33k
            if (tc->instance->jit_log_fh)
723
0
                log_inline(tc, jgb->sg, ann->data.inline_idx, 0);
724
87.9k
        } else if (ann->type == MVM_SPESH_ANN_DEOPT_ALL_INS /* ||
725
20.2k
                                                               ann->type == MVM_SPESH_ANN_DEOPT_INLINE */) {
726
20.2k
            /* An underlying assumption here is that this instruction
727
20.2k
             * will in fact set the jit_entry_label to a correct
728
20.2k
             * value. This is clearly true for invoking ops as well
729
20.2k
             * as invokish ops, and in fact there is no other way
730
20.2k
             * to get a deopt_all_ins annotation. Still, be warned. */
731
20.2k
            MVMint32 label = get_label_for_ins(tc, jgb, bb, ins, 1);
732
20.2k
            jgb_append_label(tc, jgb, label);
733
20.2k
            add_deopt_idx(tc, jgb, label, ann->data.deopt_idx);
734
20.2k
        }
735
91.2k
        ann = ann->next;
736
91.2k
    }
737
929k
}
738
739
static MVMint32 jgb_consume_reprop(MVMThreadContext *tc, JitGraphBuilder *jgb,
740
59.9k
                                   MVMSpeshBB *bb, MVMSpeshIns *ins) {
741
59.9k
    MVMint16 op = ins->info->opcode;
742
59.9k
    MVMSpeshOperand type_operand;
743
59.9k
    MVMSpeshFacts *type_facts = 0;
744
59.9k
    MVMint32 alternative = 0;
745
59.9k
746
59.9k
    switch (op) {
747
25.7k
        case MVM_OP_unshift_i:
748
25.7k
        case MVM_OP_unshift_n:
749
25.7k
        case MVM_OP_unshift_s:
750
25.7k
        case MVM_OP_unshift_o:
751
25.7k
        case MVM_OP_bindkey_i:
752
25.7k
        case MVM_OP_bindkey_n:
753
25.7k
        case MVM_OP_bindkey_s:
754
25.7k
        case MVM_OP_bindkey_o:
755
25.7k
        case MVM_OP_bindpos_i:
756
25.7k
        case MVM_OP_bindpos_n:
757
25.7k
        case MVM_OP_bindpos_s:
758
25.7k
        case MVM_OP_bindpos_o:
759
25.7k
        case MVM_OP_bindattr_i:
760
25.7k
        case MVM_OP_bindattr_n:
761
25.7k
        case MVM_OP_bindattr_s:
762
25.7k
        case MVM_OP_bindattr_o:
763
25.7k
        case MVM_OP_bindattrs_i:
764
25.7k
        case MVM_OP_bindattrs_n:
765
25.7k
        case MVM_OP_bindattrs_s:
766
25.7k
        case MVM_OP_bindattrs_o:
767
25.7k
        case MVM_OP_push_i:
768
25.7k
        case MVM_OP_push_n:
769
25.7k
        case MVM_OP_push_s:
770
25.7k
        case MVM_OP_push_o:
771
25.7k
        case MVM_OP_deletekey:
772
25.7k
        case MVM_OP_setelemspos:
773
25.7k
        case MVM_OP_splice:
774
25.7k
            type_operand = ins->operands[0];
775
25.7k
            break;
776
34.1k
        case MVM_OP_atpos_i:
777
34.1k
        case MVM_OP_atpos_n:
778
34.1k
        case MVM_OP_atpos_s:
779
34.1k
        case MVM_OP_atpos_o:
780
34.1k
        case MVM_OP_atkey_i:
781
34.1k
        case MVM_OP_atkey_n:
782
34.1k
        case MVM_OP_atkey_s:
783
34.1k
        case MVM_OP_atkey_o:
784
34.1k
        case MVM_OP_elems:
785
34.1k
        case MVM_OP_shift_i:
786
34.1k
        case MVM_OP_shift_n:
787
34.1k
        case MVM_OP_shift_s:
788
34.1k
        case MVM_OP_shift_o:
789
34.1k
        case MVM_OP_pop_i:
790
34.1k
        case MVM_OP_pop_n:
791
34.1k
        case MVM_OP_pop_s:
792
34.1k
        case MVM_OP_pop_o:
793
34.1k
        case MVM_OP_existskey:
794
34.1k
        case MVM_OP_existspos:
795
34.1k
        case MVM_OP_getattr_i:
796
34.1k
        case MVM_OP_getattr_n:
797
34.1k
        case MVM_OP_getattr_s:
798
34.1k
        case MVM_OP_getattr_o:
799
34.1k
        case MVM_OP_getattrs_i:
800
34.1k
        case MVM_OP_getattrs_n:
801
34.1k
        case MVM_OP_getattrs_s:
802
34.1k
        case MVM_OP_getattrs_o:
803
34.1k
        case MVM_OP_attrinited:
804
34.1k
        case MVM_OP_hintfor:
805
34.1k
            type_operand = ins->operands[1];
806
34.1k
            break;
807
0
        case MVM_OP_box_i:
808
0
        case MVM_OP_box_n:
809
0
        case MVM_OP_box_s:
810
0
            type_operand = ins->operands[2];
811
0
            break;
812
0
        default:
813
0
            MVM_jit_log(tc, "devirt: couldn't figure out type operand for op %s\n", ins->info->name);
814
0
            return 0;
815
59.9k
816
59.9k
    }
817
59.9k
818
59.9k
    type_facts = MVM_spesh_get_facts(tc, jgb->sg, type_operand);
819
59.9k
820
59.9k
    if (type_facts && type_facts->flags & MVM_SPESH_FACT_KNOWN_TYPE && type_facts->type) {
821
40.1k
        switch(op) {
822
3.13k
            case MVM_OP_atkey_i:
823
3.13k
            case MVM_OP_atkey_n:
824
3.13k
            case MVM_OP_atkey_s:
825
3.13k
            case MVM_OP_atkey_o:
826
3.13k
                alternative = 1;
827
11.6k
            case MVM_OP_atpos_i:
828
11.6k
            case MVM_OP_atpos_n:
829
11.6k
            case MVM_OP_atpos_s:
830
11.6k
            case MVM_OP_atpos_o: {
831
11.6k
                /* atpos_i             w(int64) r(obj) r(int64) */
832
11.6k
                /* atkey_i             w(int64) r(obj) r(str)*/
833
11.6k
834
11.6k
                /*void (*at_pos) (MVMThreadContext *tc, MVMSTable *st,
835
11.6k
                 *    MVMObject *root, void *data, MVMint64 index,
836
11.6k
                 *    MVMRegister *result, MVMuint16 kind);*/
837
11.6k
838
11.6k
                /*REPR(obj)->pos_funcs.at_pos(tc, STABLE(obj), obj, OBJECT_BODY(obj),
839
11.6k
                 *  idx, &value, MVM_reg_int64);*/
840
11.6k
841
11.6k
                MVMint32 dst      = ins->operands[0].reg.orig;
842
11.6k
                MVMint32 invocant = ins->operands[1].reg.orig;
843
11.6k
                MVMint32 value    = ins->operands[2].reg.orig;
844
11.6k
845
11.6k
                void *function = alternative
846
3.13k
                    ? (void *)((MVMObject*)type_facts->type)->st->REPR->ass_funcs.at_key
847
8.53k
                    : (void *)((MVMObject*)type_facts->type)->st->REPR->pos_funcs.at_pos;
848
11.6k
849
11.6k
                MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
850
11.6k
                                         { MVM_JIT_REG_STABLE,  invocant },
851
11.6k
                                         { MVM_JIT_REG_VAL,     invocant },
852
11.6k
                                         { MVM_JIT_REG_OBJBODY, invocant },
853
11.6k
                                         { MVM_JIT_REG_VAL,  value },
854
11.6k
                                         { MVM_JIT_REG_ADDR, dst },
855
11.6k
                                         { MVM_JIT_LITERAL,
856
11.6k
                                             op == MVM_OP_atpos_i || op == MVM_OP_atkey_i ? MVM_reg_int64 :
857
6.01k
                                             op == MVM_OP_atpos_n || op == MVM_OP_atkey_n ? MVM_reg_num64 :
858
6.01k
                                             op == MVM_OP_atpos_s || op == MVM_OP_atkey_s ? MVM_reg_str :
859
6.01k
                                                                    MVM_reg_obj } };
860
11.6k
                jgb_append_call_c(tc, jgb, function, 7, args, MVM_JIT_RV_VOID, -1);
861
11.6k
                MVM_jit_log(tc, "devirt: emitted an %s via jgb_consume_reprop\n", ins->info->name);
862
11.6k
                return 1;
863
11.6k
            }
864
2.72k
            case MVM_OP_bindkey_i:
865
2.72k
            case MVM_OP_bindkey_n:
866
2.72k
            case MVM_OP_bindkey_s:
867
2.72k
            case MVM_OP_bindkey_o:
868
2.72k
                alternative = 1;
869
3.79k
            case MVM_OP_bindpos_i:
870
3.79k
            case MVM_OP_bindpos_n:
871
3.79k
            case MVM_OP_bindpos_s:
872
3.79k
            case MVM_OP_bindpos_o: {
873
3.79k
                /*bindpos_i           r(obj) r(int64) r(int64)*/
874
3.79k
                /*bindkey_i           r(obj) r(str) r(int64)*/
875
3.79k
876
3.79k
                /* void (*bind_pos) (MVMThreadContext *tc, MVMSTable *st,
877
3.79k
                      MVMObject *root, void *data, MVMint64 index,
878
3.79k
                      MVMRegister value, MVMuint16 kind); */
879
3.79k
880
3.79k
                /* void (*bind_key) (MVMThreadContext *tc, MVMSTable *st, MVMObject *root,
881
3.79k
                      void *data, MVMObject *key, MVMRegister value, MVMuint16 kind); */
882
3.79k
883
3.79k
                MVMint32 invocant = ins->operands[0].reg.orig;
884
3.79k
                MVMint32 key      = ins->operands[1].reg.orig;
885
3.79k
                MVMint32 value    = ins->operands[2].reg.orig;
886
3.79k
887
3.79k
                void *function = alternative
888
2.72k
                    ? (void *)((MVMObject*)type_facts->type)->st->REPR->ass_funcs.bind_key
889
1.07k
                    : (void *)((MVMObject*)type_facts->type)->st->REPR->pos_funcs.bind_pos;
890
3.79k
891
3.79k
                MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
892
3.79k
                                         { MVM_JIT_REG_STABLE,  invocant },
893
3.79k
                                         { MVM_JIT_REG_VAL,     invocant },
894
3.79k
                                         { MVM_JIT_REG_OBJBODY, invocant },
895
3.79k
                                         { MVM_JIT_REG_VAL, key },
896
3.79k
                                         { MVM_JIT_REG_VAL, value },
897
3.79k
                                         { MVM_JIT_LITERAL,
898
3.79k
                                             op == MVM_OP_bindpos_i || op == MVM_OP_bindkey_i ? MVM_reg_int64 :
899
3.26k
                                             op == MVM_OP_bindpos_n || op == MVM_OP_bindkey_n ? MVM_reg_num64 :
900
3.26k
                                             op == MVM_OP_bindpos_s || op == MVM_OP_bindkey_s ? MVM_reg_str :
901
3.26k
                                                                    MVM_reg_obj } };
902
3.79k
                jgb_append_call_c(tc, jgb, function, 7, args, MVM_JIT_RV_VOID, -1);
903
3.79k
                MVM_jit_log(tc, "devirt: emitted a %s via jgb_consume_reprop\n", ins->info->name);
904
3.79k
                return 1;
905
3.79k
            }
906
5.18k
            case MVM_OP_elems: {
907
5.18k
                /*elems               w(int64) r(obj) :pure*/
908
5.18k
909
5.18k
                MVMint32 dst       = ins->operands[0].reg.orig;
910
5.18k
                MVMint32 invocant  = ins->operands[1].reg.orig;
911
5.18k
912
5.18k
                void *function = ((MVMObject*)type_facts->type)->st->REPR->elems;
913
5.18k
914
5.18k
                MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
915
5.18k
                                         { MVM_JIT_REG_STABLE,  invocant },
916
5.18k
                                         { MVM_JIT_REG_VAL,     invocant },
917
5.18k
                                         { MVM_JIT_REG_OBJBODY, invocant } };
918
5.18k
                jgb_append_call_c(tc, jgb, function, 4, args, MVM_JIT_RV_INT, dst);
919
5.18k
                MVM_jit_log(tc, "devirt: emitted an elems via jgb_consume_reprop\n");
920
5.18k
                return 1;
921
3.79k
            }
922
2.08k
            case MVM_OP_getattr_i:
923
2.08k
            case MVM_OP_getattr_n:
924
2.08k
            case MVM_OP_getattr_s:
925
2.08k
            case MVM_OP_getattr_o:
926
2.08k
            case MVM_OP_getattrs_i:
927
2.08k
            case MVM_OP_getattrs_n:
928
2.08k
            case MVM_OP_getattrs_s:
929
2.08k
            case MVM_OP_getattrs_o: {
930
2.08k
                /*getattr_i           w(int64) r(obj) r(obj) str int16*/
931
2.08k
                /*getattrs_i          w(int64) r(obj) r(obj) r(str)*/
932
2.08k
                /*static void get_attribute(MVMThreadContext *tc, MVMSTable *st, MVMObject *root,*/
933
2.08k
                /*        void *data, MVMObject *class_handle, MVMString *name, MVMint64 hint,*/
934
2.08k
                /*      MVMRegister *result_reg, MVMuint16 kind) {*/
935
2.08k
936
2.08k
                /* reprconv and interp.c check for concreteness, so we'd either
937
2.08k
                 * have to emit a bit of code to check and throw or just rely
938
2.08k
                 * on a concreteness fact */
939
2.08k
940
2.08k
                MVMSpeshFacts *object_facts = MVM_spesh_get_facts(tc, jgb->sg, ins->operands[1]);
941
2.08k
942
2.08k
                if (object_facts->flags & MVM_SPESH_FACT_CONCRETE) {
943
2.08k
                    MVMint32 is_name_direct = ins->info->num_operands == 5;
944
2.08k
945
2.08k
                    MVMint32 dst       = ins->operands[0].reg.orig;
946
2.08k
                    MVMint32 invocant  = ins->operands[1].reg.orig;
947
2.08k
                    MVMint32 type      = ins->operands[2].reg.orig;
948
2.08k
                    MVMint32 attrname  = is_name_direct ? ins->operands[3].lit_str_idx : ins->operands[3].reg.orig;
949
2.08k
                    MVMint32 attrhint  = is_name_direct ? ins->operands[4].lit_i16 : -1;
950
2.08k
951
2.08k
                    void *function = ((MVMObject*)type_facts->type)->st->REPR->attr_funcs.get_attribute;
952
2.08k
953
2.08k
                    MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
954
2.08k
                                             { MVM_JIT_REG_STABLE,  invocant },
955
2.08k
                                             { MVM_JIT_REG_VAL,     invocant },
956
2.08k
                                             { MVM_JIT_REG_OBJBODY, invocant },
957
2.08k
                                             { MVM_JIT_REG_VAL,     type },
958
2.08k
                                             { is_name_direct ? MVM_JIT_STR_IDX : MVM_JIT_REG_VAL,
959
2.08k
                                                                    attrname },
960
2.08k
                                             { MVM_JIT_LITERAL,     attrhint },
961
2.08k
                                             { MVM_JIT_REG_ADDR,    dst },
962
2.08k
                                             { MVM_JIT_LITERAL,
963
2.08k
                                                 op == MVM_OP_getattr_i || op == MVM_OP_getattrs_i ? MVM_reg_int64 :
964
1.38k
                                                 op == MVM_OP_getattr_n || op == MVM_OP_getattrs_n ? MVM_reg_num64 :
965
1.38k
                                                 op == MVM_OP_getattr_s || op == MVM_OP_getattrs_s ? MVM_reg_str :
966
964
                                                                        MVM_reg_obj } };
967
2.08k
                    MVM_jit_log(tc, "devirt: emitted a %s via jgb_consume_reprop\n", ins->info->name);
968
2.08k
                    jgb_append_call_c(tc, jgb, function, 9, args, MVM_JIT_RV_VOID, -1);
969
2.08k
970
2.08k
                    return 1;
971
0
                } else {
972
0
                    MVM_jit_log(tc, "devirt: couldn't %s; concreteness not sure\n", ins->info->name);
973
0
                    break;
974
0
                }
975
2.08k
            }
976
0
            case MVM_OP_attrinited: {
977
0
                /*attrinited          w(int64) r(obj) r(obj) r(str)*/
978
0
979
0
                /*MVMint64 (*is_attribute_initialized) (MVMThreadContext *tc, MVMSTable *st,*/
980
0
                    /*void *data, MVMObject *class_handle, MVMString *name,*/
981
0
                    /*MVMint64 hint);*/
982
0
983
0
                /* reprconv and interp.c check for concreteness, so we'd either
984
0
                 * have to emit a bit of code to check and throw or just rely
985
0
                 * on a concreteness fact */
986
0
987
0
                MVMSpeshFacts *object_facts = MVM_spesh_get_facts(tc, jgb->sg, ins->operands[1]);
988
0
989
0
                if (object_facts->flags & MVM_SPESH_FACT_CONCRETE) {
990
0
                    MVMint32 dst       = ins->operands[0].reg.orig;
991
0
                    MVMint32 invocant  = ins->operands[1].reg.orig;
992
0
                    MVMint32 type      = ins->operands[2].reg.orig;
993
0
                    MVMint32 attrname  = ins->operands[3].reg.orig;
994
0
                    MVMint32 attrhint  = MVM_NO_HINT;
995
0
996
0
                    void *function = ((MVMObject*)type_facts->type)->st->REPR->attr_funcs.is_attribute_initialized;
997
0
998
0
                    MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
999
0
                                             { MVM_JIT_REG_STABLE,  invocant },
1000
0
                                             { MVM_JIT_REG_OBJBODY, invocant },
1001
0
                                             { MVM_JIT_REG_VAL,     type },
1002
0
                                             { MVM_JIT_REG_VAL,     attrname },
1003
0
                                             { MVM_JIT_LITERAL,     attrhint } };
1004
0
                    MVM_jit_log(tc, "devirt: emitted a %s via jgb_consume_reprop\n", ins->info->name);
1005
0
                    jgb_append_call_c(tc, jgb, function, 6, args, MVM_JIT_RV_INT, dst);
1006
0
1007
0
                    return 1;
1008
0
                } else {
1009
0
                    MVM_jit_log(tc, "devirt: couldn't %s; concreteness not sure\n", ins->info->name);
1010
0
                    break;
1011
0
                }
1012
0
            }
1013
844
            case MVM_OP_bindattr_i:
1014
844
            case MVM_OP_bindattr_n:
1015
844
            case MVM_OP_bindattr_s:
1016
844
            case MVM_OP_bindattr_o:
1017
844
            case MVM_OP_bindattrs_i:
1018
844
            case MVM_OP_bindattrs_n:
1019
844
            case MVM_OP_bindattrs_s:
1020
844
            case MVM_OP_bindattrs_o: {
1021
844
                /*bindattr_n          r(obj) r(obj) str    r(num64) int16*/
1022
844
                /*bindattrs_n         r(obj) r(obj) r(str) r(num64)*/
1023
844
1024
844
                /* static void bind_attribute(MVMThreadContext *tc, MVMSTable *st, MVMObject *root,
1025
844
                 *        void *data, MVMObject *class_handle, MVMString *name, MVMint64 hint,
1026
844
                 *        MVMRegister value_reg, MVMuint16 kind) */
1027
844
1028
844
                /* reprconv and interp.c check for concreteness, so we'd either
1029
844
                 * have to emit a bit of code to check and throw or just rely
1030
844
                 * on a concreteness fact */
1031
844
1032
844
                MVMSpeshFacts *object_facts = MVM_spesh_get_facts(tc, jgb->sg, ins->operands[1]);
1033
844
1034
844
                if (object_facts->flags & MVM_SPESH_FACT_CONCRETE) {
1035
0
                    MVMint32 is_name_direct = ins->info->num_operands == 5;
1036
0
1037
0
                    MVMint32 invocant  = ins->operands[0].reg.orig;
1038
0
                    MVMint32 type      = ins->operands[1].reg.orig;
1039
0
                    MVMint32 attrname  = is_name_direct ? ins->operands[2].lit_str_idx : ins->operands[2].reg.orig;
1040
0
                    MVMint32 attrhint  = is_name_direct ? ins->operands[4].lit_i16 : -1;
1041
0
                    MVMint32 value     = ins->operands[3].reg.orig;
1042
0
1043
0
                    void *function = ((MVMObject*)type_facts->type)->st->REPR->attr_funcs.bind_attribute;
1044
0
1045
0
                    MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
1046
0
                                             { MVM_JIT_REG_STABLE,  invocant },
1047
0
                                             { MVM_JIT_REG_VAL,     invocant },
1048
0
                                             { MVM_JIT_REG_OBJBODY, invocant },
1049
0
                                             { MVM_JIT_REG_VAL,     type },
1050
0
                                             { is_name_direct ? MVM_JIT_STR_IDX : MVM_JIT_REG_VAL,
1051
0
                                                                    attrname },
1052
0
                                             { MVM_JIT_LITERAL,     attrhint },
1053
0
                                             { MVM_JIT_REG_VAL,     value },
1054
0
                                             { MVM_JIT_LITERAL,
1055
0
                                                 op == MVM_OP_bindattr_i || op == MVM_OP_bindattrs_i ? MVM_reg_int64 :
1056
0
                                                 op == MVM_OP_bindattr_n || op == MVM_OP_bindattrs_n ? MVM_reg_num64 :
1057
0
                                                 op == MVM_OP_bindattr_s || op == MVM_OP_bindattrs_s ? MVM_reg_str :
1058
0
                                                                        MVM_reg_obj } };
1059
0
                    MVM_jit_log(tc, "devirt: emitted a %s via jgb_consume_reprop\n", ins->info->name);
1060
0
                    jgb_append_call_c(tc, jgb, function, 9, args, MVM_JIT_RV_VOID, -1);
1061
0
1062
0
                    return 1;
1063
844
                } else {
1064
844
                    MVM_jit_log(tc, "devirt: couldn't %s; concreteness not sure\n", ins->info->name);
1065
844
                    break;
1066
844
                }
1067
844
            }
1068
10
            case MVM_OP_hintfor: {
1069
10
                /*
1070
10
                 *  MVMint64 (*hint_for) (MVMThreadContext *tc, MVMSTable *st,
1071
10
                 *      MVMObject *class_handle, MVMString *name);
1072
10
                 */
1073
10
1074
10
                MVMint32 result    = ins->operands[0].reg.orig;
1075
10
                MVMint32 type      = ins->operands[1].reg.orig;
1076
10
                MVMint32 attrname  = ins->operands[2].reg.orig;
1077
10
1078
10
                void *function = ((MVMObject*)type_facts->type)->st->REPR->attr_funcs.hint_for;
1079
10
1080
10
                MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
1081
10
                                         { MVM_JIT_REG_STABLE,  type },
1082
10
                                         { MVM_JIT_REG_VAL,     type },
1083
10
                                         { MVM_JIT_REG_VAL,     attrname } };
1084
10
1085
10
1086
10
                MVM_jit_log(tc, "devirt: emitted a %s via jgb_consume_reprop\n", ins->info->name);
1087
10
                jgb_append_call_c(tc, jgb, function, 4, args, MVM_JIT_RV_INT, result);
1088
10
                return 1;
1089
0
                break;
1090
844
            }
1091
13.2k
            case MVM_OP_push_i:
1092
13.2k
            case MVM_OP_push_n:
1093
13.2k
            case MVM_OP_push_s:
1094
13.2k
            case MVM_OP_push_o:
1095
13.2k
                alternative = 1;
1096
13.2k
            case MVM_OP_unshift_i:
1097
13.2k
            case MVM_OP_unshift_n:
1098
13.2k
            case MVM_OP_unshift_s:
1099
13.2k
            case MVM_OP_unshift_o: {
1100
13.2k
                MVMint32 invocant = ins->operands[0].reg.orig;
1101
13.2k
                MVMint32 value    = ins->operands[1].reg.orig;
1102
13.2k
1103
13.2k
                void *function = alternative
1104
13.2k
                    ? (void *)((MVMObject*)type_facts->type)->st->REPR->pos_funcs.push
1105
5
                    : (void *)((MVMObject*)type_facts->type)->st->REPR->pos_funcs.unshift;
1106
13.2k
1107
13.2k
                MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
1108
13.2k
                                         { MVM_JIT_REG_STABLE,  invocant },
1109
13.2k
                                         { MVM_JIT_REG_VAL,     invocant },
1110
13.2k
                                         { MVM_JIT_REG_OBJBODY, invocant },
1111
13.2k
                                         { MVM_JIT_REG_VAL,     value },
1112
13.2k
                                         { MVM_JIT_LITERAL,
1113
13.2k
                                             op == MVM_OP_push_i || op == MVM_OP_unshift_i ? MVM_reg_int64 :
1114
1.40k
                                             op == MVM_OP_push_n || op == MVM_OP_unshift_n ? MVM_reg_num64 :
1115
1.40k
                                             op == MVM_OP_push_s || op == MVM_OP_unshift_s ? MVM_reg_str :
1116
1.40k
                                                                    MVM_reg_obj } };
1117
13.2k
                jgb_append_call_c(tc, jgb, function, 6, args, MVM_JIT_RV_VOID, -1);
1118
13.2k
                MVM_jit_log(tc, "devirt: emitted a %s via jgb_consume_reprop\n", ins->info->name);
1119
13.2k
                return 1;
1120
13.2k
            }
1121
1.69k
            case MVM_OP_pop_i:
1122
1.69k
            case MVM_OP_pop_n:
1123
1.69k
            case MVM_OP_pop_s:
1124
1.69k
            case MVM_OP_pop_o:
1125
1.69k
                alternative = 1;
1126
1.81k
            case MVM_OP_shift_i:
1127
1.81k
            case MVM_OP_shift_n:
1128
1.81k
            case MVM_OP_shift_s:
1129
1.81k
            case MVM_OP_shift_o: {
1130
1.81k
                MVMint32 dst      = ins->operands[0].reg.orig;
1131
1.81k
                MVMint32 invocant = ins->operands[1].reg.orig;
1132
1.81k
1133
1.81k
                void *function = alternative
1134
1.69k
                    ? (void *)((MVMObject*)type_facts->type)->st->REPR->pos_funcs.pop
1135
123
                    : (void *)((MVMObject*)type_facts->type)->st->REPR->pos_funcs.shift;
1136
1.81k
1137
1.81k
                MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
1138
1.81k
                                         { MVM_JIT_REG_STABLE,  invocant },
1139
1.81k
                                         { MVM_JIT_REG_VAL,     invocant },
1140
1.81k
                                         { MVM_JIT_REG_OBJBODY, invocant },
1141
1.81k
                                         { MVM_JIT_REG_ADDR,     dst },
1142
1.81k
                                         { MVM_JIT_LITERAL,
1143
1.81k
                                             op == MVM_OP_pop_i || op == MVM_OP_shift_i ? MVM_reg_int64 :
1144
202
                                             op == MVM_OP_pop_n || op == MVM_OP_shift_n ? MVM_reg_num64 :
1145
202
                                             op == MVM_OP_pop_s || op == MVM_OP_shift_s ? MVM_reg_str :
1146
202
                                                                    MVM_reg_obj } };
1147
1.81k
                jgb_append_call_c(tc, jgb, function, 6, args, MVM_JIT_RV_VOID, -1);
1148
1.81k
                MVM_jit_log(tc, "devirt: emitted a %s via jgb_consume_reprop\n", ins->info->name);
1149
1.81k
                return 1;
1150
1.81k
            }
1151
873
            case MVM_OP_setelemspos: {
1152
873
                MVMint32 invocant = ins->operands[0].reg.orig;
1153
873
                MVMint32 amount   = ins->operands[1].reg.orig;
1154
873
1155
873
                void *function = ((MVMObject*)type_facts->type)->st->REPR->pos_funcs.set_elems;
1156
873
1157
873
                MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
1158
873
                                         { MVM_JIT_REG_STABLE,  invocant },
1159
873
                                         { MVM_JIT_REG_VAL,     invocant },
1160
873
                                         { MVM_JIT_REG_OBJBODY, invocant },
1161
873
                                         { MVM_JIT_REG_VAL,     amount } };
1162
873
                jgb_append_call_c(tc, jgb, function, 5, args, MVM_JIT_RV_VOID, -1);
1163
873
                MVM_jit_log(tc, "devirt: emitted a %s via jgb_consume_reprop\n", ins->info->name);
1164
873
                return 1;
1165
1.81k
            }
1166
402
            case MVM_OP_existskey: {
1167
402
                /*existskey           w(int64) r(obj) r(str) :pure*/
1168
402
                MVMint32 dst      = ins->operands[0].reg.orig;
1169
402
                MVMint32 invocant = ins->operands[1].reg.orig;
1170
402
                MVMint32 keyidx   = ins->operands[2].reg.orig;
1171
402
1172
402
                void *function = (void *)((MVMObject*)type_facts->type)->st->REPR->ass_funcs.exists_key;
1173
402
1174
402
                MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
1175
402
                                         { MVM_JIT_REG_STABLE,  invocant },
1176
402
                                         { MVM_JIT_REG_VAL,     invocant },
1177
402
                                         { MVM_JIT_REG_OBJBODY, invocant },
1178
402
                                         { MVM_JIT_REG_VAL,     keyidx } };
1179
402
                jgb_append_call_c(tc, jgb, function, 5, args, MVM_JIT_RV_INT, dst);
1180
402
                MVM_jit_log(tc, "devirt: emitted a %s via jgb_consume_reprop\n", ins->info->name);
1181
402
                return 1;
1182
1.81k
            }
1183
218
            default:
1184
218
                MVM_jit_log(tc, "devirt: please implement emitting repr op %s\n", ins->info->name);
1185
40.1k
        }
1186
19.7k
    } else {
1187
19.7k
        MVM_jit_log(tc, "devirt: repr op %s couldn't be devirtualized: type unknown\n", ins->info->name);
1188
19.7k
    }
1189
59.9k
1190
20.8k
skipdevirt:
1191
20.8k
1192
20.8k
    switch(op) {
1193
2.00k
    case MVM_OP_push_i:
1194
2.00k
    case MVM_OP_push_s:
1195
2.00k
    case MVM_OP_push_o:
1196
2.00k
    case MVM_OP_unshift_i:
1197
2.00k
    case MVM_OP_unshift_s:
1198
2.00k
    case MVM_OP_unshift_o: {
1199
2.00k
        MVMint32 invocant = ins->operands[0].reg.orig;
1200
2.00k
        MVMint32 value    = ins->operands[1].reg.orig;
1201
2.00k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1202
2.00k
                                 { MVM_JIT_REG_VAL, invocant },
1203
2.00k
                                 { MVM_JIT_REG_VAL, value } };
1204
2.00k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_VOID, -1);
1205
2.00k
        break;
1206
2.00k
    }
1207
0
    case MVM_OP_unshift_n:
1208
0
    case MVM_OP_push_n: {
1209
0
        MVMint32 invocant = ins->operands[0].reg.orig;
1210
0
        MVMint32 value    = ins->operands[1].reg.orig;
1211
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1212
0
                                 { MVM_JIT_REG_VAL, invocant },
1213
0
                                 { MVM_JIT_REG_VAL_F, value } };
1214
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_VOID, -1);
1215
0
        break;
1216
0
    }
1217
1.27k
    case MVM_OP_shift_s:
1218
1.27k
    case MVM_OP_pop_s:
1219
1.27k
    case MVM_OP_shift_o:
1220
1.27k
    case MVM_OP_pop_o: {
1221
1.27k
        MVMint16 dst = ins->operands[0].reg.orig;
1222
1.27k
        MVMint32 invocant = ins->operands[1].reg.orig;
1223
1.27k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1224
1.27k
                                 { MVM_JIT_REG_VAL, invocant } };
1225
1.27k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
1226
1.27k
        break;
1227
1.27k
    }
1228
129
    case MVM_OP_shift_i:
1229
129
    case MVM_OP_pop_i: {
1230
129
        MVMint16 dst = ins->operands[0].reg.orig;
1231
129
        MVMint32 invocant = ins->operands[1].reg.orig;
1232
129
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1233
129
                                 { MVM_JIT_REG_VAL, invocant } };
1234
129
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_INT, dst);
1235
129
        break;
1236
129
    }
1237
0
    case MVM_OP_shift_n:
1238
0
    case MVM_OP_pop_n: {
1239
0
        MVMint16 dst = ins->operands[0].reg.orig;
1240
0
        MVMint32 invocant = ins->operands[1].reg.orig;
1241
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1242
0
                                 { MVM_JIT_REG_VAL, invocant } };
1243
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_NUM, dst);
1244
0
        break;
1245
0
    }
1246
585
    case MVM_OP_deletekey:
1247
585
    case MVM_OP_setelemspos: {
1248
585
        MVMint32 invocant = ins->operands[0].reg.orig;
1249
585
        MVMint32 key_or_val = ins->operands[1].reg.orig;
1250
585
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1251
585
                                 { MVM_JIT_REG_VAL, invocant },
1252
585
                                 { MVM_JIT_REG_VAL, key_or_val } };
1253
585
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_VOID, -1);
1254
585
        break;
1255
585
    }
1256
171
    case MVM_OP_existskey: {
1257
171
        MVMint16 dst = ins->operands[0].reg.orig;
1258
171
        MVMint32 invocant = ins->operands[1].reg.orig;
1259
171
        MVMint32 key = ins->operands[2].reg.orig;
1260
171
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1261
171
                                 { MVM_JIT_REG_VAL, invocant },
1262
171
                                 { MVM_JIT_REG_VAL, key } };
1263
171
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_INT, dst);
1264
171
        break;
1265
585
    }
1266
131
    case MVM_OP_splice: {
1267
131
        MVMint16 invocant = ins->operands[0].reg.orig;
1268
131
        MVMint16 source = ins->operands[1].reg.orig;
1269
131
        MVMint16 offset = ins->operands[2].reg.orig;
1270
131
        MVMint16 count = ins->operands[3].reg.orig;
1271
131
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1272
131
                                 { MVM_JIT_REG_VAL, invocant },
1273
131
                                 { MVM_JIT_REG_VAL, source },
1274
131
                                 { MVM_JIT_REG_VAL, offset },
1275
131
                                 { MVM_JIT_REG_VAL, count } };
1276
131
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 5, args, MVM_JIT_RV_VOID, -1);
1277
131
        break;
1278
585
    }
1279
140
    case MVM_OP_existspos:
1280
140
    case MVM_OP_atkey_i:
1281
140
    case MVM_OP_atpos_i: {
1282
140
        MVMint16 dst = ins->operands[0].reg.orig;
1283
140
        MVMint32 invocant = ins->operands[1].reg.orig;
1284
140
        MVMint32 position = ins->operands[2].reg.orig;
1285
140
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1286
140
                                 { MVM_JIT_REG_VAL, invocant },
1287
140
                                 { MVM_JIT_REG_VAL, position } };
1288
140
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_INT, dst);
1289
140
        break;
1290
140
    }
1291
0
    case MVM_OP_atkey_n:
1292
0
    case MVM_OP_atpos_n: {
1293
0
        MVMint16 dst = ins->operands[0].reg.orig;
1294
0
        MVMint32 invocant = ins->operands[1].reg.orig;
1295
0
        MVMint32 position = ins->operands[2].reg.orig;
1296
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1297
0
                                 { MVM_JIT_REG_VAL, invocant },
1298
0
                                 { MVM_JIT_REG_VAL, position } };
1299
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_NUM, dst);
1300
0
        break;
1301
0
    }
1302
7.44k
    case MVM_OP_atpos_o:
1303
7.44k
    case MVM_OP_atkey_o:
1304
7.44k
    case MVM_OP_atkey_s:
1305
7.44k
    case MVM_OP_atpos_s: {
1306
7.44k
        MVMint16 dst = ins->operands[0].reg.orig;
1307
7.44k
        MVMint32 invocant = ins->operands[1].reg.orig;
1308
7.44k
        MVMint32 position = ins->operands[2].reg.orig;
1309
7.44k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1310
7.44k
                                 { MVM_JIT_REG_VAL, invocant },
1311
7.44k
                                 { MVM_JIT_REG_VAL, position } };
1312
7.44k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
1313
7.44k
        break;
1314
7.44k
    }
1315
2.90k
    case MVM_OP_bindpos_i:
1316
2.90k
    case MVM_OP_bindpos_n:
1317
2.90k
    case MVM_OP_bindpos_s:
1318
2.90k
    case MVM_OP_bindpos_o:
1319
2.90k
    case MVM_OP_bindkey_i:
1320
2.90k
    case MVM_OP_bindkey_n:
1321
2.90k
    case MVM_OP_bindkey_s:
1322
2.90k
    case MVM_OP_bindkey_o: {
1323
2.90k
        MVMint32 invocant = ins->operands[0].reg.orig;
1324
2.90k
        MVMint32 key_pos = ins->operands[1].reg.orig;
1325
2.90k
        MVMint32 value = ins->operands[2].reg.orig;
1326
2.90k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1327
2.90k
                                 { MVM_JIT_REG_VAL, invocant },
1328
2.90k
                                 { MVM_JIT_REG_VAL, key_pos },
1329
2.90k
                                 { op == MVM_OP_bindpos_n || op == MVM_OP_bindkey_n ? MVM_JIT_REG_VAL_F : MVM_JIT_REG_VAL, value } };
1330
2.90k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_VOID, -1);
1331
2.90k
        break;
1332
2.90k
    }
1333
2.41k
    case MVM_OP_getattr_i:
1334
2.41k
    case MVM_OP_getattr_n:
1335
2.41k
    case MVM_OP_getattr_s:
1336
2.41k
    case MVM_OP_getattr_o: {
1337
2.41k
        MVMuint16 kind = op == MVM_OP_getattr_i ? MVM_JIT_RV_INT :
1338
1.25k
                         op == MVM_OP_getattr_n ? MVM_JIT_RV_NUM :
1339
1.25k
                         op == MVM_OP_getattr_s ? MVM_JIT_RV_PTR :
1340
729
                         /* MVM_OP_getattr_o ? */ MVM_JIT_RV_PTR;
1341
2.41k
        MVMint16 dst = ins->operands[0].reg.orig;
1342
2.41k
        MVMint16 obj = ins->operands[1].reg.orig;
1343
2.41k
        MVMint16 typ = ins->operands[2].reg.orig;
1344
2.41k
        MVMuint32 str_idx = ins->operands[3].lit_str_idx;
1345
2.41k
        MVMint16 hint = ins->operands[4].lit_i16;
1346
2.41k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1347
2.41k
                                 { MVM_JIT_REG_VAL, obj },
1348
2.41k
                                 { MVM_JIT_REG_VAL, typ },
1349
2.41k
                                 { MVM_JIT_STR_IDX, str_idx },
1350
2.41k
                                 { MVM_JIT_LITERAL, hint }};
1351
2.41k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 5, args, kind, dst);
1352
2.41k
        break;
1353
2.41k
    }
1354
0
    case MVM_OP_getattrs_i:
1355
0
    case MVM_OP_getattrs_n:
1356
0
    case MVM_OP_getattrs_s:
1357
0
    case MVM_OP_getattrs_o: {
1358
0
        MVMuint16 kind = op == MVM_OP_getattrs_i ? MVM_JIT_RV_INT :
1359
0
                         op == MVM_OP_getattrs_n ? MVM_JIT_RV_NUM :
1360
0
                         op == MVM_OP_getattrs_s ? MVM_JIT_RV_PTR :
1361
0
                         /* MVM_OP_getattrs_o ? */ MVM_JIT_RV_PTR;
1362
0
        MVMint16 dst = ins->operands[0].reg.orig;
1363
0
        MVMint16 obj = ins->operands[1].reg.orig;
1364
0
        MVMint16 typ = ins->operands[2].reg.orig;
1365
0
        MVMint16 str = ins->operands[3].reg.orig;
1366
0
        MVMint16 hint = -1;
1367
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1368
0
                                 { MVM_JIT_REG_VAL, obj },
1369
0
                                 { MVM_JIT_REG_VAL, typ },
1370
0
                                 { MVM_JIT_REG_VAL, str },
1371
0
                                 { MVM_JIT_LITERAL, hint }};
1372
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 5, args, kind, dst);
1373
0
        break;
1374
0
    }
1375
0
    case MVM_OP_attrinited: {
1376
0
        MVMint32 dst       = ins->operands[0].reg.orig;
1377
0
        MVMint32 invocant  = ins->operands[1].reg.orig;
1378
0
        MVMint32 type      = ins->operands[2].reg.orig;
1379
0
        MVMint32 attrname  = ins->operands[3].reg.orig;
1380
0
1381
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1382
0
                                 { MVM_JIT_REG_VAL, invocant },
1383
0
                                 { MVM_JIT_REG_VAL, type },
1384
0
                                 { MVM_JIT_REG_VAL, attrname } };
1385
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_INT, dst);
1386
0
        break;
1387
0
    }
1388
1.94k
    case MVM_OP_bindattr_i:
1389
1.94k
    case MVM_OP_bindattr_n:
1390
1.94k
    case MVM_OP_bindattr_s:
1391
1.94k
    case MVM_OP_bindattr_o: {
1392
1.94k
        MVMint16 obj = ins->operands[0].reg.orig;
1393
1.94k
        MVMint16 typ = ins->operands[1].reg.orig;
1394
1.94k
        MVMuint32 str_idx = ins->operands[2].lit_str_idx;
1395
1.94k
        MVMint16 val = ins->operands[3].reg.orig;
1396
1.94k
        MVMint16 hint = ins->operands[4].lit_i16;
1397
1.94k
        MVMuint16 kind = op == MVM_OP_bindattr_i ? MVM_reg_int64 :
1398
1.54k
                         op == MVM_OP_bindattr_n ? MVM_reg_num64 :
1399
1.54k
                         op == MVM_OP_bindattr_s ? MVM_reg_str :
1400
1.54k
                         /* MVM_OP_bindattr_o ? */ MVM_reg_obj;
1401
1.94k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1402
1.94k
                                 { MVM_JIT_REG_VAL, obj },
1403
1.94k
                                 { MVM_JIT_REG_VAL, typ },
1404
1.94k
                                 { MVM_JIT_STR_IDX, str_idx },
1405
1.94k
                                 { MVM_JIT_LITERAL, hint },
1406
1.94k
                                 { MVM_JIT_REG_VAL, val }, /* Takes MVMRegister, so no _F needed. */
1407
1.94k
                                 { MVM_JIT_LITERAL, kind } };
1408
1.94k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 7, args, MVM_JIT_RV_VOID, -1);
1409
1.94k
        break;
1410
1.94k
    }
1411
236
    case MVM_OP_bindattrs_i:
1412
236
    case MVM_OP_bindattrs_n:
1413
236
    case MVM_OP_bindattrs_s:
1414
236
    case MVM_OP_bindattrs_o: {
1415
236
        MVMint16 obj = ins->operands[0].reg.orig;
1416
236
        MVMint16 typ = ins->operands[1].reg.orig;
1417
236
        MVMint16 str = ins->operands[2].reg.orig;
1418
236
        MVMint16 val = ins->operands[3].reg.orig;
1419
236
        MVMint16 hint = -1;
1420
236
        MVMuint16 kind = op == MVM_OP_bindattrs_i ? MVM_reg_int64 :
1421
0
                         op == MVM_OP_bindattrs_n ? MVM_reg_num64 :
1422
0
                         op == MVM_OP_bindattrs_s ? MVM_reg_str :
1423
0
                         /* MVM_OP_bindattrs_o ? */ MVM_reg_obj;
1424
236
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1425
236
                                 { MVM_JIT_REG_VAL, obj },
1426
236
                                 { MVM_JIT_REG_VAL, typ },
1427
236
                                 { MVM_JIT_REG_VAL, str },
1428
236
                                 { MVM_JIT_LITERAL, hint },
1429
236
                                 { MVM_JIT_REG_VAL, val }, /* Takes MVMRegister, so no _F needed. */
1430
236
                                 { MVM_JIT_LITERAL, kind } };
1431
236
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 7, args, MVM_JIT_RV_VOID, -1);
1432
236
        break;
1433
236
    }
1434
1
    case MVM_OP_hintfor: {
1435
1
        MVMint16 dst      = ins->operands[0].reg.orig;
1436
1
        MVMint32 type     = ins->operands[1].reg.orig;
1437
1
        MVMint32 attrname = ins->operands[2].reg.orig;
1438
1
1439
1
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  MVM_JIT_INTERP_TC },
1440
1
                                 { MVM_JIT_REG_VAL,     type },
1441
1
                                 { MVM_JIT_REG_VAL,     attrname } };
1442
1
1443
1
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_INT, dst);
1444
1
        break;
1445
236
    }
1446
1.42k
    case MVM_OP_elems: {
1447
1.42k
        MVMint16 dst = ins->operands[0].reg.orig;
1448
1.42k
        MVMint32 invocant = ins->operands[1].reg.orig;
1449
1.42k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
1450
1.42k
                                 { MVM_JIT_REG_VAL, invocant } };
1451
1.42k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_INT, dst);
1452
1.42k
        break;
1453
236
    }
1454
0
    default:
1455
0
        return 0;
1456
20.8k
    }
1457
20.8k
1458
20.8k
    return 1;
1459
20.8k
}
1460
1461
static MVMint32 jgb_consume_ins(MVMThreadContext *tc, JitGraphBuilder *jgb,
1462
930k
                                MVMSpeshBB *bb, MVMSpeshIns *ins) {
1463
930k
    MVMint16 op = ins->info->opcode;
1464
930k
    MVM_jit_log(tc, "append_ins: <%s>\n", ins->info->name);
1465
930k
    switch(op) {
1466
224k
    case MVM_SSA_PHI:
1467
224k
    case MVM_OP_no_op:
1468
224k
        break;
1469
224k
        /* arithmetic */
1470
428k
    case MVM_OP_add_i:
1471
428k
    case MVM_OP_sub_i:
1472
428k
    case MVM_OP_mul_i:
1473
428k
    case MVM_OP_div_i:
1474
428k
    case MVM_OP_mod_i:
1475
428k
    case MVM_OP_inc_i:
1476
428k
    case MVM_OP_dec_i:
1477
428k
    case MVM_OP_neg_i:
1478
428k
    case MVM_OP_band_i:
1479
428k
    case MVM_OP_bor_i:
1480
428k
    case MVM_OP_bxor_i:
1481
428k
    case MVM_OP_bnot_i:
1482
428k
    case MVM_OP_blshift_i:
1483
428k
    case MVM_OP_brshift_i:
1484
428k
    case MVM_OP_add_n:
1485
428k
    case MVM_OP_sub_n:
1486
428k
    case MVM_OP_mul_n:
1487
428k
    case MVM_OP_div_n:
1488
428k
    case MVM_OP_neg_n:
1489
428k
        /* number coercion */
1490
428k
    case MVM_OP_coerce_ni:
1491
428k
    case MVM_OP_coerce_in:
1492
428k
        /* comparison (integer) */
1493
428k
    case MVM_OP_eq_i:
1494
428k
    case MVM_OP_ne_i:
1495
428k
    case MVM_OP_lt_i:
1496
428k
    case MVM_OP_le_i:
1497
428k
    case MVM_OP_gt_i:
1498
428k
    case MVM_OP_ge_i:
1499
428k
    case MVM_OP_cmp_i:
1500
428k
        /* comparison (numbers) */
1501
428k
    case MVM_OP_eq_n:
1502
428k
    case MVM_OP_ne_n:
1503
428k
    case MVM_OP_ge_n:
1504
428k
    case MVM_OP_gt_n:
1505
428k
    case MVM_OP_lt_n:
1506
428k
    case MVM_OP_le_n:
1507
428k
    case MVM_OP_cmp_n:
1508
428k
        /* comparison (objects) */
1509
428k
    case MVM_OP_eqaddr:
1510
428k
    case MVM_OP_isconcrete:
1511
428k
        /* comparison (big integer) */
1512
428k
    case MVM_OP_eq_I:
1513
428k
    case MVM_OP_ne_I:
1514
428k
    case MVM_OP_lt_I:
1515
428k
    case MVM_OP_le_I:
1516
428k
    case MVM_OP_gt_I:
1517
428k
    case MVM_OP_ge_I:
1518
428k
        /* constants */
1519
428k
    case MVM_OP_const_i64_16:
1520
428k
    case MVM_OP_const_i64_32:
1521
428k
    case MVM_OP_const_i64:
1522
428k
    case MVM_OP_const_n64:
1523
428k
    case MVM_OP_nan:
1524
428k
    case MVM_OP_const_s:
1525
428k
    case MVM_OP_null:
1526
428k
        /* argument reading */
1527
428k
    case MVM_OP_sp_getarg_i:
1528
428k
    case MVM_OP_sp_getarg_o:
1529
428k
    case MVM_OP_sp_getarg_n:
1530
428k
    case MVM_OP_sp_getarg_s:
1531
428k
        /* accessors */
1532
428k
    case MVM_OP_sp_p6oget_o:
1533
428k
    case MVM_OP_sp_p6oget_s:
1534
428k
    case MVM_OP_sp_p6oget_i:
1535
428k
    case MVM_OP_sp_p6oget_n:
1536
428k
    case MVM_OP_sp_p6ogetvc_o:
1537
428k
    case MVM_OP_sp_p6ogetvt_o:
1538
428k
    case MVM_OP_sp_p6obind_i:
1539
428k
    case MVM_OP_sp_p6obind_n:
1540
428k
    case MVM_OP_sp_p6obind_s:
1541
428k
    case MVM_OP_sp_p6obind_o:
1542
428k
    case MVM_OP_sp_bind_i64:
1543
428k
    case MVM_OP_sp_bind_n:
1544
428k
    case MVM_OP_sp_bind_s:
1545
428k
    case MVM_OP_sp_bind_o:
1546
428k
    case MVM_OP_sp_get_i64:
1547
428k
    case MVM_OP_sp_get_n:
1548
428k
    case MVM_OP_sp_get_s:
1549
428k
    case MVM_OP_sp_get_o:
1550
428k
    case MVM_OP_sp_deref_bind_i64:
1551
428k
    case MVM_OP_sp_deref_bind_n:
1552
428k
    case MVM_OP_sp_deref_get_i64:
1553
428k
    case MVM_OP_sp_deref_get_n:
1554
428k
    case MVM_OP_set:
1555
428k
    case MVM_OP_getlex:
1556
428k
    case MVM_OP_getlex_no:
1557
428k
    case MVM_OP_bindlex:
1558
428k
    case MVM_OP_getwhat:
1559
428k
    case MVM_OP_getwho:
1560
428k
    case MVM_OP_getwhere:
1561
428k
    case MVM_OP_sp_getspeshslot:
1562
428k
    case MVM_OP_takedispatcher:
1563
428k
    case MVM_OP_setdispatcher:
1564
428k
    case MVM_OP_curcode:
1565
428k
    case MVM_OP_getcode:
1566
428k
    case MVM_OP_callercode:
1567
428k
    case MVM_OP_sp_fastcreate:
1568
428k
    case MVM_OP_iscont:
1569
428k
    case MVM_OP_decont:
1570
428k
    case MVM_OP_sp_namedarg_used:
1571
428k
    case MVM_OP_sp_findmeth:
1572
428k
    case MVM_OP_hllboxtype_i:
1573
428k
    case MVM_OP_hllboxtype_n:
1574
428k
    case MVM_OP_hllboxtype_s:
1575
428k
    case MVM_OP_null_s:
1576
428k
    case MVM_OP_isnull_s:
1577
428k
    case MVM_OP_not_i:
1578
428k
    case MVM_OP_isnull:
1579
428k
    case MVM_OP_isnonnull:
1580
428k
    case MVM_OP_isint:
1581
428k
    case MVM_OP_isnum:
1582
428k
    case MVM_OP_isstr:
1583
428k
    case MVM_OP_islist:
1584
428k
    case MVM_OP_ishash:
1585
428k
    case MVM_OP_sp_boolify_iter_arr:
1586
428k
    case MVM_OP_sp_boolify_iter_hash:
1587
428k
    case MVM_OP_objprimspec:
1588
428k
    case MVM_OP_objprimbits:
1589
428k
    case MVM_OP_takehandlerresult:
1590
428k
    case MVM_OP_lexoticresult:
1591
428k
    case MVM_OP_exception:
1592
428k
    case MVM_OP_scwbdisable:
1593
428k
    case MVM_OP_scwbenable:
1594
428k
    case MVM_OP_assign:
1595
428k
    case MVM_OP_assignunchecked:
1596
428k
    case MVM_OP_getlexstatic_o:
1597
428k
    case MVM_OP_getlexperinvtype_o:
1598
428k
    case MVM_OP_paramnamesused:
1599
428k
    case MVM_OP_assertparamcheck:
1600
428k
    case MVM_OP_getobjsc:
1601
428k
    case MVM_OP_getstderr:
1602
428k
    case MVM_OP_getstdout:
1603
428k
    case MVM_OP_getstdin:
1604
428k
    case MVM_OP_ordat:
1605
428k
    case MVM_OP_ordfirst:
1606
428k
        /* Profiling */
1607
428k
    case MVM_OP_prof_enterspesh:
1608
428k
    case MVM_OP_prof_enterinline:
1609
428k
    case MVM_OP_invokewithcapture:
1610
428k
    case MVM_OP_captureposelems:
1611
428k
    case MVM_OP_capturehasnameds:
1612
428k
        /* Exception handling */
1613
428k
    case MVM_OP_lastexpayload:
1614
428k
1615
428k
        jgb_append_primitive(tc, jgb, ins);
1616
428k
        break;
1617
428k
        /* branches */
1618
98.4k
    case MVM_OP_goto:
1619
98.4k
    case MVM_OP_if_i:
1620
98.4k
    case MVM_OP_unless_i:
1621
98.4k
    case MVM_OP_if_n:
1622
98.4k
    case MVM_OP_unless_n:
1623
98.4k
    case MVM_OP_ifnonnull:
1624
98.4k
    case MVM_OP_indexat:
1625
98.4k
    case MVM_OP_indexnat:
1626
98.4k
    case MVM_OP_if_s0:
1627
98.4k
    case MVM_OP_unless_s0:
1628
98.4k
        jgb_append_branch(tc, jgb, 0, ins);
1629
98.4k
        break;
1630
3.79k
    case MVM_OP_if_o:
1631
3.79k
    case MVM_OP_unless_o: {
1632
3.79k
        /* Very special / funky branches. The function involved in
1633
3.79k
         * making this decision - namely, MVM_coerse_istrue - expects
1634
3.79k
         * to take a return register address /or/ two bytecode
1635
3.79k
         * addresses.  This is a reasonable decision with regards to
1636
3.79k
         * invocation nesting in the interpreter, but not for the
1637
3.79k
         * JIT. Hence, we will transform this into the istrue /
1638
3.79k
         * isfalse primitive combined with the if_i branch. A special
1639
3.79k
         * problem is that there really isn't any 'real' work space
1640
3.79k
         * available to store the result. Instead, we'll use the
1641
3.79k
         * args space to store and read the result */
1642
3.79k
        MVMint16 obj = ins->operands[0].reg.orig;
1643
3.79k
        /* Assign the very last register allocated */
1644
3.79k
        MVMint16 dst = jgb->sg->num_locals + jgb->sg->sf->body.cu->body.max_callsite_size - 1;
1645
3.79k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1646
3.79k
                                 { MVM_JIT_REG_VAL,  { obj } },
1647
3.79k
                                 { MVM_JIT_REG_ADDR, { dst } }, /* destination register (in args space) */
1648
3.79k
                                 { MVM_JIT_LITERAL, { 0 } }, /* true code */
1649
3.79k
                                 { MVM_JIT_LITERAL, { 0 } }, /* false code */
1650
3.79k
                                 { MVM_JIT_LITERAL, { op == MVM_OP_unless_o } }}; /* switch */
1651
3.79k
        MVMSpeshIns * branch = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMSpeshIns));
1652
3.79k
        if (dst + 1 <= jgb->sg->num_locals) {
1653
0
            MVM_oops(tc, "JIT: no space in args buffer to store"
1654
0
                     " temporary result for <%s>", ins->info->name);
1655
0
        }
1656
3.79k
        /* This is now necessary for the invokish control to work correctly */
1657
3.79k
        jgb_append_control(tc, jgb, ins, MVM_JIT_CONTROL_THROWISH_PRE);
1658
3.79k
        jgb_append_call_c(tc, jgb, op_to_func(tc, MVM_OP_istrue), 6,
1659
3.79k
                          args, MVM_JIT_RV_VOID, -1);
1660
3.79k
        /* guard the potential invoke */
1661
3.79k
        jgb_append_control(tc, jgb, ins, MVM_JIT_CONTROL_INVOKISH);
1662
3.79k
        /* branch if true (switch is done by coercion) */
1663
3.79k
        branch->info = MVM_op_get_op(MVM_OP_if_i);
1664
3.79k
        branch->operands = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMSpeshOperand) * 2);
1665
3.79k
        branch->operands[0].reg.orig = dst;
1666
3.79k
        branch->operands[1].ins_bb = ins->operands[1].ins_bb;
1667
3.79k
        jgb_append_branch(tc, jgb, 0, branch);
1668
3.79k
        break;
1669
3.79k
    }
1670
3.79k
        /* some functions */
1671
122
    case MVM_OP_gethow: {
1672
122
        MVMint16 dst = ins->operands[0].reg.orig;
1673
122
        MVMint16 obj = ins->operands[1].reg.orig;
1674
122
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1675
122
                                 { MVM_JIT_REG_VAL, { obj } } };
1676
122
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
1677
122
        break;
1678
3.79k
    }
1679
1.12k
    case MVM_OP_istype: {
1680
1.12k
        MVMint16 dst = ins->operands[0].reg.orig;
1681
1.12k
        MVMint16 obj = ins->operands[1].reg.orig;
1682
1.12k
        MVMint16 type = ins->operands[2].reg.orig;
1683
1.12k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1684
1.12k
                                 { MVM_JIT_REG_VAL, { obj } },
1685
1.12k
                                 { MVM_JIT_REG_VAL, { type } },
1686
1.12k
                                 { MVM_JIT_REG_ADDR, { dst } }};
1687
1.12k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_VOID, -1);
1688
1.12k
        break;
1689
3.79k
    }
1690
5
    case MVM_OP_gethllsym: {
1691
5
        MVMint16 dst = ins->operands[0].reg.orig;
1692
5
        MVMint16 hll = ins->operands[1].reg.orig;
1693
5
        MVMint16 sym = ins->operands[2].reg.orig;
1694
5
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1695
5
                                 { MVM_JIT_REG_VAL, { hll } },
1696
5
                                 { MVM_JIT_REG_VAL, { sym } } };
1697
5
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
1698
5
        break;
1699
3.79k
    }
1700
327
    case MVM_OP_checkarity: {
1701
327
        MVMuint16 min = ins->operands[0].lit_i16;
1702
327
        MVMuint16 max = ins->operands[1].lit_i16;
1703
327
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1704
327
                                 { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_PARAMS } },
1705
327
                                 { MVM_JIT_LITERAL, { min } },
1706
327
                                 { MVM_JIT_LITERAL, { max } } };
1707
327
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_VOID, -1);
1708
327
        break;
1709
3.79k
    }
1710
0
    case MVM_OP_say:
1711
0
    case MVM_OP_print: {
1712
0
        MVMint32 reg = ins->operands[0].reg.orig;
1713
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1714
0
                                 { MVM_JIT_REG_VAL, { reg } } };
1715
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_VOID, -1);
1716
0
        break;
1717
0
    }
1718
23.1k
    case MVM_OP_wval:
1719
23.1k
    case MVM_OP_wval_wide: {
1720
23.1k
        MVMint16 dst = ins->operands[0].reg.orig;
1721
23.1k
        MVMint16 dep = ins->operands[1].lit_i16;
1722
23.1k
        MVMint64 idx = op == MVM_OP_wval
1723
23.1k
            ? ins->operands[2].lit_i16
1724
0
            : ins->operands[2].lit_i64;
1725
23.1k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1726
23.1k
                                 { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_CU } },
1727
23.1k
                                 { MVM_JIT_LITERAL, { dep } },
1728
23.1k
                                 { MVM_JIT_LITERAL, { idx } } };
1729
23.1k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_PTR, dst);
1730
23.1k
        break;
1731
23.1k
    }
1732
10
    case MVM_OP_scgetobjidx: {
1733
10
        MVMint16 dst = ins->operands[0].reg.orig;
1734
10
        MVMint16 sc  = ins->operands[1].reg.orig;
1735
10
        MVMint64 obj = ins->operands[2].reg.orig;
1736
10
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1737
10
                                 { MVM_JIT_REG_VAL, { sc } },
1738
10
                                 { MVM_JIT_REG_VAL, { obj } } };
1739
10
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_INT, dst);
1740
10
        break;
1741
23.1k
    }
1742
0
    case MVM_OP_throwdyn:
1743
0
    case MVM_OP_throwlex:
1744
0
    case MVM_OP_throwlexotic: {
1745
0
        MVMint16 regi   = ins->operands[0].reg.orig;
1746
0
        MVMint16 object = ins->operands[1].reg.orig;
1747
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1748
0
                                 { MVM_JIT_LITERAL, {
1749
0
                                   op == MVM_OP_throwlexotic ? MVM_EX_THROW_LEXOTIC :
1750
0
                                   op == MVM_OP_throwlex     ? MVM_EX_THROW_LEX :
1751
0
                                                               MVM_EX_THROW_DYN
1752
0
                                   } },
1753
0
                                 { MVM_JIT_REG_VAL, { object } },
1754
0
                                 { MVM_JIT_REG_ADDR, { regi } }};
1755
0
1756
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op),
1757
0
                          4, args, MVM_JIT_RV_VOID, -1);
1758
0
        break;
1759
0
    }
1760
0
    case MVM_OP_rethrow: {
1761
0
        MVMint16 obj = ins->operands[0].reg.orig;
1762
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1763
0
                                 { MVM_JIT_LITERAL, { MVM_EX_THROW_DYN } },
1764
0
                                 { MVM_JIT_REG_VAL, { obj } },
1765
0
                                 { MVM_JIT_LITERAL, { 0 } } };
1766
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_VOID, -1);
1767
0
        break;
1768
0
    }
1769
12
    case MVM_OP_throwcatdyn:
1770
12
    case MVM_OP_throwcatlex:
1771
12
    case MVM_OP_throwcatlexotic: {
1772
12
        MVMint16 regi     = ins->operands[0].reg.orig;
1773
12
        MVMint32 category = (MVMuint32)ins->operands[1].lit_i64;
1774
12
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1775
12
                                 { MVM_JIT_LITERAL, {
1776
12
                                   op == MVM_OP_throwcatdyn ? MVM_EX_THROW_DYN :
1777
0
                                   op == MVM_OP_throwcatlex ? MVM_EX_THROW_LEX :
1778
0
                                                              MVM_EX_THROW_LEXOTIC
1779
12
                                   } },
1780
12
                                 { MVM_JIT_LITERAL, { category } },
1781
12
                                 { MVM_JIT_REG_ADDR, { regi } }};
1782
12
        jgb_append_call_c(tc, jgb, op_to_func(tc, op),
1783
12
                          4, args, MVM_JIT_RV_VOID, -1);
1784
12
        break;
1785
12
    }
1786
0
    case MVM_OP_resume: {
1787
0
        MVMint16 exc = ins->operands[0].reg.orig;
1788
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1789
0
                                 { MVM_JIT_REG_VAL, { exc } } };
1790
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_VOID, -1);
1791
0
        break;
1792
12
    }
1793
1.80k
    case MVM_OP_die: {
1794
1.80k
        MVMint16 dst = ins->operands[0].reg.orig;
1795
1.80k
        MVMint16 str = ins->operands[1].reg.orig;
1796
1.80k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1797
1.80k
                                 { MVM_JIT_REG_VAL, { str } },
1798
1.80k
                                 { MVM_JIT_REG_ADDR, { dst } }};
1799
1.80k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op),
1800
1.80k
                          3, args, MVM_JIT_RV_VOID, -1);
1801
1.80k
        break;
1802
12
    }
1803
1.05k
    case MVM_OP_getdynlex: {
1804
1.05k
        MVMint16 dst = ins->operands[0].reg.orig;
1805
1.05k
        MVMint16 name = ins->operands[1].reg.orig;
1806
1.05k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1807
1.05k
                                 { MVM_JIT_REG_VAL, { name } },
1808
1.05k
                                 { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_CALLER } }};
1809
1.05k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
1810
1.05k
        break;
1811
12
    }
1812
18
    case MVM_OP_binddynlex: {
1813
18
        MVMint16 name = ins->operands[0].reg.orig;
1814
18
        MVMint16 val  = ins->operands[1].reg.orig;
1815
18
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1816
18
                                 { MVM_JIT_REG_VAL, { name } },
1817
18
                                 { MVM_JIT_REG_VAL, { val }  },
1818
18
                                 { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_CALLER } }};
1819
18
        jgb_append_call_c(tc, jgb, op_to_func(tc, op),
1820
18
                          4, args, MVM_JIT_RV_VOID, -1);
1821
18
        break;
1822
12
    }
1823
0
    case MVM_OP_getlexouter: {
1824
0
        MVMint16 dst  = ins->operands[0].reg.orig;
1825
0
        MVMint16 name = ins->operands[1].reg.orig;
1826
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1827
0
                                 { MVM_JIT_REG_VAL, { name } }};
1828
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
1829
0
        break;
1830
12
    }
1831
588
    case MVM_OP_isfalse:
1832
588
    case MVM_OP_istrue: {
1833
588
        MVMint16 obj = ins->operands[1].reg.orig;
1834
588
        MVMint16 dst = ins->operands[0].reg.orig;
1835
588
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1836
588
                                 { MVM_JIT_REG_VAL,  { obj } },
1837
588
                                 { MVM_JIT_REG_ADDR, { dst } },
1838
588
                                 { MVM_JIT_LITERAL, { 0 } },
1839
588
                                 { MVM_JIT_LITERAL, { 0 } },
1840
588
                                 { MVM_JIT_LITERAL, { op == MVM_OP_isfalse } }};
1841
588
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 6, args, MVM_JIT_RV_VOID, -1);
1842
588
        break;
1843
588
    }
1844
0
    case MVM_OP_capturelex: {
1845
0
        MVMint16 code = ins->operands[0].reg.orig;
1846
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1847
0
                                 { MVM_JIT_REG_VAL, { code } } };
1848
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_VOID, -1);
1849
0
        break;
1850
588
    }
1851
682
    case MVM_OP_takeclosure: {
1852
682
        MVMint16 dst = ins->operands[0].reg.orig;
1853
682
        MVMint16 src = ins->operands[1].reg.orig;
1854
682
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1855
682
                                 { MVM_JIT_REG_VAL, { src } } };
1856
682
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
1857
682
        break;
1858
588
    }
1859
0
    case MVM_OP_newlexotic: {
1860
0
        MVMint16 dst = ins->operands[0].reg.orig;
1861
0
        MVMint32 label = get_label_for_bb(tc, jgb, ins->operands[1].ins_bb);
1862
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1863
0
                                 { MVM_JIT_LITERAL, { label } } };
1864
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
1865
0
        break;
1866
588
    }
1867
0
    case MVM_OP_usecapture:
1868
0
    case MVM_OP_savecapture: {
1869
0
        MVMint16 dst = ins->operands[0].reg.orig;
1870
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1871
0
                                 { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_FRAME } }};
1872
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
1873
0
        break;
1874
0
    }
1875
0
    case MVM_OP_captureposprimspec: {
1876
0
        MVMint16 dst     = ins->operands[0].reg.orig;
1877
0
        MVMint16 capture = ins->operands[1].reg.orig;
1878
0
        MVMint16 index   = ins->operands[2].reg.orig;
1879
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1880
0
                                 { MVM_JIT_REG_VAL, { capture } },
1881
0
                                 { MVM_JIT_REG_VAL, { index } } };
1882
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_INT, dst);
1883
0
        break;
1884
0
    }
1885
10
    case MVM_OP_gt_s:
1886
10
    case MVM_OP_ge_s:
1887
10
    case MVM_OP_lt_s:
1888
10
    case MVM_OP_le_s:
1889
10
    case MVM_OP_cmp_s: {
1890
10
        MVMint16 dst = ins->operands[0].reg.orig;
1891
10
        MVMint16 a   = ins->operands[1].reg.orig;
1892
10
        MVMint16 b   = ins->operands[2].reg.orig;
1893
10
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1894
10
                                 { MVM_JIT_REG_VAL, { a } },
1895
10
                                 { MVM_JIT_REG_VAL, { b } }};
1896
10
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_INT, dst);
1897
10
        /* We rely on an implementation of the comparisons against -1, 0 and 1
1898
10
         * in emit.dasc */
1899
10
        if (op != MVM_OP_cmp_s)
1900
10
            jgb_append_primitive(tc, jgb, ins);
1901
10
        break;
1902
10
    }
1903
0
    case MVM_OP_hllize: {
1904
0
        MVMint16 dst = ins->operands[0].reg.orig;
1905
0
        MVMint16 src = ins->operands[1].reg.orig;
1906
0
        MVMHLLConfig *hll_config = jgb->sg->sf->body.cu->body.hll_config;
1907
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1908
0
                                 { MVM_JIT_REG_VAL, { src } },
1909
0
                                 { MVM_JIT_LITERAL_PTR, { (MVMint64)hll_config } },
1910
0
                                 { MVM_JIT_REG_ADDR, { dst } }};
1911
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_VOID, -1);
1912
0
        break;
1913
10
    }
1914
248
    case MVM_OP_clone: {
1915
248
        MVMint16 dst = ins->operands[0].reg.orig;
1916
248
        MVMint16 obj = ins->operands[1].reg.orig;
1917
248
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1918
248
                                 { MVM_JIT_REG_VAL, { obj } } };
1919
248
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
1920
248
        break;
1921
10
    }
1922
10
        /* repr ops */
1923
59.9k
    case MVM_OP_unshift_i:
1924
59.9k
    case MVM_OP_unshift_n:
1925
59.9k
    case MVM_OP_unshift_s:
1926
59.9k
    case MVM_OP_unshift_o:
1927
59.9k
    case MVM_OP_push_i:
1928
59.9k
    case MVM_OP_push_n:
1929
59.9k
    case MVM_OP_push_s:
1930
59.9k
    case MVM_OP_push_o:
1931
59.9k
    case MVM_OP_shift_i:
1932
59.9k
    case MVM_OP_shift_n:
1933
59.9k
    case MVM_OP_shift_s:
1934
59.9k
    case MVM_OP_shift_o:
1935
59.9k
    case MVM_OP_pop_i:
1936
59.9k
    case MVM_OP_pop_n:
1937
59.9k
    case MVM_OP_pop_s:
1938
59.9k
    case MVM_OP_pop_o:
1939
59.9k
    case MVM_OP_deletekey:
1940
59.9k
    case MVM_OP_existskey:
1941
59.9k
    case MVM_OP_existspos:
1942
59.9k
    case MVM_OP_setelemspos:
1943
59.9k
    case MVM_OP_splice:
1944
59.9k
    case MVM_OP_atpos_i:
1945
59.9k
    case MVM_OP_atpos_n:
1946
59.9k
    case MVM_OP_atpos_s:
1947
59.9k
    case MVM_OP_atpos_o:
1948
59.9k
    case MVM_OP_atkey_i:
1949
59.9k
    case MVM_OP_atkey_n:
1950
59.9k
    case MVM_OP_atkey_s:
1951
59.9k
    case MVM_OP_atkey_o:
1952
59.9k
    case MVM_OP_bindpos_i:
1953
59.9k
    case MVM_OP_bindpos_n:
1954
59.9k
    case MVM_OP_bindpos_s:
1955
59.9k
    case MVM_OP_bindpos_o:
1956
59.9k
    case MVM_OP_bindkey_i:
1957
59.9k
    case MVM_OP_bindkey_n:
1958
59.9k
    case MVM_OP_bindkey_s:
1959
59.9k
    case MVM_OP_bindkey_o:
1960
59.9k
    case MVM_OP_getattr_i:
1961
59.9k
    case MVM_OP_getattr_n:
1962
59.9k
    case MVM_OP_getattr_s:
1963
59.9k
    case MVM_OP_getattr_o:
1964
59.9k
    case MVM_OP_getattrs_i:
1965
59.9k
    case MVM_OP_getattrs_n:
1966
59.9k
    case MVM_OP_getattrs_s:
1967
59.9k
    case MVM_OP_getattrs_o:
1968
59.9k
    case MVM_OP_attrinited:
1969
59.9k
    case MVM_OP_bindattr_i:
1970
59.9k
    case MVM_OP_bindattr_n:
1971
59.9k
    case MVM_OP_bindattr_s:
1972
59.9k
    case MVM_OP_bindattr_o:
1973
59.9k
    case MVM_OP_bindattrs_i:
1974
59.9k
    case MVM_OP_bindattrs_n:
1975
59.9k
    case MVM_OP_bindattrs_s:
1976
59.9k
    case MVM_OP_bindattrs_o:
1977
59.9k
    case MVM_OP_hintfor:
1978
59.9k
    case MVM_OP_elems:
1979
59.9k
        if (!jgb_consume_reprop(tc, jgb, bb, ins)) {
1980
0
            MVM_jit_log(tc, "BAIL: op <%s> (devirt attempted)\n", ins->info->name);
1981
0
            return 0;
1982
0
        }
1983
59.9k
        break;
1984
1.63k
    case MVM_OP_iterkey_s:
1985
1.63k
    case MVM_OP_iterval:
1986
1.63k
    case MVM_OP_iter: {
1987
1.63k
        MVMint16 dst      = ins->operands[0].reg.orig;
1988
1.63k
        MVMint32 invocant = ins->operands[1].reg.orig;
1989
1.63k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1990
1.63k
                                 { MVM_JIT_REG_VAL, { invocant } } };
1991
1.63k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
1992
1.63k
        break;
1993
1.63k
    }
1994
0
    case MVM_OP_continuationreset: {
1995
0
        MVMint16 reg  = ins->operands[0].reg.orig;
1996
0
        MVMint16 tag  = ins->operands[1].reg.orig;
1997
0
        MVMint16 code = ins->operands[2].reg.orig;
1998
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
1999
0
                                 { MVM_JIT_REG_VAL, { tag } },
2000
0
                                 { MVM_JIT_REG_VAL, { code } },
2001
0
                                 { MVM_JIT_REG_ADDR, { reg } }};
2002
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_VOID, -1);
2003
0
        break;
2004
1.63k
    }
2005
0
    case MVM_OP_continuationcontrol: {
2006
0
        MVMint16 reg  = ins->operands[0].reg.orig;
2007
0
        MVMint16 protect  = ins->operands[1].reg.orig;
2008
0
        MVMint16 tag  = ins->operands[2].reg.orig;
2009
0
        MVMint16 code = ins->operands[3].reg.orig;
2010
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2011
0
                                 { MVM_JIT_REG_VAL, { protect } },
2012
0
                                 { MVM_JIT_REG_VAL, { tag } },
2013
0
                                 { MVM_JIT_REG_VAL, { code } },
2014
0
                                 { MVM_JIT_REG_ADDR, { reg } }};
2015
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 5, args, MVM_JIT_RV_VOID, -1);
2016
0
        break;
2017
1.63k
    }
2018
0
    case MVM_OP_sp_boolify_iter: {
2019
0
        MVMint16 dst = ins->operands[0].reg.orig;
2020
0
        MVMint16 obj = ins->operands[1].reg.orig;
2021
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2022
0
                                 { MVM_JIT_REG_VAL, { obj } }};
2023
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_INT, dst);
2024
0
        break;
2025
1.63k
    }
2026
697
    case MVM_OP_findmeth:
2027
697
    case MVM_OP_findmeth_s: {
2028
697
        MVMint16 dst = ins->operands[0].reg.orig;
2029
697
        MVMint16 obj = ins->operands[1].reg.orig;
2030
697
        MVMint32 name = (op == MVM_OP_findmeth_s ? ins->operands[2].reg.orig :
2031
0
                         ins->operands[2].lit_str_idx);
2032
697
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2033
697
                                 { MVM_JIT_REG_VAL, { obj } },
2034
697
                                 { (op == MVM_OP_findmeth_s ? MVM_JIT_REG_VAL :
2035
0
                                    MVM_JIT_STR_IDX), { name } },
2036
697
                                 { MVM_JIT_REG_ADDR, { dst } } };
2037
697
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_VOID, -1);
2038
697
        break;
2039
697
    }
2040
697
2041
0
    case MVM_OP_multicachefind: {
2042
0
        MVMint16 dst = ins->operands[0].reg.orig;
2043
0
        MVMint16 cache = ins->operands[1].reg.orig;
2044
0
        MVMint16 capture = ins->operands[2].reg.orig;
2045
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2046
0
                                 { MVM_JIT_REG_VAL, { cache } },
2047
0
                                 { MVM_JIT_REG_VAL, { capture } } };
2048
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
2049
0
        break;
2050
697
    }
2051
0
    case MVM_OP_multicacheadd: {
2052
0
        MVMint16 dst = ins->operands[0].reg.orig;
2053
0
        MVMint16 cache = ins->operands[1].reg.orig;
2054
0
        MVMint16 capture = ins->operands[2].reg.orig;
2055
0
        MVMint16 result = ins->operands[3].reg.orig;
2056
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2057
0
                                 { MVM_JIT_REG_VAL, { cache } },
2058
0
                                 { MVM_JIT_REG_VAL, { capture } },
2059
0
                                 { MVM_JIT_REG_VAL, { result } } };
2060
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_PTR, dst);
2061
0
        break;
2062
697
    }
2063
697
2064
496
    case MVM_OP_can:
2065
496
    case MVM_OP_can_s: {
2066
496
        MVMint16 dst = ins->operands[0].reg.orig;
2067
496
        MVMint16 obj = ins->operands[1].reg.orig;
2068
496
        MVMint32 name = (op == MVM_OP_can_s ? ins->operands[2].reg.orig :
2069
68
                         ins->operands[2].lit_str_idx);
2070
496
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2071
496
                                 { MVM_JIT_REG_VAL, { obj } },
2072
496
                                 { (op == MVM_OP_can_s ? MVM_JIT_REG_VAL :
2073
68
                                    MVM_JIT_STR_IDX), { name } },
2074
496
                                 { MVM_JIT_REG_ADDR, { dst } } };
2075
496
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_VOID, -1);
2076
496
        break;
2077
496
    }
2078
496
2079
496
        /* coercion */
2080
1.02k
    case MVM_OP_coerce_sn:
2081
1.02k
    case MVM_OP_coerce_ns:
2082
1.02k
    case MVM_OP_coerce_si:
2083
1.02k
    case MVM_OP_coerce_is:
2084
1.02k
    case MVM_OP_coerce_In: {
2085
1.02k
        MVMint16 src = ins->operands[1].reg.orig;
2086
1.02k
        MVMint16 dst = ins->operands[0].reg.orig;
2087
1.02k
        MVMJitCallArg args[] = {{ MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2088
1.02k
                                 { MVM_JIT_REG_VAL, { src } } };
2089
1.02k
        MVMJitRVMode rv_mode = ((op == MVM_OP_coerce_sn || op == MVM_OP_coerce_In) ? MVM_JIT_RV_NUM :
2090
1.02k
                                op == MVM_OP_coerce_si ? MVM_JIT_RV_INT :
2091
81
                                MVM_JIT_RV_PTR);
2092
1.02k
        if (op == MVM_OP_coerce_ns) {
2093
34
            args[1].type = MVM_JIT_REG_VAL_F;
2094
34
        }
2095
1.02k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, rv_mode, dst);
2096
1.02k
        break;
2097
1.02k
    }
2098
0
    case MVM_OP_coerce_nI: {
2099
0
        MVMint16 src = ins->operands[1].reg.orig;
2100
0
        MVMint16 dst = ins->operands[0].reg.orig;
2101
0
        MVMint16 typ = ins->operands[2].reg.orig;
2102
0
        MVMJitCallArg args[] = {{ MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2103
0
                                { MVM_JIT_REG_VAL,   { typ } },
2104
0
                                { MVM_JIT_REG_VAL_F, { src } }};
2105
0
2106
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
2107
0
        break;
2108
1.02k
    }
2109
13.0k
    case MVM_OP_smrt_strify:
2110
13.0k
    case MVM_OP_smrt_numify: {
2111
13.0k
        MVMint16 obj = ins->operands[1].reg.orig;
2112
13.0k
        MVMint16 dst = ins->operands[0].reg.orig;
2113
13.0k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2114
13.0k
                                 { MVM_JIT_REG_VAL, { obj } },
2115
13.0k
                                 { MVM_JIT_REG_ADDR, { dst } }};
2116
13.0k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args,
2117
13.0k
                          MVM_JIT_RV_VOID, -1);
2118
13.0k
        break;
2119
13.0k
    }
2120
9
    case MVM_OP_say_fhs:
2121
9
    case MVM_OP_write_fhs: {
2122
9
        MVMint16 dst = ins->operands[0].reg.orig;
2123
9
        MVMint16 fho = ins->operands[1].reg.orig;
2124
9
        MVMint16 str = ins->operands[2].reg.orig;
2125
9
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2126
9
                                 { MVM_JIT_REG_VAL, { fho } },
2127
9
                                 { MVM_JIT_REG_VAL, { str } },
2128
9
                                 { MVM_JIT_LITERAL, { op == MVM_OP_say_fhs ? 1 : 0 } }};
2129
9
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_INT, dst);
2130
9
        break;
2131
9
    }
2132
0
    case MVM_OP_eof_fh: {
2133
0
        MVMint16 dst = ins->operands[0].reg.orig;
2134
0
        MVMint16 fho = ins->operands[1].reg.orig;
2135
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2136
0
                                 { MVM_JIT_REG_VAL, { fho } } };
2137
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_INT, dst);
2138
0
        break;
2139
9
    }
2140
3
    case MVM_OP_readline_fh:
2141
3
    case MVM_OP_readlinechomp_fh: {
2142
3
        MVMint16 dst = ins->operands[0].reg.orig;
2143
3
        MVMint16 fho = ins->operands[1].reg.orig;
2144
3
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2145
3
                                 { MVM_JIT_REG_VAL, { fho } },
2146
3
                                 { MVM_JIT_LITERAL, { op == MVM_OP_readlinechomp_fh ? 1 : 0 } } };
2147
3
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
2148
3
        break;
2149
3
    }
2150
0
    case MVM_OP_read_fhs: {
2151
0
        MVMint16 dst = ins->operands[0].reg.orig;
2152
0
        MVMint16 fho = ins->operands[1].reg.orig;
2153
0
        MVMint16 cnt = ins->operands[2].reg.orig;
2154
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2155
0
                                 { MVM_JIT_REG_VAL, { fho } },
2156
0
                                 { MVM_JIT_REG_VAL, { cnt } } };
2157
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
2158
0
        break;
2159
3
    }
2160
9.40k
    case MVM_OP_box_n:
2161
9.40k
    case MVM_OP_box_s:
2162
9.40k
    case MVM_OP_box_i: {
2163
9.40k
        MVMint16 dst = ins->operands[0].reg.orig;
2164
9.40k
        MVMint16 val = ins->operands[1].reg.orig;
2165
9.40k
        MVMint16 type = ins->operands[2].reg.orig;
2166
9.40k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR , { MVM_JIT_INTERP_TC } },
2167
9.40k
                                 { op == MVM_OP_box_n ? MVM_JIT_REG_VAL_F : MVM_JIT_REG_VAL, { val } },
2168
9.40k
                                 { MVM_JIT_REG_VAL, { type } },
2169
9.40k
                                 { MVM_JIT_REG_ADDR, { dst } }};
2170
9.40k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_VOID, -1);
2171
9.40k
        break;
2172
9.40k
    }
2173
1.30k
    case MVM_OP_unbox_i: {
2174
1.30k
        MVMint16 dst = ins->operands[0].reg.orig;
2175
1.30k
        MVMint16 obj = ins->operands[1].reg.orig;
2176
1.30k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR , { MVM_JIT_INTERP_TC } },
2177
1.30k
                                 { MVM_JIT_REG_VAL, { obj } } };
2178
1.30k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_INT, dst);
2179
1.30k
        break;
2180
9.40k
    }
2181
0
    case MVM_OP_unbox_n: {
2182
0
        MVMint16 dst = ins->operands[0].reg.orig;
2183
0
        MVMint16 obj = ins->operands[1].reg.orig;
2184
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR , { MVM_JIT_INTERP_TC } },
2185
0
                                 { MVM_JIT_REG_VAL, { obj } } };
2186
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_NUM, dst);
2187
0
        break;
2188
9.40k
    }
2189
2.09k
    case MVM_OP_unbox_s: {
2190
2.09k
        MVMint16 dst = ins->operands[0].reg.orig;
2191
2.09k
        MVMint16 obj = ins->operands[1].reg.orig;
2192
2.09k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR , { MVM_JIT_INTERP_TC } },
2193
2.09k
                                 { MVM_JIT_REG_VAL, { obj } } };
2194
2.09k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
2195
2.09k
        break;
2196
9.40k
    }
2197
9.40k
        /* string ops */
2198
1.62k
    case MVM_OP_repeat_s:
2199
1.62k
    case MVM_OP_split:
2200
1.62k
    case MVM_OP_concat_s: {
2201
1.62k
        MVMint16 src_a = ins->operands[1].reg.orig;
2202
1.62k
        MVMint16 src_b = ins->operands[2].reg.orig;
2203
1.62k
        MVMint16 dst   = ins->operands[0].reg.orig;
2204
1.62k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2205
1.62k
                                 { MVM_JIT_REG_VAL, { src_a } },
2206
1.62k
                                 { MVM_JIT_REG_VAL, { src_b } } };
2207
1.62k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args,
2208
1.62k
                          MVM_JIT_RV_PTR, dst);
2209
1.62k
        break;
2210
1.62k
    }
2211
227
    case MVM_OP_escape:
2212
227
    case MVM_OP_uc:
2213
227
    case MVM_OP_lc:
2214
227
    case MVM_OP_tc:
2215
227
    case MVM_OP_indexingoptimized: {
2216
227
        MVMint16 dst    = ins->operands[0].reg.orig;
2217
227
        MVMint16 string = ins->operands[1].reg.orig;
2218
227
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2219
227
                                 { MVM_JIT_REG_VAL, { string } } };
2220
227
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
2221
227
        break;
2222
227
    }
2223
2.11k
    case MVM_OP_ne_s:
2224
2.11k
    case MVM_OP_eq_s: {
2225
2.11k
        MVMint16 src_a = ins->operands[1].reg.orig;
2226
2.11k
        MVMint16 src_b = ins->operands[2].reg.orig;
2227
2.11k
        MVMint16 dst   = ins->operands[0].reg.orig;
2228
2.11k
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2229
2.11k
                                 { MVM_JIT_REG_VAL, { src_a } },
2230
2.11k
                                 { MVM_JIT_REG_VAL, { src_b } } };
2231
2.11k
        jgb_append_call_c(tc, jgb, op_to_func(tc, MVM_OP_eq_s), 3, args,
2232
2.11k
                          MVM_JIT_RV_INT, dst);
2233
2.11k
        if (op == MVM_OP_ne_s) {
2234
568
            /* append not_i to negate ne_s */
2235
568
            MVMSpeshIns *not_i          = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMSpeshIns));
2236
568
            not_i->info                 = MVM_op_get_op(MVM_OP_not_i);
2237
568
            not_i->operands             = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMSpeshOperand) * 2);
2238
568
            not_i->operands[0].reg.orig = dst;
2239
568
            not_i->operands[1].reg.orig = dst;
2240
568
            jgb_append_primitive(tc, jgb, not_i);
2241
568
        }
2242
2.11k
        break;
2243
2.11k
    }
2244
455
    case MVM_OP_eqat_s: {
2245
455
        MVMint16 dst    = ins->operands[0].reg.orig;
2246
455
        MVMint16 src_a  = ins->operands[1].reg.orig;
2247
455
        MVMint16 src_b  = ins->operands[2].reg.orig;
2248
455
        MVMint16 offset = ins->operands[3].reg.orig;
2249
455
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2250
455
                                 { MVM_JIT_REG_VAL, { src_a } },
2251
455
                                 { MVM_JIT_REG_VAL, { src_b } },
2252
455
                                 { MVM_JIT_REG_VAL, { offset } } };
2253
455
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args,
2254
455
                          MVM_JIT_RV_INT, dst);
2255
455
        break;
2256
2.11k
    }
2257
632
    case MVM_OP_chars:
2258
632
    case MVM_OP_graphs_s:
2259
632
    case MVM_OP_codes_s:
2260
632
    case MVM_OP_flip: {
2261
632
        MVMint16 src = ins->operands[1].reg.orig;
2262
632
        MVMint16 dst = ins->operands[0].reg.orig;
2263
632
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2264
632
                                 { MVM_JIT_REG_VAL, { src } } };
2265
632
        MVMJitRVMode rv_mode = (op == MVM_OP_flip ? MVM_JIT_RV_PTR : MVM_JIT_RV_INT);
2266
632
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, rv_mode, dst);
2267
632
        break;
2268
632
    }
2269
9
    case MVM_OP_join: {
2270
9
        MVMint16 dst   = ins->operands[0].reg.orig;
2271
9
        MVMint16 sep   = ins->operands[1].reg.orig;
2272
9
        MVMint16 input = ins->operands[2].reg.orig;
2273
9
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2274
9
                                 { MVM_JIT_REG_VAL, { sep } },
2275
9
                                 { MVM_JIT_REG_VAL, { input } } };
2276
9
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
2277
9
        break;
2278
632
    }
2279
0
    case MVM_OP_replace: {
2280
0
        MVMint16 dst     = ins->operands[0].reg.orig;
2281
0
        MVMint16 a       = ins->operands[1].reg.orig;
2282
0
        MVMint16 start   = ins->operands[2].reg.orig;
2283
0
        MVMint16 length  = ins->operands[3].reg.orig;
2284
0
        MVMint16 replace = ins->operands[4].reg.orig;
2285
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2286
0
                                 { MVM_JIT_REG_VAL, { a } },
2287
0
                                 { MVM_JIT_REG_VAL, { start } },
2288
0
                                 { MVM_JIT_REG_VAL, { length } },
2289
0
                                 { MVM_JIT_REG_VAL, { replace } } };
2290
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 5, args, MVM_JIT_RV_PTR, dst);
2291
0
        break;
2292
632
    }
2293
390
    case MVM_OP_substr_s: {
2294
390
        MVMint16 dst = ins->operands[0].reg.orig;
2295
390
        MVMint16 string = ins->operands[1].reg.orig;
2296
390
        MVMint16 start = ins->operands[2].reg.orig;
2297
390
        MVMint16 length = ins->operands[3].reg.orig;
2298
390
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2299
390
                                 { MVM_JIT_REG_VAL, { string } },
2300
390
                                 { MVM_JIT_REG_VAL, { start } },
2301
390
                                 { MVM_JIT_REG_VAL, { length } } };
2302
390
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_PTR, dst);
2303
390
        break;
2304
632
    }
2305
268
    case MVM_OP_index_s: {
2306
268
        MVMint16 dst = ins->operands[0].reg.orig;
2307
268
        MVMint16 haystack = ins->operands[1].reg.orig;
2308
268
        MVMint16 needle = ins->operands[2].reg.orig;
2309
268
        MVMint16 start = ins->operands[3].reg.orig;
2310
268
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2311
268
                                 { MVM_JIT_REG_VAL, { haystack } },
2312
268
                                 { MVM_JIT_REG_VAL, { needle } },
2313
268
                                 { MVM_JIT_REG_VAL, { start } } };
2314
268
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_PTR, dst);
2315
268
        break;
2316
632
    }
2317
349
    case MVM_OP_iscclass: {
2318
349
        MVMint16 dst    = ins->operands[0].reg.orig;
2319
349
        MVMint16 cclass = ins->operands[1].reg.orig;
2320
349
        MVMint16 str    = ins->operands[2].reg.orig;
2321
349
        MVMint16 offset = ins->operands[3].reg.orig;
2322
349
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2323
349
                                 { MVM_JIT_REG_VAL, { cclass } },
2324
349
                                 { MVM_JIT_REG_VAL, { str } },
2325
349
                                 { MVM_JIT_REG_VAL, { offset } } };
2326
349
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_INT, dst);
2327
349
        break;
2328
632
    }
2329
29
    case MVM_OP_findcclass:
2330
29
    case MVM_OP_findnotcclass: {
2331
29
        MVMint16 dst    = ins->operands[0].reg.orig;
2332
29
        MVMint16 cclass = ins->operands[1].reg.orig;
2333
29
        MVMint16 target = ins->operands[2].reg.orig;
2334
29
        MVMint16 offset = ins->operands[3].reg.orig;
2335
29
        MVMint16 count  = ins->operands[4].reg.orig;
2336
29
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2337
29
                                 { MVM_JIT_REG_VAL, { cclass } },
2338
29
                                 { MVM_JIT_REG_VAL, { target } },
2339
29
                                 { MVM_JIT_REG_VAL, { offset } },
2340
29
                                 { MVM_JIT_REG_VAL, { count } } };
2341
29
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 5, args, MVM_JIT_RV_INT, dst);
2342
29
        break;
2343
29
    }
2344
325
    case MVM_OP_nfarunalt: {
2345
325
        MVMint16 nfa    = ins->operands[0].reg.orig;
2346
325
        MVMint16 target = ins->operands[1].reg.orig;
2347
325
        MVMint16 offset = ins->operands[2].reg.orig;
2348
325
        MVMint16 bstack = ins->operands[3].reg.orig;
2349
325
        MVMint16 cstack = ins->operands[4].reg.orig;
2350
325
        MVMint16 labels = ins->operands[5].reg.orig;
2351
325
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2352
325
                                 { MVM_JIT_REG_VAL, { nfa } },
2353
325
                                 { MVM_JIT_REG_VAL, { target } },
2354
325
                                 { MVM_JIT_REG_VAL, { offset } },
2355
325
                                 { MVM_JIT_REG_VAL, { bstack } },
2356
325
                                 { MVM_JIT_REG_VAL, { cstack } },
2357
325
                                 { MVM_JIT_REG_VAL, { labels } } };
2358
325
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 7, args, MVM_JIT_RV_VOID, -1);
2359
325
        break;
2360
29
    }
2361
110
    case MVM_OP_nfarunproto: {
2362
110
        MVMint16 dst     = ins->operands[0].reg.orig;
2363
110
        MVMint16 nfa     = ins->operands[1].reg.orig;
2364
110
        MVMint16 target  = ins->operands[2].reg.orig;
2365
110
        MVMint16 offset  = ins->operands[3].reg.orig;
2366
110
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2367
110
                                 { MVM_JIT_REG_VAL, { nfa } },
2368
110
                                 { MVM_JIT_REG_VAL, { target } },
2369
110
                                 { MVM_JIT_REG_VAL, { offset } } };
2370
110
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_PTR, dst);
2371
110
        break;
2372
29
    }
2373
435
    case MVM_OP_nfafromstatelist: {
2374
435
        MVMint16 dst     = ins->operands[0].reg.orig;
2375
435
        MVMint16 states  = ins->operands[1].reg.orig;
2376
435
        MVMint16 type    = ins->operands[2].reg.orig;
2377
435
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2378
435
                                 { MVM_JIT_REG_VAL, { states } },
2379
435
                                 { MVM_JIT_REG_VAL, { type } } };
2380
435
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
2381
435
        break;
2382
29
    }
2383
29
        /* bigint ops */
2384
0
    case MVM_OP_isbig_I: {
2385
0
        MVMint16 dst = ins->operands[0].reg.orig;
2386
0
        MVMint16 src = ins->operands[1].reg.orig;
2387
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2388
0
                                 { MVM_JIT_REG_VAL, { src } } };
2389
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args,
2390
0
                          MVM_JIT_RV_INT, dst);
2391
0
        break;
2392
29
    }
2393
0
    case MVM_OP_cmp_I: {
2394
0
        MVMint16 src_a = ins->operands[1].reg.orig;
2395
0
        MVMint16 src_b = ins->operands[2].reg.orig;
2396
0
        MVMint16 dst   = ins->operands[0].reg.orig;
2397
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2398
0
                                 { MVM_JIT_REG_VAL, { src_a } },
2399
0
                                 { MVM_JIT_REG_VAL, { src_b } } };
2400
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args,
2401
0
                          MVM_JIT_RV_INT, dst);
2402
0
        break;
2403
29
    }
2404
0
    case MVM_OP_add_I:
2405
0
    case MVM_OP_sub_I:
2406
0
    case MVM_OP_mul_I:
2407
0
    case MVM_OP_div_I:
2408
0
    case MVM_OP_mod_I:
2409
0
    case MVM_OP_bor_I:
2410
0
    case MVM_OP_band_I:
2411
0
    case MVM_OP_bxor_I:
2412
0
    case MVM_OP_lcm_I:
2413
0
    case MVM_OP_gcd_I: {
2414
0
        MVMint16 src_a = ins->operands[1].reg.orig;
2415
0
        MVMint16 src_b = ins->operands[2].reg.orig;
2416
0
        MVMint16 type  = ins->operands[3].reg.orig;
2417
0
        MVMint16 dst   = ins->operands[0].reg.orig;
2418
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2419
0
                                 { MVM_JIT_REG_VAL, { type } },
2420
0
                                 { MVM_JIT_REG_VAL, { src_a } },
2421
0
                                 { MVM_JIT_REG_VAL, { src_b } } };
2422
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args,
2423
0
                          MVM_JIT_RV_PTR, dst);
2424
0
        break;
2425
0
    }
2426
0
    case MVM_OP_div_In: {
2427
0
        MVMint16 dst   = ins->operands[0].reg.orig;
2428
0
        MVMint16 src_a = ins->operands[1].reg.orig;
2429
0
        MVMint16 src_b = ins->operands[2].reg.orig;
2430
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2431
0
                                 { MVM_JIT_REG_VAL, { src_a } },
2432
0
                                 { MVM_JIT_REG_VAL, { src_b } } };
2433
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_NUM, dst);
2434
0
        break;
2435
0
    }
2436
0
    case MVM_OP_brshift_I:
2437
0
    case MVM_OP_blshift_I: {
2438
0
        MVMint16 dst   = ins->operands[0].reg.orig;
2439
0
        MVMint16 src   = ins->operands[1].reg.orig;
2440
0
        MVMint16 shift = ins->operands[2].reg.orig;
2441
0
        MVMint16 type  = ins->operands[3].reg.orig;
2442
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2443
0
                                 { MVM_JIT_REG_VAL, { type } },
2444
0
                                 { MVM_JIT_REG_VAL, { src } },
2445
0
                                 { MVM_JIT_REG_VAL, { shift } } };
2446
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_PTR, dst);
2447
0
        break;
2448
0
    }
2449
0
    case MVM_OP_coerce_Is: {
2450
0
        MVMint16 src = ins->operands[1].reg.orig;
2451
0
        MVMint16 dst = ins->operands[0].reg.orig;
2452
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2453
0
                                 { MVM_JIT_REG_VAL, { src } },
2454
0
                                 { MVM_JIT_LITERAL, { 10 } } };
2455
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args,
2456
0
                          MVM_JIT_RV_PTR, dst);
2457
0
        break;
2458
0
    }
2459
9
    case MVM_OP_radix: {
2460
9
        MVMint16 dst = ins->operands[0].reg.orig;
2461
9
        MVMint16 radix = ins->operands[1].reg.orig;
2462
9
        MVMint16 string = ins->operands[2].reg.orig;
2463
9
        MVMint16 offset = ins->operands[3].reg.orig;
2464
9
        MVMint16 flag = ins->operands[4].reg.orig;
2465
9
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2466
9
                                 { MVM_JIT_REG_VAL, { radix } },
2467
9
                                 { MVM_JIT_REG_VAL, { string } },
2468
9
                                 { MVM_JIT_REG_VAL, { offset } },
2469
9
                                 { MVM_JIT_REG_VAL, { flag } } };
2470
9
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 5, args,
2471
9
                          MVM_JIT_RV_PTR, dst);
2472
9
        break;
2473
0
    }
2474
0
    case MVM_OP_radix_I: {
2475
0
        MVMint16 dst = ins->operands[0].reg.orig;
2476
0
        MVMint16 radix = ins->operands[1].reg.orig;
2477
0
        MVMint16 string = ins->operands[2].reg.orig;
2478
0
        MVMint16 offset = ins->operands[3].reg.orig;
2479
0
        MVMint16 flag = ins->operands[4].reg.orig;
2480
0
        MVMint16 type = ins->operands[5].reg.orig;
2481
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2482
0
                                 { MVM_JIT_REG_VAL, { radix } },
2483
0
                                 { MVM_JIT_REG_VAL, { string } },
2484
0
                                 { MVM_JIT_REG_VAL, { offset } },
2485
0
                                 { MVM_JIT_REG_VAL, { flag } },
2486
0
                                 { MVM_JIT_REG_VAL, { type } } };
2487
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 6, args,
2488
0
                          MVM_JIT_RV_PTR, dst);
2489
0
        break;
2490
0
    }
2491
0
    case MVM_OP_base_I: {
2492
0
        MVMint16 src  = ins->operands[1].reg.orig;
2493
0
        MVMint16 base = ins->operands[2].reg.orig;
2494
0
        MVMint16 dst  = ins->operands[0].reg.orig;
2495
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2496
0
                                 { MVM_JIT_REG_VAL, { src } },
2497
0
                                 { MVM_JIT_REG_VAL, { base } } };
2498
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args,
2499
0
                          MVM_JIT_RV_PTR, dst);
2500
0
        break;
2501
0
    }
2502
0
    case MVM_OP_bool_I: {
2503
0
        MVMint16 dst = ins->operands[0].reg.orig;
2504
0
        MVMint32 invocant = ins->operands[1].reg.orig;
2505
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
2506
0
                                 { MVM_JIT_REG_VAL, invocant } };
2507
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_INT, dst);
2508
0
        break;
2509
0
    }
2510
0
    case MVM_OP_bnot_I: {
2511
0
        MVMint16 dst      = ins->operands[0].reg.orig;
2512
0
        MVMint32 invocant = ins->operands[1].reg.orig;
2513
0
        MVMint32 type     = ins->operands[2].reg.orig;
2514
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
2515
0
                                 { MVM_JIT_REG_VAL, type },
2516
0
                                 { MVM_JIT_REG_VAL, invocant } };
2517
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
2518
0
        break;
2519
0
    }
2520
404
    case MVM_OP_getcodeobj: {
2521
404
        MVMint16 dst = ins->operands[0].reg.orig;
2522
404
        MVMint32 invocant = ins->operands[1].reg.orig;
2523
404
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, MVM_JIT_INTERP_TC },
2524
404
                                 { MVM_JIT_REG_VAL, invocant } };
2525
404
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
2526
404
        break;
2527
0
    }
2528
0
    case MVM_OP_sqrt_n:
2529
0
    case MVM_OP_sin_n:
2530
0
    case MVM_OP_cos_n:
2531
0
    case MVM_OP_tan_n:
2532
0
    case MVM_OP_asin_n:
2533
0
    case MVM_OP_acos_n:
2534
0
    case MVM_OP_atan_n: {
2535
0
        MVMint16 dst   = ins->operands[0].reg.orig;
2536
0
        MVMint16 src   = ins->operands[1].reg.orig;
2537
0
        MVMJitCallArg args[] = { { MVM_JIT_REG_VAL_F, { src } } };
2538
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 1, args,
2539
0
                          MVM_JIT_RV_NUM, dst);
2540
0
        break;
2541
0
    }
2542
0
    case MVM_OP_pow_n:
2543
0
    case MVM_OP_atan2_n: {
2544
0
        MVMint16 dst   = ins->operands[0].reg.orig;
2545
0
        MVMint16 a     = ins->operands[1].reg.orig;
2546
0
        MVMint16 b     = ins->operands[2].reg.orig;
2547
0
        MVMJitCallArg args[] = { { MVM_JIT_REG_VAL_F, { a } },
2548
0
                                 { MVM_JIT_REG_VAL_F, { b } } };
2549
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args,
2550
0
                          MVM_JIT_RV_NUM, dst);
2551
0
        break;
2552
0
    }
2553
7
    case MVM_OP_time_n: {
2554
7
        MVMint16 dst   = ins->operands[0].reg.orig;
2555
7
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } } };
2556
7
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 1, args,
2557
7
                          MVM_JIT_RV_NUM, dst);
2558
7
        break;
2559
0
    }
2560
0
    case MVM_OP_randscale_n: {
2561
0
        MVMint16 dst   = ins->operands[0].reg.orig;
2562
0
        MVMint16 scale = ins->operands[1].reg.orig;
2563
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2564
0
                                 { MVM_JIT_REG_VAL_F, { scale } } };
2565
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_NUM, dst);
2566
0
        break;
2567
0
    }
2568
0
    case MVM_OP_isnanorinf: {
2569
0
        MVMint16 dst   = ins->operands[0].reg.orig;
2570
0
        MVMint16 src = ins->operands[1].reg.orig;
2571
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2572
0
                                 { MVM_JIT_REG_VAL_F, { src } } };
2573
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_INT, dst);
2574
0
        break;
2575
0
    }
2576
0
    case MVM_OP_nativecallinvoke: {
2577
0
        MVMint16 dst     = ins->operands[0].reg.orig;
2578
0
        MVMint16 restype = ins->operands[1].reg.orig;
2579
0
        MVMint16 site    = ins->operands[2].reg.orig;
2580
0
        MVMint16 cargs   = ins->operands[3].reg.orig;
2581
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2582
0
                                 { MVM_JIT_REG_VAL, { restype } },
2583
0
                                 { MVM_JIT_REG_VAL, { site } },
2584
0
                                 { MVM_JIT_REG_VAL, { cargs } } };
2585
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args,
2586
0
                          MVM_JIT_RV_PTR, dst);
2587
0
        break;
2588
0
    }
2589
0
    case MVM_OP_typeparameters:
2590
0
    case MVM_OP_typeparameterized: {
2591
0
        MVMint16 dst = ins->operands[0].reg.orig;
2592
0
        MVMint16 obj = ins->operands[1].reg.orig;
2593
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2594
0
                                 { MVM_JIT_REG_VAL, { obj } } };
2595
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_PTR, dst);
2596
0
        break;
2597
0
    }
2598
0
    case MVM_OP_typeparameterat: {
2599
0
        MVMint16 dst = ins->operands[0].reg.orig;
2600
0
        MVMint16 obj = ins->operands[1].reg.orig;
2601
0
        MVMint16 idx = ins->operands[2].reg.orig;
2602
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2603
0
                                 { MVM_JIT_REG_VAL, { obj } },
2604
0
                                 { MVM_JIT_REG_VAL, { idx } } };
2605
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
2606
0
        break;
2607
0
    }
2608
0
        /* native references (as simple function calls for now) */
2609
0
    case MVM_OP_iscont_i:
2610
0
    case MVM_OP_iscont_n:
2611
0
    case MVM_OP_iscont_s:
2612
0
    case MVM_OP_isrwcont: {
2613
0
        MVMint16 dst = ins->operands[0].reg.orig;
2614
0
        MVMint16 obj = ins->operands[1].reg.orig;
2615
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2616
0
                                 { MVM_JIT_REG_VAL, { obj } } };
2617
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_INT, dst);
2618
0
        break;
2619
0
    }
2620
0
    case MVM_OP_assign_i:
2621
0
    case MVM_OP_assign_n:
2622
0
    case MVM_OP_assign_s: {
2623
0
        MVMint16 target = ins->operands[0].reg.orig;
2624
0
        MVMint16 value  = ins->operands[1].reg.orig;
2625
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2626
0
                                 { MVM_JIT_REG_VAL, { target } },
2627
0
                                 { MVM_JIT_REG_VAL, { value } } };
2628
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_VOID, -1);
2629
0
        break;
2630
0
    }
2631
0
    case MVM_OP_decont_i:
2632
0
    case MVM_OP_decont_n:
2633
0
    case MVM_OP_decont_s: {
2634
0
        MVMint16 dst = ins->operands[0].reg.orig;
2635
0
        MVMint16 obj = ins->operands[1].reg.orig;
2636
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2637
0
                                 { MVM_JIT_REG_VAL, { obj } },
2638
0
                                 { MVM_JIT_REG_ADDR, { dst } } };
2639
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_VOID, -1);
2640
0
        break;
2641
0
    }
2642
0
    case MVM_OP_getlexref_i:
2643
0
    case MVM_OP_getlexref_i32:
2644
0
    case MVM_OP_getlexref_i16:
2645
0
    case MVM_OP_getlexref_i8:
2646
0
    case MVM_OP_getlexref_n:
2647
0
    case MVM_OP_getlexref_n32:
2648
0
    case MVM_OP_getlexref_s: {
2649
0
        MVMint16 dst     = ins->operands[0].reg.orig;
2650
0
        MVMuint16 outers = ins->operands[1].lex.outers;
2651
0
        MVMuint16 idx    = ins->operands[1].lex.idx;
2652
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2653
0
                                 { MVM_JIT_LITERAL, { outers } },
2654
0
                                 { MVM_JIT_LITERAL, { idx } } };
2655
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
2656
0
        break;
2657
0
    }
2658
0
    case MVM_OP_getattrref_i:
2659
0
    case MVM_OP_getattrref_n:
2660
0
    case MVM_OP_getattrref_s: {
2661
0
        MVMint16 dst     = ins->operands[0].reg.orig;
2662
0
        MVMint16 obj     = ins->operands[1].reg.orig;
2663
0
        MVMint16 class   = ins->operands[2].reg.orig;
2664
0
        MVMint16 name    = ins->operands[3].lit_str_idx;
2665
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2666
0
                                 { MVM_JIT_REG_VAL, { obj } },
2667
0
                                 { MVM_JIT_REG_VAL, { class } },
2668
0
                                 { MVM_JIT_STR_IDX, { name } } };
2669
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_PTR, dst);
2670
0
        break;
2671
0
    }
2672
0
    case MVM_OP_getattrsref_i:
2673
0
    case MVM_OP_getattrsref_n:
2674
0
    case MVM_OP_getattrsref_s: {
2675
0
        MVMint16 dst     = ins->operands[0].reg.orig;
2676
0
        MVMint16 obj     = ins->operands[1].reg.orig;
2677
0
        MVMint16 class   = ins->operands[2].reg.orig;
2678
0
        MVMint16 name    = ins->operands[3].reg.orig;
2679
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2680
0
                                 { MVM_JIT_REG_VAL, { obj } },
2681
0
                                 { MVM_JIT_REG_VAL, { class } },
2682
0
                                 { MVM_JIT_REG_VAL, { name } } };
2683
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 4, args, MVM_JIT_RV_PTR, dst);
2684
0
        break;
2685
0
    }
2686
0
    case MVM_OP_atposref_i:
2687
0
    case MVM_OP_atposref_n:
2688
0
    case MVM_OP_atposref_s: {
2689
0
        MVMint16 dst     = ins->operands[0].reg.orig;
2690
0
        MVMint16 obj     = ins->operands[1].reg.orig;
2691
0
        MVMint16 index   = ins->operands[2].reg.orig;
2692
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2693
0
                                 { MVM_JIT_REG_VAL, { obj } },
2694
0
                                 { MVM_JIT_REG_VAL, { index } } };
2695
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_PTR, dst);
2696
0
        break;
2697
0
    }
2698
0
        /* profiling */
2699
0
    case MVM_OP_prof_allocated: {
2700
0
        MVMint16 reg = ins->operands[0].reg.orig;
2701
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2702
0
                                 { MVM_JIT_REG_VAL, { reg } } };
2703
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_VOID, -1);
2704
0
        break;
2705
0
    }
2706
0
    case MVM_OP_prof_exit: {
2707
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } } };
2708
0
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 1, args, MVM_JIT_RV_VOID, -1);
2709
0
        break;
2710
0
    }
2711
0
        /* special jumplist branch */
2712
406
    case MVM_OP_jumplist: {
2713
406
        return jgb_consume_jumplist(tc, jgb, ins);
2714
0
    }
2715
0
        /* returning */
2716
4
    case MVM_OP_return: {
2717
4
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  { MVM_JIT_INTERP_TC } },
2718
4
                                 { MVM_JIT_LITERAL, { 0 } }};
2719
4
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 2, args, MVM_JIT_RV_VOID, -1);
2720
4
        jgb_append_branch(tc, jgb, MVM_JIT_BRANCH_EXIT, NULL);
2721
4
        break;
2722
0
    }
2723
12.7k
    case MVM_OP_return_o:
2724
12.7k
    case MVM_OP_return_s:
2725
12.7k
    case MVM_OP_return_n:
2726
12.7k
    case MVM_OP_return_i: {
2727
12.7k
        MVMint16 reg = ins->operands[0].reg.orig;
2728
12.7k
        MVMJitCallArg args[] = {{ MVM_JIT_INTERP_VAR, { MVM_JIT_INTERP_TC } },
2729
12.7k
                                 { MVM_JIT_REG_VAL, { reg } },
2730
12.7k
                                 { MVM_JIT_LITERAL, { 0 } } };
2731
12.7k
        if (op == MVM_OP_return_n) {
2732
2
            args[1].type = MVM_JIT_REG_VAL_F;
2733
2
        }
2734
12.7k
        jgb_append_call_c(tc, jgb, op_to_func(tc, op), 3, args, MVM_JIT_RV_VOID, -1);
2735
12.7k
        jgb_append_branch(tc, jgb, MVM_JIT_BRANCH_EXIT, NULL);
2736
12.7k
        break;
2737
12.7k
    }
2738
16.5k
    case MVM_OP_sp_guardconc:
2739
16.5k
    case MVM_OP_sp_guardtype:
2740
16.5k
    case MVM_OP_sp_guardcontconc:
2741
16.5k
    case MVM_OP_sp_guardconttype:
2742
16.5k
    case MVM_OP_sp_guardrwconc:
2743
16.5k
    case MVM_OP_sp_guardrwtype:
2744
16.5k
        jgb_append_guard(tc, jgb, ins);
2745
16.5k
        break;
2746
17.7k
    case MVM_OP_prepargs: {
2747
17.7k
        return jgb_consume_invoke(tc, jgb, ins);
2748
16.5k
    }
2749
1.53k
    default: {
2750
1.53k
        /* Check if it's an extop. */
2751
1.53k
        MVMint32 emitted_extop = 0;
2752
1.53k
        if (ins->info->opcode == (MVMuint16)-1) {
2753
0
            MVMExtOpRecord *extops     = jgb->sg->sf->body.cu->body.extops;
2754
0
            MVMuint16       num_extops = jgb->sg->sf->body.cu->body.num_extops;
2755
0
            MVMuint16       i;
2756
0
            for (i = 0; i < num_extops; i++) {
2757
0
                if (extops[i].info == ins->info && !extops[i].no_jit) {
2758
0
                    size_t fake_regs_size;
2759
0
                    MVMuint16 *fake_regs = try_fake_extop_regs(tc, jgb->sg, ins, &fake_regs_size);
2760
0
                    if (fake_regs_size && fake_regs != NULL) {
2761
0
                        MVMint32  data_label = jgb_add_data_node(tc, jgb, fake_regs, fake_regs_size);
2762
0
                        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR,  { MVM_JIT_INTERP_TC } },
2763
0
                                                 { MVM_JIT_DATA_LABEL,  { data_label } }};
2764
0
                        if (ins->info->jittivity & MVM_JIT_INFO_INVOKISH)
2765
0
                            jgb_append_control(tc, jgb, ins, MVM_JIT_CONTROL_THROWISH_PRE);
2766
0
                        jgb_append_call_c(tc, jgb, extops[i].func, 2, args, MVM_JIT_RV_VOID, -1);
2767
0
                        if (ins->info->jittivity & MVM_JIT_INFO_INVOKISH)
2768
0
                            jgb_append_control(tc, jgb, ins, MVM_JIT_CONTROL_INVOKISH);
2769
0
                        MVM_jit_log(tc, "append extop: <%s>\n", ins->info->name);
2770
0
                        emitted_extop = 1;
2771
0
                    }
2772
0
                    break;
2773
0
                }
2774
0
            }
2775
0
        }
2776
1.53k
        if (!emitted_extop) {
2777
1.53k
            MVM_jit_log(tc, "BAIL: op <%s>\n", ins->info->name);
2778
1.53k
            return 0;
2779
1.53k
        }
2780
1.53k
    }
2781
930k
    }
2782
911k
    return 1;
2783
930k
}
2784
2785
static MVMint32 jgb_consume_bb(MVMThreadContext *tc, JitGraphBuilder *jgb,
2786
187k
                               MVMSpeshBB *bb) {
2787
187k
    MVMint32 label = get_label_for_bb(tc, jgb, bb);
2788
187k
    jgb->cur_bb = bb;
2789
187k
    jgb_append_label(tc, jgb, label);
2790
187k
    /* We always append a label update at the start of a basic block for now.
2791
187k
     * This may be more than is actually needed, but it's safe. The problem is
2792
187k
     * that a jump can move us out of the scope of an exception hander, and so
2793
187k
     * we need a location update. This came to light in the case that we left
2794
187k
     * an inline (which is a jump) and came back to a region where a handler
2795
187k
     * should be in force, and it failed to be. */
2796
187k
    jgb_append_control(tc, jgb, bb->first_ins, MVM_JIT_CONTROL_DYNAMIC_LABEL);
2797
187k
    jgb->cur_ins = bb->first_ins;
2798
1.11M
    while (jgb->cur_ins) {
2799
930k
        jgb_before_ins(tc, jgb, jgb->cur_bb, jgb->cur_ins);
2800
930k
        if(!jgb_consume_ins(tc, jgb, jgb->cur_bb, jgb->cur_ins))
2801
1.53k
            return 0;
2802
929k
        jgb_after_ins(tc, jgb, jgb->cur_bb, jgb->cur_ins);
2803
929k
        jgb->cur_ins = jgb->cur_ins->next;
2804
929k
    }
2805
185k
    return 1;
2806
187k
}
2807
2808
12.3k
static MVMJitGraph *jgb_build(MVMThreadContext *tc, JitGraphBuilder *jgb) {
2809
12.3k
    MVMint32 i;
2810
12.3k
    MVMJitGraph * jg       = MVM_spesh_alloc(tc, jgb->sg, sizeof(MVMJitGraph));
2811
12.3k
    jg->sg                 = jgb->sg;
2812
12.3k
    jg->first_node         = jgb->first_node;
2813
12.3k
    jg->last_node          = jgb->last_node;
2814
12.3k
    /* find the last assigned label */
2815
177k
    for (i = 0; i < jgb->num_labels; i++)
2816
177k
        if (jgb->labeleds[i] == NULL)
2817
12.3k
            break;
2818
12.3k
    jg->num_labels         = i;
2819
12.3k
    jg->num_bbs            = jgb->num_bbs;
2820
12.3k
    jg->bb_labels          = jgb->bb_labels;
2821
12.3k
    jg->num_deopts         = jgb->num_deopts;
2822
12.3k
    jg->deopts             = jgb->deopts;
2823
12.3k
    jg->num_inlines       = jgb->num_inlines;
2824
12.3k
    jg->inlines           = jgb->inlines;
2825
12.3k
    jg->num_handlers      = jgb->num_handlers;
2826
12.3k
    jg->handlers          = jgb->handlers;
2827
12.3k
    return jg;
2828
12.3k
}
2829
2830
13.8k
MVMJitGraph * MVM_jit_try_make_graph(MVMThreadContext *tc, MVMSpeshGraph *sg) {
2831
13.8k
    JitGraphBuilder jgb;
2832
13.8k
    if (!MVM_jit_support()) {
2833
0
        return NULL;
2834
0
    }
2835
13.8k
2836
13.8k
    if (tc->instance->jit_log_fh) {
2837
0
        char *cuuid = MVM_string_utf8_encode_C_string(tc, sg->sf->body.cuuid);
2838
0
        char *name  = MVM_string_utf8_encode_C_string(tc, sg->sf->body.name);
2839
0
        MVM_jit_log(tc, "Constructing JIT graph (cuuid: %s, name: '%s')\n",
2840
0
                    cuuid, name);
2841
0
        MVM_free(cuuid);
2842
0
        MVM_free(name);
2843
0
    }
2844
13.8k
2845
13.8k
    jgb.sg = sg;
2846
13.8k
    /* ignore first BB, which always contains a NOP */
2847
13.8k
    jgb.cur_bb = sg->entry->linear_next;
2848
13.8k
    jgb.cur_ins = jgb.cur_bb->first_ins;
2849
13.8k
    jgb.first_node = jgb.last_node = NULL;
2850
13.8k
    /* Total (expected) number of labels. May grow if there are more than 4
2851
13.8k
     * deopt labels (OSR deopt labels or deopt_all labels). */
2852
13.8k
    jgb.num_labels = sg->num_bbs + (sg->num_handlers * 3) + 4;
2853
13.8k
    /* The objects that are labeled (spesh ins or spesh bbs). May grow */
2854
13.8k
    jgb.labeleds   = MVM_spesh_alloc(tc, sg, sizeof(void*) * jgb.num_labels);
2855
13.8k
    /* bb labels are indexed by bb index (much wow) */
2856
13.8k
    jgb.num_bbs    = sg->num_bbs;
2857
13.8k
    jgb.bb_labels  = MVM_spesh_alloc(tc, sg, sizeof(MVMint32) * sg->num_bbs);
2858
13.8k
    /* deopt points may grow */
2859
13.8k
    jgb.num_deopts   = 0;
2860
13.8k
    jgb.alloc_deopts = 2;
2861
13.8k
    jgb.deopts       = MVM_spesh_alloc(tc, sg, sizeof(MVMJitDeopt) * 2);
2862
13.8k
    /* jit handlers are indexed by.. handler index (also much wow) */
2863
13.8k
    jgb.num_handlers = sg->num_handlers;
2864
1.63k
    jgb.handlers     = sg->num_handlers ? MVM_spesh_alloc(tc, sg, sizeof(MVMJitHandler) * sg->num_handlers) : NULL;
2865
13.8k
    /* guess what inlines are indexed by */
2866
13.8k
    jgb.num_inlines  = sg->num_inlines;
2867
2.49k
    jgb.inlines      = sg->num_inlines ? MVM_spesh_alloc(tc, sg, sizeof(MVMJitInline) * sg->num_inlines) : NULL;
2868
13.8k
    /* loop over basic blocks, adding one after the other */
2869
199k
    while (jgb.cur_bb) {
2870
187k
        if (!jgb_consume_bb(tc, &jgb, jgb.cur_bb))
2871
1.53k
            return NULL;
2872
185k
        jgb.cur_bb = jgb.cur_bb->linear_next;
2873
185k
    }
2874
13.8k
    /* Check if we've added a instruction at all */
2875
12.3k
    if (!jgb.first_node)
2876
0
        return NULL;
2877
12.3k
    /* append the end-of-graph label */
2878
12.3k
    jgb_append_label(tc, &jgb, get_label_for_graph(tc, &jgb, sg));
2879
12.3k
    return jgb_build(tc, &jgb);
2880
12.3k
}