Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4460211
swarm.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
378 KB
Referenced Files
None
Subscribers
None
swarm.c
View Options
This file is larger than 256 KB, so syntax highlighting was skipped.
#ifdef ANT_JIT
#include "silver/swarm.h"
#include "silver/glue.h"
#include "silver/engine.h"
#include "silver/opcode.h"
#include "internal.h"
#include "debug.h"
#include "shapes.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmacro-redefined"
#include <mir.h>
#include <mir-gen.h>
#pragma GCC diagnostic pop
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stddef.h>
static const char *sv_op_name[] = {
#define OP_DEF(name, size, n_pop, n_push, f) [OP_##name] = #name,
#include "silver/opcode.h"
};
typedef struct {
MIR_context_t ctx;
bool externals_loaded;
} sv_jit_ctx_t;
static sv_jit_ctx_t *jit_ctx_get(ant_t *js) {
return (sv_jit_ctx_t *)js->jit_ctx;
}
static void jit_ctx_set(ant_t *js, sv_jit_ctx_t *ctx) {
js->jit_ctx = ctx;
}
static void jit_ctx_remove(ant_t *js) {
js->jit_ctx = NULL;
}
static void jit_load_externals_once(sv_jit_ctx_t *jc) {
if (jc == NULL || jc->externals_loaded) return;
MIR_context_t ctx = jc->ctx;
#define LOAD_EXT(name) MIR_load_external(ctx, #name, name)
LOAD_EXT(jit_helper_add);
LOAD_EXT(jit_helper_sub);
LOAD_EXT(jit_helper_mul);
LOAD_EXT(jit_helper_div);
LOAD_EXT(jit_helper_mod);
LOAD_EXT(jit_helper_str_append_local);
LOAD_EXT(jit_helper_str_append_local_snapshot);
LOAD_EXT(jit_helper_str_flush_local);
LOAD_EXT(jit_helper_lt);
LOAD_EXT(jit_helper_le);
LOAD_EXT(jit_helper_gt);
LOAD_EXT(jit_helper_ge);
LOAD_EXT(jit_helper_call);
LOAD_EXT(jit_helper_call_method);
LOAD_EXT(jit_helper_call_array_includes);
LOAD_EXT(jit_helper_apply);
LOAD_EXT(jit_helper_rest);
LOAD_EXT(jit_helper_special_obj);
LOAD_EXT(jit_helper_for_of);
LOAD_EXT(jit_helper_destructure_close);
LOAD_EXT(jit_helper_destructure_next);
LOAD_EXT(jit_helper_get_global);
LOAD_EXT(jit_helper_get_field);
LOAD_EXT(jit_helper_to_propkey);
LOAD_EXT(jit_helper_bailout_resume);
LOAD_EXT(jit_helper_close_upval);
LOAD_EXT(jit_helper_closure);
LOAD_EXT(jit_helper_in);
LOAD_EXT(jit_helper_instanceof);
LOAD_EXT(jit_helper_call_is_proto);
LOAD_EXT(jit_helper_get_length);
LOAD_EXT(jit_helper_define_field);
LOAD_EXT(jit_helper_define_method_comp);
LOAD_EXT(jit_helper_seq);
LOAD_EXT(jit_helper_eq);
LOAD_EXT(jit_helper_ne);
LOAD_EXT(jit_helper_sne);
LOAD_EXT(jit_helper_put_field);
LOAD_EXT(jit_helper_get_elem);
LOAD_EXT(jit_helper_get_elem2);
LOAD_EXT(jit_helper_put_elem);
LOAD_EXT(jit_helper_put_global);
LOAD_EXT(jit_helper_object);
LOAD_EXT(jit_helper_array);
LOAD_EXT(jit_helper_catch_value);
LOAD_EXT(jit_helper_throw);
LOAD_EXT(jit_helper_throw_error);
LOAD_EXT(jit_helper_set_proto);
LOAD_EXT(jit_helper_band);
LOAD_EXT(jit_helper_bor);
LOAD_EXT(jit_helper_bxor);
LOAD_EXT(jit_helper_bnot);
LOAD_EXT(jit_helper_shl);
LOAD_EXT(jit_helper_shr);
LOAD_EXT(jit_helper_ushr);
LOAD_EXT(jit_helper_not);
LOAD_EXT(jit_helper_is_truthy);
LOAD_EXT(jit_helper_typeof);
LOAD_EXT(jit_helper_new);
LOAD_EXT(jit_helper_delete);
LOAD_EXT(jit_helper_set_name);
LOAD_EXT(jit_helper_stack_overflow);
LOAD_EXT(jit_helper_stack_overflow_error);
#undef LOAD_EXT
jc->externals_loaded = true;
}
void sv_jit_init(ant_t *js) {
if (jit_ctx_get(js)) return;
sv_jit_ctx_t *jc = calloc(1, sizeof(*jc));
if (!jc) return;
jc->ctx = MIR_init();
MIR_gen_init(jc->ctx);
MIR_gen_set_optimize_level(jc->ctx, 3);
jit_load_externals_once(jc);
jit_ctx_set(js, jc);
}
void sv_jit_destroy(ant_t *js) {
sv_jit_ctx_t *jc = jit_ctx_get(js);
if (!jc) return;
MIR_gen_finish(jc->ctx);
MIR_finish(jc->ctx);
free(jc);
jit_ctx_remove(js);
}
typedef struct {
MIR_reg_t *regs;
MIR_reg_t *d_regs;
sv_func_t **known_func;
struct jit_method_ic_info *method_ic;
uint8_t *slot_type;
uint64_t *known_const;
bool *has_const;
int sp;
int max;
} jit_vstack_t;
typedef struct jit_method_ic_info {
sv_ic_entry_t *ic;
ant_shape_t *receiver_shape;
sv_func_t *callee;
bool valid;
} jit_method_ic_info_t;
static bool jit_atom_matches_shape_prop(sv_atom_t *atom,
const ant_shape_prop_t *prop) {
if (!atom || !prop || prop->type != ANT_SHAPE_KEY_STRING || !prop->key.interned)
return false;
if (prop->key.interned == atom->str) return true;
return strncmp(prop->key.interned, atom->str, atom->len) == 0 &&
prop->key.interned[atom->len] == '\0';
}
static MIR_reg_t vstack_push(jit_vstack_t *vs) {
if (vs->known_func) vs->known_func[vs->sp] = NULL;
if (vs->method_ic) vs->method_ic[vs->sp] = (jit_method_ic_info_t){0};
if (vs->slot_type) vs->slot_type[vs->sp] = 0;
if (vs->has_const) vs->has_const[vs->sp] = false;
return vs->regs[vs->sp++];
}
static MIR_reg_t vstack_push_const(jit_vstack_t *vs, uint64_t val) {
if (vs->known_func) vs->known_func[vs->sp] = NULL;
if (vs->method_ic) vs->method_ic[vs->sp] = (jit_method_ic_info_t){0};
if (vs->slot_type) vs->slot_type[vs->sp] = 0;
if (vs->has_const) { vs->has_const[vs->sp] = true; vs->known_const[vs->sp] = val; }
return vs->regs[vs->sp++];
}
static MIR_reg_t vstack_pop(jit_vstack_t *vs) {
return vs->regs[--vs->sp];
}
static MIR_reg_t vstack_top(jit_vstack_t *vs) {
return vs->regs[vs->sp - 1];
}
#define MAX_LABELS 1024
typedef struct {
int bc_off;
MIR_label_t label;
int sp;
} jit_label_t;
typedef struct {
jit_label_t entries[MAX_LABELS];
int count;
} jit_label_map_t;
static MIR_label_t label_for_offset(MIR_context_t ctx, jit_label_map_t *lm,
int bc_off) {
for (int i = 0; i < lm->count; i++)
if (lm->entries[i].bc_off == bc_off) return lm->entries[i].label;
if (lm->count >= MAX_LABELS) return NULL;
MIR_label_t lbl = MIR_new_label(ctx);
lm->entries[lm->count].bc_off = bc_off;
lm->entries[lm->count].label = lbl;
lm->entries[lm->count].sp = -1;
lm->count++;
return lbl;
}
static void label_record_sp(jit_label_map_t *lm, int bc_off, int sp) {
for (int i = 0; i < lm->count; i++)
if (lm->entries[i].bc_off != bc_off) continue;
else { if (lm->entries[i].sp < 0) lm->entries[i].sp = sp; return; }
}
static MIR_label_t label_for_branch(MIR_context_t ctx, jit_label_map_t *lm,
int bc_off, int sp) {
MIR_label_t lbl = label_for_offset(ctx, lm, bc_off);
label_record_sp(lm, bc_off, sp);
return lbl;
}
#define MIR_JSVAL MIR_T_I64
#define JIT_ERR_TAG ((NANBOX_PREFIX >> NANBOX_TYPE_SHIFT) | T_ERR)
static void mir_i64_to_d(MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t dst_d, MIR_reg_t src_i64,
MIR_reg_t slot) {
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64, 0, slot, 0, 1),
MIR_new_reg_op(ctx, src_i64)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, dst_d),
MIR_new_mem_op(ctx, MIR_T_D, 0, slot, 0, 1)));
}
static void mir_d_to_i64(MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t dst_i64, MIR_reg_t src_d,
MIR_reg_t slot) {
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_mem_op(ctx, MIR_T_D, 0, slot, 0, 1),
MIR_new_reg_op(ctx, src_d)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst_i64),
MIR_new_mem_op(ctx, MIR_T_I64, 0, slot, 0, 1)));
}
#define SLOT_BOXED 0
#define SLOT_NUM 1
static void vstack_ensure_boxed(jit_vstack_t *vs, int idx,
MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t d_slot) {
if (!vs->slot_type || vs->slot_type[idx] != SLOT_NUM) return;
mir_d_to_i64(ctx, fn, vs->regs[idx], vs->d_regs[idx], d_slot);
vs->slot_type[idx] = SLOT_BOXED;
}
static void vstack_ensure_num(jit_vstack_t *vs, int idx,
MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t d_slot) {
if (!vs->slot_type || vs->slot_type[idx] == SLOT_NUM) return;
mir_i64_to_d(ctx, fn, vs->d_regs[idx], vs->regs[idx], d_slot);
vs->slot_type[idx] = SLOT_NUM;
}
static void vstack_flush_to_boxed(jit_vstack_t *vs,
MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t d_slot) {
if (!vs->slot_type) return;
for (int i = 0; i < vs->sp; i++)
vstack_ensure_boxed(vs, i, ctx, fn, d_slot);
}
static void mir_emit_bailout_check(MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t res,
MIR_reg_t restore_val,
MIR_reg_t r_bailout_off, int bc_off,
MIR_reg_t r_bailout_sp, int pre_op_sp,
MIR_label_t bailout_tramp,
MIR_reg_t r_args_buf,
jit_vstack_t *vs,
MIR_reg_t *local_regs, int n_locals,
MIR_reg_t r_lbuf,
MIR_reg_t r_d_slot) {
MIR_label_t no_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_bail),
MIR_new_reg_op(ctx, res),
MIR_new_uint_op(ctx, (uint64_t)SV_JIT_BAILOUT)));
if (restore_val)
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, res),
MIR_new_reg_op(ctx, restore_val)));
for (int i = 0; i < pre_op_sp; i++) {
if (vs->slot_type && vs->slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, fn, vs->regs[i], vs->d_regs[i], r_d_slot);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs->regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, fn, no_bail);
}
static void mir_load_imm(MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t dst, uint64_t imm) {
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_uint_op(ctx, imm)));
}
static void mir_emit_fill_param_slots_from_args(
MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t r_slotbuf, MIR_reg_t r_args, MIR_reg_t r_argc,
bool *captured_params, int param_count
) {
if (!captured_params) return;
for (int i = 0; i < param_count; i++) {
if (!captured_params[i]) continue;
MIR_label_t arg_present = MIR_new_label(ctx);
MIR_label_t arg_done = MIR_new_label(ctx);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_UBGT,
MIR_new_label_op(ctx, arg_present),
MIR_new_reg_op(ctx, r_argc),
MIR_new_int_op(ctx, (int64_t)i)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_slotbuf, 0, 1),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0))));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, arg_done)));
MIR_append_insn(ctx, fn, arg_present);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_slotbuf, 0, 1),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args, 0, 1)));
MIR_append_insn(ctx, fn, arg_done);
}
}
static void mir_emit_spill_child_captured_locals(
MIR_context_t ctx, MIR_item_t fn,
sv_func_t *parent_func, sv_func_t *child,
MIR_reg_t *local_regs, int n_locals, MIR_reg_t r_lbuf
) {
if (!child || !parent_func || !local_regs || n_locals <= 0 || !r_lbuf) return;
for (int i = 0; i < child->upvalue_count; i++) {
sv_upval_desc_t *desc = &child->upval_descs[i];
if (!desc->is_local) continue;
int li = (int)desc->index - parent_func->param_count;
if (li < 0 || li >= n_locals) continue;
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(li * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[li])));
}
}
static void mir_emit_close_marked_slots(
MIR_context_t ctx, MIR_item_t fn,
MIR_item_t close_upval_proto, MIR_item_t imp_close_upval,
MIR_reg_t r_vm, MIR_reg_t r_slots,
bool *captured, int start_idx, int slot_count
) {
if (!captured || start_idx >= slot_count || slot_count <= 0 || !r_slots) return;
if (start_idx < 0) start_idx = 0;
for (int i = start_idx; i < slot_count; i++) {
if (!captured[i]) continue;
MIR_append_insn(ctx, fn,
MIR_new_call_insn(ctx, 6,
MIR_new_ref_op(ctx, close_upval_proto),
MIR_new_ref_op(ctx, imp_close_upval),
MIR_new_reg_op(ctx, r_vm),
MIR_new_uint_op(ctx, (uint64_t)i),
MIR_new_reg_op(ctx, r_slots),
MIR_new_int_op(ctx, i + 1)));
}
}
static inline void mir_emit_self_tail(
MIR_context_t ctx, MIR_item_t fn,
int call_argc, int param_count,
MIR_reg_t r_tco_args, MIR_reg_t r_arg_arr,
MIR_reg_t r_args, MIR_reg_t r_argc,
MIR_reg_t *local_regs, int n_locals,
bool has_captured_slots, MIR_reg_t r_slotbuf, bool *captured_params,
bool has_captures, bool *captured_locals,
MIR_reg_t r_lbuf, MIR_label_t entry
) {
for (int i = 0; i < call_argc && i < param_count; i++)
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_tco_args, 0, 1),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_arg_arr, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_args),
MIR_new_reg_op(ctx, r_tco_args)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_argc),
MIR_new_int_op(ctx, (int64_t)call_argc)));
if (has_captured_slots)
mir_emit_fill_param_slots_from_args(ctx, fn, r_slotbuf, r_tco_args, r_argc, captured_params, param_count);
for (int i = 0; i < n_locals; i++)
mir_load_imm(ctx, fn, local_regs[i], mkval(T_UNDEF, 0));
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0))));
}
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, entry)));
}
static inline bool jit_const_is_heap(ant_value_t cv) {
uint8_t t = vtype(cv);
return
((1u << t) & ((1u << T_OBJ)
| (1u << T_STR)
| (1u << T_ARR)
| (1u << T_PROMISE)
| (1u << T_BIGINT)
| (1u << T_GENERATOR)
| (1u << T_SYMBOL))) != 0;
}
static void mir_load_const_slot(MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t dst, ant_value_t *slot) {
mir_load_imm(ctx, fn, dst, (uint64_t)(uintptr_t)slot);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_T_I64, 0, dst, 0, 1)));
}
static void mir_call_helper2(MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t dst,
MIR_item_t proto, MIR_item_t func_item,
MIR_reg_t vm_reg, MIR_reg_t js_reg,
MIR_reg_t arg0, MIR_reg_t arg1) {
MIR_append_insn(ctx, fn,
MIR_new_call_insn(ctx, 7,
MIR_new_ref_op(ctx, proto),
MIR_new_ref_op(ctx, func_item),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, vm_reg),
MIR_new_reg_op(ctx, js_reg),
MIR_new_reg_op(ctx, arg0),
MIR_new_reg_op(ctx, arg1)));
}
static void mir_emit_is_num_guard(MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t r_bool, MIR_reg_t v,
MIR_label_t slow) {
(void)r_bool;
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_UBGT,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, v),
MIR_new_uint_op(ctx, NANBOX_PREFIX)));
}
#define NANBOX_TFUNC_TAG ((NANBOX_PREFIX >> NANBOX_TYPE_SHIFT) | (uint64_t)T_FUNC)
#define NANBOX_TOBJ_TAG ((NANBOX_PREFIX >> NANBOX_TYPE_SHIFT) | (uint64_t)T_OBJ)
#define NANBOX_TARR_TAG ((NANBOX_PREFIX >> NANBOX_TYPE_SHIFT) | (uint64_t)T_ARR)
#define NANBOX_TPROM_TAG ((NANBOX_PREFIX >> NANBOX_TYPE_SHIFT) | (uint64_t)T_PROMISE)
static void mir_emit_get_closure(MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t dst, MIR_reg_t v,
MIR_reg_t r_tag, MIR_label_t fallback) {
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_tag),
MIR_new_reg_op(ctx, v),
MIR_new_uint_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, fallback),
MIR_new_reg_op(ctx, r_tag),
MIR_new_uint_op(ctx, NANBOX_TFUNC_TAG)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, v),
MIR_new_uint_op(ctx, NANBOX_DATA_MASK)));
}
static void mir_emit_resolve_call_this(MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t dst, MIR_reg_t r_closure,
MIR_reg_t fallback_this,
MIR_reg_t r_flags, MIR_reg_t r_bound) {
MIR_label_t not_arrow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_flags),
MIR_new_mem_op(ctx, MIR_T_U32,
(MIR_disp_t)offsetof(sv_closure_t, call_flags),
r_closure, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, r_flags),
MIR_new_reg_op(ctx, r_flags),
MIR_new_uint_op(ctx, SV_CALL_IS_ARROW)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, not_arrow),
MIR_new_reg_op(ctx, r_flags),
MIR_new_uint_op(ctx, 0)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)offsetof(sv_closure_t, bound_this),
r_closure, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, fn, not_arrow);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, fallback_this)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bound),
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)offsetof(sv_closure_t, bound_this),
r_closure, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, done),
MIR_new_reg_op(ctx, r_bound),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0))));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_bound)));
MIR_append_insn(ctx, fn, done);
}
static void mir_emit_value_to_objptr_or_jmp(
MIR_context_t ctx, MIR_item_t fn,
MIR_reg_t v, MIR_reg_t out_ptr,
MIR_reg_t r_tag, MIR_label_t slow
) {
MIR_label_t is_obj = MIR_new_label(ctx);
MIR_label_t is_func = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_tag),
MIR_new_reg_op(ctx, v),
MIR_new_uint_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_obj),
MIR_new_reg_op(ctx, r_tag),
MIR_new_uint_op(ctx, NANBOX_TOBJ_TAG)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_obj),
MIR_new_reg_op(ctx, r_tag),
MIR_new_uint_op(ctx, NANBOX_TARR_TAG)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_obj),
MIR_new_reg_op(ctx, r_tag),
MIR_new_uint_op(ctx, NANBOX_TPROM_TAG)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_func),
MIR_new_reg_op(ctx, r_tag),
MIR_new_uint_op(ctx, NANBOX_TFUNC_TAG)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, slow)));
MIR_append_insn(ctx, fn, is_obj);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, out_ptr),
MIR_new_reg_op(ctx, v),
MIR_new_uint_op(ctx, NANBOX_DATA_MASK)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, fn, is_func);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, out_ptr),
MIR_new_reg_op(ctx, v),
MIR_new_uint_op(ctx, NANBOX_DATA_MASK)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, out_ptr),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_closure_t, func_obj),
out_ptr, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, out_ptr),
MIR_new_reg_op(ctx, out_ptr),
MIR_new_uint_op(ctx, NANBOX_DATA_MASK)));
MIR_append_insn(ctx, fn, done);
}
static bool mir_emit_get_field_ic_fastpath(
MIR_context_t ctx,
MIR_item_t fn,
sv_func_t *func,
int bc_off,
uint16_t ic_idx,
sv_atom_t *atom,
MIR_reg_t obj,
MIR_reg_t dst,
MIR_label_t slow,
MIR_reg_t r_global_epoch
) {
if (!func || !func->ic_slots || !atom) return false;
if (ic_idx == UINT16_MAX || ic_idx >= func->ic_count) return false;
if (is_length_key(atom->str, atom->len)) return false;
sv_ic_entry_t *ic = &func->ic_slots[ic_idx];
if (!sv_gf_ic_active(ic->cached_aux)) return false;
char gf_ic_name[32], gf_ice_name[32];
char gf_ot_name[32], gf_op_name[32], gf_os_name[32], gf_ics_name[32];
char gf_h_name[32], gf_hs_name[32], gf_idx_name[32], gf_pc_name[32];
char gf_ica_name[32], gf_il_name[32], gf_ovf_name[32], gf_ovi_name[32];
char gf_io_name[32], gf_src_name[32];
snprintf(gf_ic_name, sizeof(gf_ic_name), "gf_ic_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_ice_name, sizeof(gf_ice_name), "gf_ice_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_ot_name, sizeof(gf_ot_name), "gf_ot_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_op_name, sizeof(gf_op_name), "gf_op_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_os_name, sizeof(gf_os_name), "gf_os_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_ics_name, sizeof(gf_ics_name), "gf_ics_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_h_name, sizeof(gf_h_name), "gf_h_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_hs_name, sizeof(gf_hs_name), "gf_hs_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_idx_name, sizeof(gf_idx_name), "gf_idx_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_pc_name, sizeof(gf_pc_name), "gf_pc_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_ica_name, sizeof(gf_ica_name), "gf_ica_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_il_name, sizeof(gf_il_name), "gf_il_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_ovf_name, sizeof(gf_ovf_name), "gf_ovf_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_ovi_name, sizeof(gf_ovi_name), "gf_ovi_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_io_name, sizeof(gf_io_name), "gf_io_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(gf_src_name, sizeof(gf_src_name), "gf_src_%d_%u", bc_off, (unsigned)ic_idx);
MIR_reg_t r_ic = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_ic_name);
MIR_reg_t r_ic_epoch = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_ice_name);
MIR_reg_t r_obj_tag = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_ot_name);
MIR_reg_t r_obj_ptr = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_op_name);
MIR_reg_t r_obj_shape = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_os_name);
MIR_reg_t r_ic_shape = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_ics_name);
MIR_reg_t r_holder = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_h_name);
MIR_reg_t r_holder_shape = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_hs_name);
MIR_reg_t r_ic_idx_val = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_idx_name);
MIR_reg_t r_holder_prop_count = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_pc_name);
MIR_reg_t r_ic_aux = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_ica_name);
MIR_reg_t r_inobj_limit = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_il_name);
MIR_reg_t r_overflow = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_ovf_name);
MIR_reg_t r_overflow_idx = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_ovi_name);
MIR_reg_t r_is_own = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_io_name);
MIR_reg_t r_source = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, gf_src_name);
MIR_label_t load_overflow = MIR_new_label(ctx);
MIR_label_t fast_done = MIR_new_label(ctx);
MIR_label_t own_path = MIR_new_label(ctx);
MIR_label_t do_read = MIR_new_label(ctx);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)ic)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_aux),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_aux), r_ic, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, r_ic_aux),
MIR_new_reg_op(ctx, r_ic_aux),
MIR_new_uint_op(ctx, (uint64_t)SV_GF_IC_AUX_ACTIVE_BIT)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_ic_aux),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_epoch),
MIR_new_mem_op(ctx, MIR_T_U32,
(MIR_disp_t)offsetof(sv_ic_entry_t, epoch), r_ic, 0, 1)));
{
char ce_name[40];
snprintf(ce_name, sizeof(ce_name), "gf_ce_%d_%u", bc_off, (unsigned)ic_idx);
MIR_reg_t r_cur_epoch = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, ce_name);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_cur_epoch),
MIR_new_mem_op(ctx, MIR_T_U32, 0, r_global_epoch, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_ic_epoch),
MIR_new_reg_op(ctx, r_cur_epoch)));
}
mir_emit_value_to_objptr_or_jmp(
ctx, fn, obj, r_obj_ptr, r_obj_tag, slow);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_obj_shape),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(ant_object_t, shape), r_obj_ptr, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_shape),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_shape), r_ic, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_obj_shape),
MIR_new_reg_op(ctx, r_ic_shape)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_is_own),
MIR_new_mem_op(ctx, MIR_T_U8,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_is_own), r_ic, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, own_path),
MIR_new_reg_op(ctx, r_is_own),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_holder),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_holder), r_ic, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_holder),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_holder_shape),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(ant_object_t, shape), r_holder, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_holder_shape),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_source),
MIR_new_reg_op(ctx, r_holder)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, do_read)));
MIR_append_insn(ctx, fn, own_path);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_source),
MIR_new_reg_op(ctx, r_obj_ptr)));
MIR_append_insn(ctx, fn, do_read);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_idx_val),
MIR_new_mem_op(ctx, MIR_T_U32,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_index), r_ic, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_holder_prop_count),
MIR_new_mem_op(ctx, MIR_T_U32,
(MIR_disp_t)offsetof(ant_object_t, prop_count), r_source, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_UBGE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_ic_idx_val),
MIR_new_reg_op(ctx, r_holder_prop_count)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_inobj_limit),
MIR_new_mem_op(ctx, MIR_T_U8,
(MIR_disp_t)offsetof(ant_object_t, inobj_limit), r_source, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_UBGE,
MIR_new_label_op(ctx, load_overflow),
MIR_new_reg_op(ctx, r_ic_idx_val),
MIR_new_reg_op(ctx, r_inobj_limit)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(ant_object_t, inobj), r_source, r_ic_idx_val, 8)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, fast_done)));
MIR_append_insn(ctx, fn, load_overflow);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_overflow),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(ant_object_t, overflow_prop), r_source, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_overflow),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_SUB,
MIR_new_reg_op(ctx, r_overflow_idx),
MIR_new_reg_op(ctx, r_ic_idx_val),
MIR_new_reg_op(ctx, r_inobj_limit)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_T_I64, 0, r_overflow, r_overflow_idx, 8)));
MIR_append_insn(ctx, fn, fast_done);
return true;
}
static bool jit_ic_try_resolve_method(
sv_func_t *func,
uint16_t ic_idx,
sv_atom_t *atom,
jit_method_ic_info_t *out
) {
if (out) *out = (jit_method_ic_info_t){0};
if (!func || !func->ic_slots || !atom || is_length_key(atom->str, atom->len))
return false;
if (ic_idx == UINT16_MAX || ic_idx >= func->ic_count) return false;
sv_ic_entry_t *ic = &func->ic_slots[ic_idx];
if (!sv_gf_ic_active(ic->cached_aux)) return false;
if (ic->epoch != ant_ic_epoch_counter) return false;
if (!ic->cached_shape || !ic->cached_holder) return false;
if (ic->cached_index >= ic->cached_holder->prop_count) return false;
ant_shape_t *prop_shape = ic->cached_is_own
? ic->cached_shape
: ic->cached_holder->shape;
if (!prop_shape) return false;
const ant_shape_prop_t *prop = ant_shape_prop_at(prop_shape, ic->cached_index);
if (!prop) return false;
if (!jit_atom_matches_shape_prop(atom, prop)) return false;
if (prop->has_getter || prop->has_setter) return false;
ant_value_t value = ant_object_prop_get_unchecked(ic->cached_holder, ic->cached_index);
if (vtype(value) != T_FUNC) return false;
sv_closure_t *closure = js_func_closure(value);
if (!closure || !closure->func) return false;
if (closure->func->is_arrow) return false;
if (closure->call_flags & SV_CALL_HAS_BOUND_ARGS)
return false;
if (vtype(closure->bound_this) != T_UNDEF) return false;
if (out) {
out->ic = ic;
out->receiver_shape = ic->cached_shape;
out->callee = closure->func;
out->valid = true;
}
return true;
}
static bool jit_ic_direct_this_slot(
sv_func_t *func,
uint16_t ic_idx,
sv_atom_t *atom,
ant_shape_t *receiver_shape,
bool require_writable,
sv_ic_entry_t **out_ic,
uint32_t *out_index
) {
if (out_ic) *out_ic = NULL;
if (out_index) *out_index = 0;
if (!func || !func->ic_slots || !atom || !receiver_shape) return false;
if (ic_idx == UINT16_MAX || ic_idx >= func->ic_count) return false;
if (is_length_key(atom->str, atom->len)) return false;
sv_ic_entry_t *ic = &func->ic_slots[ic_idx];
if (!require_writable && !sv_gf_ic_active(ic->cached_aux)) return false;
if (ic->epoch != ant_ic_epoch_counter) return false;
if (!require_writable && !ic->cached_is_own) return false;
if (ic->cached_shape != receiver_shape) return false;
if (!ic->cached_holder || ic->cached_holder->shape != receiver_shape) return false;
if (ic->cached_index >= ic->cached_holder->prop_count) return false;
const ant_shape_prop_t *prop = ant_shape_prop_at(receiver_shape, ic->cached_index);
if (!prop) return false;
if (!jit_atom_matches_shape_prop(atom, prop)) return false;
if (prop->has_getter || prop->has_setter) return false;
if (require_writable && (prop->attrs & ANT_PROP_ATTR_WRITABLE) == 0)
return false;
if (out_ic) *out_ic = ic;
if (out_index) *out_index = ic->cached_index;
return true;
}
static bool jit_shape_direct_this_slot(
sv_atom_t *atom,
ant_shape_t *receiver_shape,
bool require_writable,
uint32_t *out_index
) {
if (out_index) *out_index = 0;
if (!atom || !receiver_shape || is_length_key(atom->str, atom->len))
return false;
int32_t slot = ant_shape_lookup_interned(receiver_shape, atom->str);
if (slot < 0) {
uint32_t count = ant_shape_count(receiver_shape);
for (uint32_t i = 0; i < count; i++) {
const ant_shape_prop_t *candidate = ant_shape_prop_at(receiver_shape, i);
if (jit_atom_matches_shape_prop(atom, candidate)) {
slot = (int32_t)i;
break;
}
}
}
if (slot < 0) return false;
const ant_shape_prop_t *prop = ant_shape_prop_at(receiver_shape, (uint32_t)slot);
if (!prop) return false;
if (!jit_atom_matches_shape_prop(atom, prop)) return false;
if (prop->has_getter || prop->has_setter) return false;
if (require_writable && (prop->attrs & ANT_PROP_ATTR_WRITABLE) == 0)
return false;
if (out_index) *out_index = (uint32_t)slot;
return true;
}
static void mir_emit_ic_epoch_guard(
MIR_context_t ctx,
MIR_item_t fn,
sv_ic_entry_t *ic,
MIR_reg_t r_global_epoch,
MIR_label_t slow,
const char *name
) {
if (!ic || !r_global_epoch) {
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, slow)));
return;
}
char rn_ic[48], rn_epoch[48], rn_cur_epoch[48];
snprintf(rn_ic, sizeof(rn_ic), "%s_ic", name);
snprintf(rn_epoch, sizeof(rn_epoch), "%s_epoch", name);
snprintf(rn_cur_epoch, sizeof(rn_cur_epoch), "%s_cur_epoch", name);
MIR_reg_t r_ic = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_ic);
MIR_reg_t r_epoch = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_epoch);
MIR_reg_t r_cur_epoch = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_cur_epoch);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)ic)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_epoch),
MIR_new_mem_op(ctx, MIR_T_U32,
(MIR_disp_t)offsetof(sv_ic_entry_t, epoch), r_ic, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_cur_epoch),
MIR_new_mem_op(ctx, MIR_T_U32, 0, r_global_epoch, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_epoch),
MIR_new_reg_op(ctx, r_cur_epoch)));
}
static void mir_emit_ic_active_epoch_guard(
MIR_context_t ctx,
MIR_item_t fn,
sv_ic_entry_t *ic,
MIR_reg_t r_global_epoch,
MIR_label_t slow,
const char *name
) {
if (!ic || !r_global_epoch) {
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, slow)));
return;
}
char rn_ic[48], rn_aux[48], rn_epoch[48], rn_cur_epoch[48];
snprintf(rn_ic, sizeof(rn_ic), "%s_ic", name);
snprintf(rn_aux, sizeof(rn_aux), "%s_aux", name);
snprintf(rn_epoch, sizeof(rn_epoch), "%s_epoch", name);
snprintf(rn_cur_epoch, sizeof(rn_cur_epoch), "%s_cur_epoch", name);
MIR_reg_t r_ic = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_ic);
MIR_reg_t r_aux = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_aux);
MIR_reg_t r_epoch = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_epoch);
MIR_reg_t r_cur_epoch = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_cur_epoch);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)ic)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_aux),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_aux), r_ic, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, r_aux),
MIR_new_reg_op(ctx, r_aux),
MIR_new_uint_op(ctx, (uint64_t)SV_GF_IC_AUX_ACTIVE_BIT)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_aux),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_epoch),
MIR_new_mem_op(ctx, MIR_T_U32,
(MIR_disp_t)offsetof(sv_ic_entry_t, epoch), r_ic, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_cur_epoch),
MIR_new_mem_op(ctx, MIR_T_U32, 0, r_global_epoch, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_epoch),
MIR_new_reg_op(ctx, r_cur_epoch)));
}
static void mir_emit_method_receiver_shape_guard(
MIR_context_t ctx,
MIR_item_t fn,
jit_method_ic_info_t *mi,
MIR_reg_t receiver,
MIR_reg_t r_obj_ptr,
MIR_reg_t r_shape,
MIR_reg_t r_tag,
MIR_reg_t r_global_epoch,
MIR_label_t slow,
int id
) {
char guard_name[48];
snprintf(guard_name, sizeof(guard_name), "minl%d_recv", id);
mir_emit_ic_active_epoch_guard(ctx, fn, mi ? mi->ic : NULL,
r_global_epoch, slow, guard_name);
mir_emit_value_to_objptr_or_jmp(ctx, fn, receiver, r_obj_ptr, r_tag, slow);
char rn_ic[48], rn_expected_shape[48];
snprintf(rn_ic, sizeof(rn_ic), "minl%d_recv_shape_ic", id);
snprintf(rn_expected_shape, sizeof(rn_expected_shape), "minl%d_recv_shape", id);
MIR_reg_t r_ic = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_ic);
MIR_reg_t r_expected_shape = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_expected_shape);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)(mi ? mi->ic : NULL))));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_expected_shape),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_shape), r_ic, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_shape),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(ant_object_t, shape), r_obj_ptr, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_shape),
MIR_new_reg_op(ctx, r_expected_shape)));
}
static void mir_emit_this_slot_load(
MIR_context_t ctx,
MIR_item_t fn,
MIR_reg_t dst,
MIR_reg_t r_obj_ptr,
uint32_t prop_index,
MIR_label_t slow,
int id,
int bc_off
) {
char rn_idx[48], rn_pc[48], rn_il[48], rn_ovf[48], rn_ovi[48];
snprintf(rn_idx, sizeof(rn_idx), "inl%d_gf_idx_%d", id, bc_off);
snprintf(rn_pc, sizeof(rn_pc), "inl%d_gf_pc_%d", id, bc_off);
snprintf(rn_il, sizeof(rn_il), "inl%d_gf_il_%d", id, bc_off);
snprintf(rn_ovf, sizeof(rn_ovf), "inl%d_gf_ovf_%d", id, bc_off);
snprintf(rn_ovi, sizeof(rn_ovi), "inl%d_gf_ovi_%d", id, bc_off);
MIR_reg_t r_idx = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_idx);
MIR_reg_t r_prop_count = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_pc);
MIR_reg_t r_inobj_limit = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_il);
MIR_reg_t r_overflow = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_ovf);
MIR_reg_t r_overflow_idx = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_ovi);
MIR_label_t load_overflow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_idx),
MIR_new_uint_op(ctx, (uint64_t)prop_index)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_prop_count),
MIR_new_mem_op(ctx, MIR_T_U32,
(MIR_disp_t)offsetof(ant_object_t, prop_count), r_obj_ptr, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_UBGE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_idx),
MIR_new_reg_op(ctx, r_prop_count)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_inobj_limit),
MIR_new_mem_op(ctx, MIR_T_U8,
(MIR_disp_t)offsetof(ant_object_t, inobj_limit), r_obj_ptr, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_UBGE,
MIR_new_label_op(ctx, load_overflow),
MIR_new_reg_op(ctx, r_idx),
MIR_new_reg_op(ctx, r_inobj_limit)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(ant_object_t, inobj), r_obj_ptr, r_idx, 8)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, fn, load_overflow);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_overflow),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(ant_object_t, overflow_prop), r_obj_ptr, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_overflow),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_SUB,
MIR_new_reg_op(ctx, r_overflow_idx),
MIR_new_reg_op(ctx, r_idx),
MIR_new_reg_op(ctx, r_inobj_limit)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_T_I64, 0, r_overflow, r_overflow_idx, 8)));
MIR_append_insn(ctx, fn, done);
}
static void mir_emit_this_slot_store_num(
MIR_context_t ctx,
MIR_item_t fn,
MIR_reg_t val,
MIR_reg_t r_obj_ptr,
uint32_t prop_index,
MIR_label_t slow,
MIR_reg_t r_bool,
int id,
int bc_off
) {
mir_emit_is_num_guard(ctx, fn, r_bool, val, slow);
char rn_idx[48], rn_pc[48], rn_il[48], rn_ovf[48], rn_ovi[48];
snprintf(rn_idx, sizeof(rn_idx), "inl%d_pf_idx_%d", id, bc_off);
snprintf(rn_pc, sizeof(rn_pc), "inl%d_pf_pc_%d", id, bc_off);
snprintf(rn_il, sizeof(rn_il), "inl%d_pf_il_%d", id, bc_off);
snprintf(rn_ovf, sizeof(rn_ovf), "inl%d_pf_ovf_%d", id, bc_off);
snprintf(rn_ovi, sizeof(rn_ovi), "inl%d_pf_ovi_%d", id, bc_off);
MIR_reg_t r_idx = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_idx);
MIR_reg_t r_prop_count = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_pc);
MIR_reg_t r_inobj_limit = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_il);
MIR_reg_t r_overflow = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_ovf);
MIR_reg_t r_overflow_idx = MIR_new_func_reg(ctx, fn->u.func, MIR_T_I64, rn_ovi);
MIR_label_t store_overflow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_idx),
MIR_new_uint_op(ctx, (uint64_t)prop_index)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_prop_count),
MIR_new_mem_op(ctx, MIR_T_U32,
(MIR_disp_t)offsetof(ant_object_t, prop_count), r_obj_ptr, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_UBGE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_idx),
MIR_new_reg_op(ctx, r_prop_count)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_inobj_limit),
MIR_new_mem_op(ctx, MIR_T_U8,
(MIR_disp_t)offsetof(ant_object_t, inobj_limit), r_obj_ptr, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_UBGE,
MIR_new_label_op(ctx, store_overflow),
MIR_new_reg_op(ctx, r_idx),
MIR_new_reg_op(ctx, r_inobj_limit)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(ant_object_t, inobj), r_obj_ptr, r_idx, 8),
MIR_new_reg_op(ctx, val)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, fn, store_overflow);
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_overflow),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(ant_object_t, overflow_prop), r_obj_ptr, 0, 1)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_overflow),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_SUB,
MIR_new_reg_op(ctx, r_overflow_idx),
MIR_new_reg_op(ctx, r_idx),
MIR_new_reg_op(ctx, r_inobj_limit)));
MIR_append_insn(ctx, fn,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64, 0, r_overflow, r_overflow_idx, 8),
MIR_new_reg_op(ctx, val)));
MIR_append_insn(ctx, fn, done);
}
#define MAX_OSR_ENTRIES 64
typedef struct {
int offsets[MAX_OSR_ENTRIES];
int count;
} osr_entry_map_t;
static void scan_osr_entries(sv_func_t *func, osr_entry_map_t *osr) {
osr->count = 0;
uint8_t *ip = func->code;
uint8_t *end = func->code + func->code_len;
while (ip < end) {
sv_op_t op = (sv_op_t)*ip;
int sz = sv_op_size[op];
if (sz == 0) break;
int src = (int)(ip - func->code);
int target = -1;
switch (op) {
case OP_JMP:
case OP_JMP_FALSE:
case OP_JMP_TRUE:
case OP_JMP_FALSE_PEEK:
case OP_JMP_TRUE_PEEK:
case OP_JMP_NOT_NULLISH:
target = src + sz + sv_get_i32(ip + 1);
break;
case OP_JMP8:
case OP_JMP_FALSE8:
case OP_JMP_TRUE8:
target = src + sz + (int8_t)sv_get_i8(ip + 1);
break;
default: break;
}
if (target >= 0 && target < src) {
bool found = false;
for (int i = 0; i < osr->count; i++)
if (osr->offsets[i] == target) { found = true; break; }
if (!found && osr->count < MAX_OSR_ENTRIES)
osr->offsets[osr->count++] = target;
}
ip += sz;
}
}
static sv_func_t *scan_closure_child(sv_func_t *func, uint8_t *ip) {
if ((sv_op_t)*ip != OP_CLOSURE) return NULL;
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)func->const_count) return NULL;
ant_value_t cv = func->constants[idx];
if (vtype(cv) != T_NTARG) return NULL;
return (sv_func_t *)(uintptr_t)vdata(cv);
}
typedef enum {
JIT_CHILD_PLAIN = 0,
JIT_CHILD_INHERITED_ONLY,
JIT_CHILD_LOCAL_ONLY,
JIT_CHILD_PARAM_ONLY,
JIT_CHILD_MIXED,
} jit_child_kind_t;
static jit_child_kind_t classify_child_closure_kind(sv_func_t *parent, sv_func_t *child) {
if (!parent || !child || child->upvalue_count <= 0) return JIT_CHILD_PLAIN;
bool has_inherited = false;
bool has_param = false;
bool has_local = false;
for (int i = 0; i < child->upvalue_count; i++) {
sv_upval_desc_t *desc = &child->upval_descs[i];
if (!desc->is_local) {
has_inherited = true;
continue;
}
if (desc->index < (uint16_t)parent->param_count) has_param = true;
else has_local = true;
}
if (!has_param && !has_local) return has_inherited ? JIT_CHILD_INHERITED_ONLY : JIT_CHILD_PLAIN;
if (has_param && !has_local) return JIT_CHILD_PARAM_ONLY;
if (has_local && !has_param) return JIT_CHILD_LOCAL_ONLY;
return JIT_CHILD_MIXED;
}
static bool *scan_captured_locals(sv_func_t *func, int n_locals) {
if (n_locals <= 0) return NULL;
bool *captured = calloc((size_t)n_locals, sizeof(bool));
if (!captured) return NULL;
uint8_t *ip = func->code;
uint8_t *end = func->code + func->code_len;
while (ip < end) {
sv_op_t op = (sv_op_t)*ip;
int sz = sv_op_size[op];
if (sz == 0) break;
sv_func_t *child = scan_closure_child(func, ip);
if (!child) {
ip += sz;
continue;
}
for (int i = 0; i < child->upvalue_count; i++) {
sv_upval_desc_t *desc = &child->upval_descs[i];
if (!desc->is_local) continue;
int li = (int)desc->index - func->param_count;
if (li < 0 || li >= n_locals) continue;
captured[li] = true;
}
ip += sz;
}
return captured;
}
static bool *scan_captured_params(sv_func_t *func) {
int param_count = func ? func->param_count : 0;
if (param_count <= 0) return NULL;
bool *captured = calloc((size_t)param_count, sizeof(bool));
if (!captured) return NULL;
uint8_t *ip = func->code;
uint8_t *end = func->code + func->code_len;
while (ip < end) {
sv_op_t op = (sv_op_t)*ip;
int sz = sv_op_size[op];
if (sz == 0) break;
sv_func_t *child = scan_closure_child(func, ip);
if (!child) {
ip += sz;
continue;
}
for (int i = 0; i < child->upvalue_count; i++) {
sv_upval_desc_t *desc = &child->upval_descs[i];
if (!desc->is_local) continue;
if (desc->index >= (uint16_t)param_count) continue;
captured[desc->index] = true;
}
ip += sz;
}
return captured;
}
#define JIT_INLINE_MAX_BYTECODE 64
#define JIT_INLINE_MAX_DEPTH 3
#define JIT_INLINE_BUDGET 512
static bool jit_inlineable(sv_func_t *f) {
if (!f) return false;
if (f->is_async || f->is_generator) return false;
if (f->code_len > JIT_INLINE_MAX_BYTECODE) return false;
uint8_t *ip = f->code;
uint8_t *end = f->code + f->code_len;
while (ip < end) {
sv_op_t op = (sv_op_t)*ip;
int sz = sv_op_size[op];
if (sz == 0) return false;
switch (op) {
case OP_GET_ARG:
case OP_CONST_I8: case OP_CONST: case OP_CONST8:
case OP_UNDEF: case OP_NULL: case OP_TRUE: case OP_FALSE:
case OP_THIS:
case OP_GET_LOCAL: case OP_GET_LOCAL8:
case OP_PUT_LOCAL: case OP_PUT_LOCAL8:
case OP_SET_LOCAL: case OP_SET_LOCAL8:
case OP_SET_LOCAL_UNDEF:
case OP_GET_UPVAL:
case OP_POP: case OP_DUP: case OP_DUP2:
case OP_INSERT2: case OP_INSERT3:
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
case OP_ADD_NUM: case OP_SUB_NUM: case OP_MUL_NUM: case OP_DIV_NUM:
case OP_MOD: case OP_NEG:
case OP_LT: case OP_LE: case OP_GT: case OP_GE:
case OP_SEQ: case OP_SNE: case OP_EQ: case OP_NE:
case OP_IS_UNDEF: case OP_IS_NULL:
case OP_JMP: case OP_JMP_TRUE: case OP_JMP_FALSE:
case OP_JMP_TRUE8: case OP_JMP_FALSE8:
case OP_JMP_TRUE_PEEK: case OP_JMP_FALSE_PEEK:
case OP_RETURN: case OP_RETURN_UNDEF:
case OP_GET_FIELD: case OP_GET_FIELD2: case OP_PUT_FIELD:
case OP_GET_GLOBAL:
case OP_NOP: case OP_LINE_NUM: case OP_COL_NUM: case OP_LABEL:
break;
case OP_SPECIAL_OBJ:
// OP_SPECIAL_OBJ(0) materializes `arguments`. keep these functions on
// the interpreter until JIT routes a real per-call activation/object
// with matching lifetime and semantics.
if (sv_get_u8(ip + 1) == 0) return false;
break;
default:
return false;
}
ip += sz;
}
return true;
}
#define INL_MAX_LABELS 128
typedef struct {
int bc_off;
MIR_label_t label;
int sp;
} inl_label_entry_t;
typedef struct {
inl_label_entry_t entries[INL_MAX_LABELS];
int count;
} inl_label_map_t;
static MIR_label_t inl_label_for_offset(MIR_context_t ctx,
inl_label_map_t *lm,
int bc_off, int sp) {
for (int i = 0; i < lm->count; i++)
if (lm->entries[i].bc_off == bc_off) {
if (lm->entries[i].sp < 0) lm->entries[i].sp = sp;
return lm->entries[i].label;
}
if (lm->count >= INL_MAX_LABELS) return NULL;
MIR_label_t lbl = MIR_new_label(ctx);
lm->entries[lm->count].bc_off = bc_off;
lm->entries[lm->count].label = lbl;
lm->entries[lm->count].sp = sp;
lm->count++;
return lbl;
}
static MIR_label_t inl_label_lookup(inl_label_map_t *lm, int bc_off, int *out_sp) {
for (int i = 0; i < lm->count; i++)
if (lm->entries[i].bc_off == bc_off) {
if (out_sp) *out_sp = lm->entries[i].sp;
return lm->entries[i].label;
}
return NULL;
}
static bool jit_inline_body_feasible(sv_func_t *callee) {
if (!callee) return false;
int max_stack = callee->max_stack > 0 ? callee->max_stack : 4;
int n_locals = callee->max_locals > 0 ? callee->max_locals : 1;
uint8_t stack_types[max_stack];
uint8_t local_types[n_locals];
memset(stack_types, SLOT_BOXED, sizeof(stack_types));
memset(local_types, SLOT_BOXED, sizeof(local_types));
int sp = 0;
bool side_effect_seen = false;
#define FEAS_POP(n) do { if (sp < (n)) return false; sp -= (n); } while (0)
#define FEAS_PUSH(t) do { if (sp >= max_stack) return false; stack_types[sp++] = (t); } while (0)
#define FEAS_GUARD_AFTER_EFFECT() do { if (side_effect_seen) return false; } while (0)
uint8_t *ip = callee->code;
uint8_t *end = callee->code + callee->code_len;
while (ip < end) {
sv_op_t op = (sv_op_t)*ip;
int sz = sv_op_size[op];
if (sz == 0) return false;
switch (op) {
case OP_GET_ARG:
FEAS_PUSH(SLOT_BOXED);
break;
case OP_CONST_I8:
FEAS_PUSH(SLOT_NUM);
break;
case OP_CONST: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)callee->const_count) return false;
FEAS_PUSH(vtype(callee->constants[idx]) == T_NUM ? SLOT_NUM : SLOT_BOXED);
break;
}
case OP_CONST8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)callee->const_count) return false;
FEAS_PUSH(vtype(callee->constants[idx]) == T_NUM ? SLOT_NUM : SLOT_BOXED);
break;
}
case OP_UNDEF: case OP_NULL: case OP_TRUE: case OP_FALSE:
case OP_THIS:
case OP_GET_UPVAL:
case OP_GET_GLOBAL:
case OP_SPECIAL_OBJ:
if (side_effect_seen && (op == OP_GET_GLOBAL || op == OP_SPECIAL_OBJ))
return false;
FEAS_PUSH(SLOT_BOXED);
break;
case OP_GET_LOCAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)n_locals) return false;
FEAS_PUSH(local_types[idx]);
break;
}
case OP_GET_LOCAL8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)n_locals) return false;
FEAS_PUSH(local_types[idx]);
break;
}
case OP_PUT_LOCAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)n_locals || sp < 1) return false;
local_types[idx] = stack_types[--sp];
break;
}
case OP_PUT_LOCAL8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)n_locals || sp < 1) return false;
local_types[idx] = stack_types[--sp];
break;
}
case OP_SET_LOCAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)n_locals || sp < 1) return false;
local_types[idx] = stack_types[sp - 1];
break;
}
case OP_SET_LOCAL8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)n_locals || sp < 1) return false;
local_types[idx] = stack_types[sp - 1];
break;
}
case OP_SET_LOCAL_UNDEF: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)n_locals) return false;
local_types[idx] = SLOT_BOXED;
break;
}
case OP_POP:
FEAS_POP(1);
break;
case OP_DUP:
if (sp < 1) return false;
{ uint8_t top_type = stack_types[sp - 1]; FEAS_PUSH(top_type); }
break;
case OP_DUP2: {
if (sp < 2) return false;
uint8_t a = stack_types[sp - 2];
uint8_t b = stack_types[sp - 1];
FEAS_PUSH(a);
FEAS_PUSH(b);
break;
}
case OP_INSERT2: {
if (sp < 2) return false;
uint8_t a = stack_types[sp - 1];
uint8_t obj = stack_types[sp - 2];
stack_types[sp - 2] = a;
stack_types[sp - 1] = obj;
FEAS_PUSH(a);
break;
}
case OP_INSERT3: {
if (sp < 3) return false;
uint8_t a = stack_types[sp - 1];
uint8_t prop = stack_types[sp - 2];
uint8_t obj = stack_types[sp - 3];
stack_types[sp - 3] = a;
stack_types[sp - 2] = obj;
stack_types[sp - 1] = prop;
FEAS_PUSH(a);
break;
}
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
case OP_ADD_NUM: case OP_SUB_NUM: case OP_MUL_NUM: case OP_DIV_NUM: {
if (sp < 2) return false;
bool known_num =
stack_types[sp - 1] == SLOT_NUM && stack_types[sp - 2] == SLOT_NUM;
if (!known_num) FEAS_GUARD_AFTER_EFFECT();
sp -= 2;
FEAS_PUSH(SLOT_NUM);
break;
}
case OP_MOD:
FEAS_GUARD_AFTER_EFFECT();
FEAS_POP(2);
FEAS_PUSH(SLOT_NUM);
break;
case OP_NEG:
if (sp < 1) return false;
FEAS_GUARD_AFTER_EFFECT();
stack_types[sp - 1] = SLOT_NUM;
break;
case OP_LT: case OP_LE: case OP_GT: case OP_GE:
FEAS_GUARD_AFTER_EFFECT();
FEAS_POP(2);
FEAS_PUSH(SLOT_BOXED);
break;
case OP_SEQ: case OP_SNE: case OP_EQ: case OP_NE:
FEAS_POP(2);
FEAS_PUSH(SLOT_BOXED);
break;
case OP_IS_UNDEF: case OP_IS_NULL:
if (sp < 1) return false;
stack_types[sp - 1] = SLOT_BOXED;
break;
case OP_JMP:
case OP_NOP: case OP_LINE_NUM: case OP_COL_NUM: case OP_LABEL:
break;
case OP_JMP_TRUE: case OP_JMP_FALSE:
case OP_JMP_TRUE8: case OP_JMP_FALSE8:
FEAS_POP(1);
break;
case OP_JMP_TRUE_PEEK: case OP_JMP_FALSE_PEEK:
if (sp < 1) return false;
break;
case OP_RETURN:
FEAS_POP(1);
break;
case OP_RETURN_UNDEF:
break;
case OP_GET_FIELD:
if (side_effect_seen) return false;
FEAS_POP(1);
FEAS_PUSH(SLOT_BOXED);
break;
case OP_GET_FIELD2:
if (side_effect_seen) return false;
if (sp < 1) return false;
FEAS_PUSH(SLOT_BOXED);
break;
case OP_PUT_FIELD:
FEAS_POP(2);
side_effect_seen = true;
break;
default:
return false;
}
ip += sz;
}
#undef FEAS_GUARD_AFTER_EFFECT
#undef FEAS_PUSH
#undef FEAS_POP
return true;
}
static bool jit_emit_inline_body(
MIR_context_t ctx, MIR_item_t jit_func,
sv_func_t *callee,
MIR_reg_t *arg_regs, int caller_argc,
MIR_reg_t result, MIR_label_t slow, MIR_label_t join,
MIR_reg_t r_bool, MIR_reg_t *p_d_slot, int id,
MIR_reg_t r_inl_closure, MIR_reg_t r_inl_this,
MIR_reg_t r_inl_new_target, MIR_reg_t r_inl_super,
ant_shape_t *guarded_this_shape,
MIR_reg_t r_guarded_this_obj, MIR_reg_t r_guarded_this_shape,
MIR_reg_t r_global_epoch,
MIR_reg_t r_vm, MIR_reg_t r_js,
MIR_item_t helper2_proto, MIR_item_t imp_seq,
MIR_item_t imp_sne, MIR_item_t imp_eq, MIR_item_t imp_ne,
MIR_item_t gf_proto, MIR_item_t imp_get_field,
MIR_item_t put_field_proto, MIR_item_t imp_put_field,
MIR_item_t gg_proto, MIR_item_t imp_gg,
MIR_item_t special_obj_proto, MIR_item_t imp_special_obj
) {
int inl_max_stack = callee->max_stack > 0 ? callee->max_stack : 4;
MIR_reg_t inl_vs[inl_max_stack];
uint8_t inl_slot_type[inl_max_stack];
bool inl_is_this[inl_max_stack];
memset(inl_slot_type, SLOT_BOXED, sizeof(inl_slot_type));
memset(inl_is_this, 0, sizeof(inl_is_this));
#define INL_RESET_SLOT(i) do { inl_slot_type[(i)] = SLOT_BOXED; inl_is_this[(i)] = false; } while (0)
#define INL_MARK_NUM(i) do { inl_slot_type[(i)] = SLOT_NUM; inl_is_this[(i)] = false; } while (0)
for (int i = 0; i < inl_max_stack; i++) {
char rn[32]; snprintf(rn, sizeof(rn), "inl%d_s%d", id, i);
inl_vs[i] = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rn);
}
int isp = 0;
int inl_n_locals = callee->max_locals;
MIR_reg_t inl_locals[inl_n_locals > 0 ? inl_n_locals : 1];
for (int i = 0; i < inl_n_locals; i++) {
char rn[32]; snprintf(rn, sizeof(rn), "inl%d_l%d", id, i);
inl_locals[i] = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rn);
mir_load_imm(ctx, jit_func, inl_locals[i], mkval(T_UNDEF, 0));
}
int inl_arith = 0;
int inl_upval_n = 0;
inl_label_map_t inl_lm = {.count = 0};
uint8_t *code_base = callee->code;
uint8_t *ip = callee->code;
uint8_t *end = callee->code + callee->code_len;
while (ip < end) {
sv_op_t op = (sv_op_t)*ip;
int sz = sv_op_size[op];
int inl_bc_off = (int)(ip - code_base);
int label_sp = -1;
MIR_label_t target_lbl = inl_label_lookup(&inl_lm, inl_bc_off, &label_sp);
if (target_lbl) {
MIR_append_insn(ctx, jit_func, target_lbl);
if (label_sp >= 0) isp = label_sp;
}
switch (op) {
case OP_GET_ARG: {
uint16_t idx = sv_get_u16(ip + 1);
int dst_i = isp;
MIR_reg_t dst = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
if ((int)idx < caller_argc)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, arg_regs[idx])));
else
mir_load_imm(ctx, jit_func, dst, mkval(T_UNDEF, 0));
break;
}
case OP_CONST_I8: {
double d = (double)(int8_t)sv_get_i8(ip + 1);
union { double d; uint64_t u; } u = {d};
int dst_i = isp;
mir_load_imm(ctx, jit_func, inl_vs[isp++], u.u);
INL_MARK_NUM(dst_i);
break;
}
case OP_CONST: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)callee->const_count) return false;
ant_value_t cv = callee->constants[idx];
int dst_i = isp;
MIR_reg_t dst = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
if (jit_const_is_heap(cv))
mir_load_const_slot(ctx, jit_func, dst, &callee->constants[idx]);
else {
mir_load_imm(ctx, jit_func, dst, cv);
if (vtype(cv) == T_NUM) INL_MARK_NUM(dst_i);
}
break;
}
case OP_CONST8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)callee->const_count) return false;
ant_value_t cv = callee->constants[idx];
int dst_i = isp;
MIR_reg_t dst = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
if (jit_const_is_heap(cv))
mir_load_const_slot(ctx, jit_func, dst, &callee->constants[idx]);
else {
mir_load_imm(ctx, jit_func, dst, cv);
if (vtype(cv) == T_NUM) INL_MARK_NUM(dst_i);
}
break;
}
case OP_UNDEF: { int dst_i = isp; mir_load_imm(ctx, jit_func, inl_vs[isp++], mkval(T_UNDEF, 0)); INL_RESET_SLOT(dst_i); break; }
case OP_NULL: { int dst_i = isp; mir_load_imm(ctx, jit_func, inl_vs[isp++], mkval(T_NULL, 0)); INL_RESET_SLOT(dst_i); break; }
case OP_TRUE: { int dst_i = isp; mir_load_imm(ctx, jit_func, inl_vs[isp++], js_true); INL_RESET_SLOT(dst_i); break; }
case OP_FALSE: { int dst_i = isp; mir_load_imm(ctx, jit_func, inl_vs[isp++], js_false); INL_RESET_SLOT(dst_i); break; }
case OP_THIS: {
int dst_i = isp;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp++]),
MIR_new_reg_op(ctx, r_inl_this)));
INL_RESET_SLOT(dst_i);
inl_is_this[dst_i] = true;
break;
}
case OP_GET_LOCAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)inl_n_locals) return false;
int dst_i = isp;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp++]),
MIR_new_reg_op(ctx, inl_locals[idx])));
INL_RESET_SLOT(dst_i);
break;
}
case OP_GET_LOCAL8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)inl_n_locals) return false;
int dst_i = isp;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp++]),
MIR_new_reg_op(ctx, inl_locals[idx])));
INL_RESET_SLOT(dst_i);
break;
}
case OP_PUT_LOCAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)inl_n_locals) return false;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_locals[idx]),
MIR_new_reg_op(ctx, inl_vs[--isp])));
break;
}
case OP_PUT_LOCAL8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)inl_n_locals) return false;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_locals[idx]),
MIR_new_reg_op(ctx, inl_vs[--isp])));
break;
}
case OP_SET_LOCAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)inl_n_locals) return false;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_locals[idx]),
MIR_new_reg_op(ctx, inl_vs[isp - 1])));
break;
}
case OP_SET_LOCAL8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)inl_n_locals) return false;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_locals[idx]),
MIR_new_reg_op(ctx, inl_vs[isp - 1])));
break;
}
case OP_SET_LOCAL_UNDEF: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)inl_n_locals) return false;
mir_load_imm(ctx, jit_func, inl_locals[idx], mkval(T_UNDEF, 0));
break;
}
case OP_GET_UPVAL: {
if (!r_inl_closure) return false;
uint16_t idx = sv_get_u16(ip + 1);
int un = inl_upval_n++;
char rn_uvs[32], rn_uv[32], rn_loc[32];
snprintf(rn_uvs, sizeof(rn_uvs), "inl%d_uvs%d", id, un);
snprintf(rn_uv, sizeof(rn_uv), "inl%d_uv%d", id, un);
snprintf(rn_loc, sizeof(rn_loc), "inl%d_uvl%d", id, un);
MIR_reg_t r_uvs = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_uvs);
MIR_reg_t r_uv = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_uv);
MIR_reg_t r_loc = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_loc);
int dst_i = isp;
MIR_reg_t dst = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_uvs),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_closure_t, upvalues),
r_inl_closure, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_uv),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)((int)idx * (int)sizeof(sv_upvalue_t *)),
r_uvs, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_loc),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_upvalue_t, location),
r_uv, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_JSVAL, 0, r_loc, 0, 1)));
break;
}
case OP_POP: isp--; break;
case OP_DUP: {
inl_slot_type[isp] = inl_slot_type[isp - 1];
inl_is_this[isp] = inl_is_this[isp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp]),
MIR_new_reg_op(ctx, inl_vs[isp - 1])));
isp++;
break;
}
case OP_DUP2: {
if (isp < 2) return false;
MIR_reg_t ra = inl_vs[isp - 2];
MIR_reg_t rb = inl_vs[isp - 1];
inl_slot_type[isp] = inl_slot_type[isp - 2];
inl_is_this[isp] = inl_is_this[isp - 2];
inl_slot_type[isp + 1] = inl_slot_type[isp - 1];
inl_is_this[isp + 1] = inl_is_this[isp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp]),
MIR_new_reg_op(ctx, ra)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp + 1]),
MIR_new_reg_op(ctx, rb)));
isp += 2;
break;
}
case OP_INSERT2: {
if (isp < 2) return false;
uint8_t a_type = inl_slot_type[isp - 1];
bool a_is_this = inl_is_this[isp - 1];
uint8_t obj_type = inl_slot_type[isp - 2];
bool obj_is_this = inl_is_this[isp - 2];
char tn[32]; snprintf(tn, sizeof(tn), "inl%d_ins2t", id);
MIR_reg_t r_t = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, tn);
MIR_reg_t r_a = inl_vs[isp - 1];
MIR_reg_t r_obj = inl_vs[isp - 2];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_t),
MIR_new_reg_op(ctx, r_a)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp - 1]),
MIR_new_reg_op(ctx, r_obj)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp - 2]),
MIR_new_reg_op(ctx, r_t)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp]),
MIR_new_reg_op(ctx, r_t)));
inl_slot_type[isp - 2] = a_type;
inl_is_this[isp - 2] = a_is_this;
inl_slot_type[isp - 1] = obj_type;
inl_is_this[isp - 1] = obj_is_this;
inl_slot_type[isp] = a_type;
inl_is_this[isp] = a_is_this;
isp++;
break;
}
case OP_INSERT3: {
if (isp < 3) return false;
uint8_t a_type = inl_slot_type[isp - 1];
bool a_is_this = inl_is_this[isp - 1];
uint8_t prop_type = inl_slot_type[isp - 2];
bool prop_is_this = inl_is_this[isp - 2];
uint8_t obj_type = inl_slot_type[isp - 3];
bool obj_is_this = inl_is_this[isp - 3];
char tn[32]; snprintf(tn, sizeof(tn), "inl%d_ins3t", id);
MIR_reg_t r_t = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, tn);
MIR_reg_t r_a = inl_vs[isp - 1];
MIR_reg_t r_prop = inl_vs[isp - 2];
MIR_reg_t r_obj = inl_vs[isp - 3];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_t),
MIR_new_reg_op(ctx, r_a)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp - 1]),
MIR_new_reg_op(ctx, r_prop)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp - 2]),
MIR_new_reg_op(ctx, r_obj)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp - 3]),
MIR_new_reg_op(ctx, r_t)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, inl_vs[isp]),
MIR_new_reg_op(ctx, r_t)));
inl_slot_type[isp - 3] = a_type;
inl_is_this[isp - 3] = a_is_this;
inl_slot_type[isp - 2] = obj_type;
inl_is_this[isp - 2] = obj_is_this;
inl_slot_type[isp - 1] = prop_type;
inl_is_this[isp - 1] = prop_is_this;
inl_slot_type[isp] = a_type;
inl_is_this[isp] = a_is_this;
isp++;
break;
}
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
case OP_ADD_NUM: case OP_SUB_NUM: case OP_MUL_NUM: case OP_DIV_NUM: {
bool l_known_num = inl_slot_type[isp - 2] == SLOT_NUM;
bool r_known_num = inl_slot_type[isp - 1] == SLOT_NUM;
MIR_reg_t rr = inl_vs[--isp];
MIR_reg_t rl = inl_vs[--isp];
int dst_i = isp;
MIR_reg_t rd = inl_vs[isp++];
if (!l_known_num)
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, slow);
if (!r_known_num)
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
if (!*p_d_slot) {
*p_d_slot = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, "d_slot_inl");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, *p_d_slot),
MIR_new_uint_op(ctx, 8)));
}
int an = inl_arith++;
char d1[32], d2[32], d3[32];
snprintf(d1, sizeof(d1), "inl%d_fd1_%d", id, an);
snprintf(d2, sizeof(d2), "inl%d_fd2_%d", id, an);
snprintf(d3, sizeof(d3), "inl%d_fd3_%d", id, an);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d3);
mir_i64_to_d(ctx, jit_func, fd1, rl, *p_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, *p_d_slot);
MIR_insn_code_t mir_op;
switch (op) {
case OP_ADD:
case OP_ADD_NUM: mir_op = MIR_DADD; break;
case OP_SUB:
case OP_SUB_NUM: mir_op = MIR_DSUB; break;
case OP_MUL:
case OP_MUL_NUM: mir_op = MIR_DMUL; break;
default: mir_op = MIR_DDIV; break;
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, mir_op,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, rd, fd3, *p_d_slot);
INL_MARK_NUM(dst_i);
break;
}
case OP_MOD: {
mir_emit_is_num_guard(ctx, jit_func, r_bool, inl_vs[isp - 1], slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, inl_vs[isp - 2], slow);
if (!*p_d_slot) {
*p_d_slot = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, "d_slot_inl");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, *p_d_slot),
MIR_new_uint_op(ctx, 8)));
}
MIR_reg_t rr = inl_vs[--isp];
MIR_reg_t rl = inl_vs[--isp];
int dst_i = isp;
MIR_reg_t rd = inl_vs[isp++];
int mn = inl_arith++;
char md1[32], md2[32], md3[32], md4[32], md5[32];
snprintf(md1, sizeof(md1), "inl%d_mod1_%d", id, mn);
snprintf(md2, sizeof(md2), "inl%d_mod2_%d", id, mn);
snprintf(md3, sizeof(md3), "inl%d_mod3_%d", id, mn);
snprintf(md4, sizeof(md4), "inl%d_mod4_%d", id, mn);
snprintf(md5, sizeof(md5), "inl%d_mod5_%d", id, mn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, md1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, md2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, md3);
MIR_reg_t fd4 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, md4);
MIR_reg_t fd5 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, md5);
mir_i64_to_d(ctx, jit_func, fd1, rl, *p_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, *p_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DDIV,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_D2I,
MIR_new_reg_op(ctx, rd),
MIR_new_reg_op(ctx, fd3)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_I2D,
MIR_new_reg_op(ctx, fd4),
MIR_new_reg_op(ctx, rd)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMUL,
MIR_new_reg_op(ctx, fd4),
MIR_new_reg_op(ctx, fd4),
MIR_new_reg_op(ctx, fd2)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DSUB,
MIR_new_reg_op(ctx, fd5),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd4)));
mir_d_to_i64(ctx, jit_func, rd, fd5, *p_d_slot);
INL_MARK_NUM(dst_i);
break;
}
case OP_NEG: {
MIR_reg_t rs = inl_vs[isp - 1];
mir_emit_is_num_guard(ctx, jit_func, r_bool, rs, slow);
if (!*p_d_slot) {
*p_d_slot = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, "d_slot_inl");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, *p_d_slot),
MIR_new_uint_op(ctx, 8)));
}
int nn = inl_arith++;
char nd1[32], nd2[32];
snprintf(nd1, sizeof(nd1), "inl%d_neg1_%d", id, nn);
snprintf(nd2, sizeof(nd2), "inl%d_neg2_%d", id, nn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, nd1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, nd2);
mir_i64_to_d(ctx, jit_func, fd1, rs, *p_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DNEG,
MIR_new_reg_op(ctx, fd2),
MIR_new_reg_op(ctx, fd1)));
mir_d_to_i64(ctx, jit_func, rs, fd2, *p_d_slot);
INL_MARK_NUM(isp - 1);
break;
}
case OP_LT: case OP_LE: case OP_GT: case OP_GE: {
MIR_reg_t rr = inl_vs[--isp];
MIR_reg_t rl = inl_vs[--isp];
int dst_i = isp;
MIR_reg_t rd = inl_vs[isp++];
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
if (!*p_d_slot) {
*p_d_slot = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, "d_slot_inl");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, *p_d_slot),
MIR_new_uint_op(ctx, 8)));
}
int cn = inl_arith++;
char cd1[32], cd2[32];
snprintf(cd1, sizeof(cd1), "inl%d_cd1_%d", id, cn);
snprintf(cd2, sizeof(cd2), "inl%d_cd2_%d", id, cn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, cd1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, cd2);
mir_i64_to_d(ctx, jit_func, fd1, rl, *p_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, *p_d_slot);
MIR_insn_code_t cmp_op;
const char *cmp_name;
switch (op) {
case OP_LT: cmp_op = MIR_DLT; cmp_name = "lt"; break;
case OP_LE: cmp_op = MIR_DLE; cmp_name = "le"; break;
case OP_GT: cmp_op = MIR_DGT; cmp_name = "gt"; break;
default: cmp_op = MIR_DGE; cmp_name = "ge"; break;
}
char cmp_rn[32];
snprintf(cmp_rn, sizeof(cmp_rn), "inl%d_%s_%d", id, cmp_name, cn);
MIR_reg_t r_tmp = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, cmp_rn);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, cmp_op,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
INL_RESET_SLOT(dst_i);
break;
}
case OP_SEQ: {
MIR_reg_t rr = inl_vs[--isp];
MIR_reg_t rl = inl_vs[--isp];
int dst_i = isp;
MIR_reg_t rd = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_seq,
r_vm, r_js, rl, rr);
break;
}
case OP_SNE: {
MIR_reg_t rr = inl_vs[--isp];
MIR_reg_t rl = inl_vs[--isp];
int dst_i = isp;
MIR_reg_t rd = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_sne,
r_vm, r_js, rl, rr);
break;
}
case OP_EQ: {
MIR_reg_t rr = inl_vs[--isp];
MIR_reg_t rl = inl_vs[--isp];
int dst_i = isp;
MIR_reg_t rd = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_eq,
r_vm, r_js, rl, rr);
break;
}
case OP_NE: {
MIR_reg_t rr = inl_vs[--isp];
MIR_reg_t rl = inl_vs[--isp];
int dst_i = isp;
MIR_reg_t rd = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_ne,
r_vm, r_js, rl, rr);
break;
}
case OP_IS_UNDEF: case OP_IS_NULL: {
MIR_reg_t rs = inl_vs[isp - 1];
uint64_t cmp_val = (op == OP_IS_UNDEF)
? mkval(T_UNDEF, 0) : mkval(T_NULL, 0);
MIR_label_t is_true = MIR_new_label(ctx);
MIR_label_t is_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_true),
MIR_new_reg_op(ctx, rs),
MIR_new_uint_op(ctx, cmp_val)));
mir_load_imm(ctx, jit_func, rs, js_false);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, is_done)));
MIR_append_insn(ctx, jit_func, is_true);
mir_load_imm(ctx, jit_func, rs, js_true);
MIR_append_insn(ctx, jit_func, is_done);
break;
}
case OP_JMP: {
int target = inl_bc_off + sz + sv_get_i32(ip + 1);
MIR_label_t lbl = inl_label_for_offset(ctx, &inl_lm, target, isp);
if (!lbl) return false;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl)));
break;
}
case OP_JMP_TRUE_PEEK: case OP_JMP_FALSE_PEEK:
case OP_JMP_TRUE: case OP_JMP_FALSE:
case OP_JMP_TRUE8: case OP_JMP_FALSE8: {
bool is_peek = (op == OP_JMP_TRUE_PEEK || op == OP_JMP_FALSE_PEEK);
MIR_reg_t cond = is_peek ? inl_vs[isp - 1] : inl_vs[--isp];
bool short_op = (op == OP_JMP_TRUE8 || op == OP_JMP_FALSE8);
bool is_false_branch = (op == OP_JMP_FALSE || op == OP_JMP_FALSE8
|| op == OP_JMP_FALSE_PEEK);
int target = inl_bc_off + sz + (short_op ? (int8_t)sv_get_i8(ip + 1)
: sv_get_i32(ip + 1));
MIR_label_t lbl = inl_label_for_offset(ctx, &inl_lm, target, isp);
if (!lbl) return false;
uint64_t cmp_bool = is_false_branch ? js_false : js_true;
MIR_label_t lbl_not_bool = MIR_new_label(ctx);
MIR_label_t lbl_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, cond),
MIR_new_uint_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, lbl_not_bool),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, js_false >> NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl),
MIR_new_reg_op(ctx, cond),
MIR_new_uint_op(ctx, cmp_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_done)));
MIR_append_insn(ctx, jit_func, lbl_not_bool);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_UBGT,
MIR_new_label_op(ctx, is_false_branch ? lbl_done : lbl),
MIR_new_reg_op(ctx, cond),
MIR_new_uint_op(ctx, NANBOX_PREFIX)));
if (is_false_branch) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_done)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_done)));
}
MIR_append_insn(ctx, jit_func, lbl_done);
break;
}
case OP_GET_FIELD: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)callee->atom_count) return false;
sv_atom_t *atom = &callee->atoms[idx];
int obj_i = --isp;
bool obj_is_this = inl_is_this[obj_i];
MIR_reg_t obj = inl_vs[obj_i];
int dst_i = isp;
MIR_reg_t dst = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
uint16_t ic_idx = sv_get_u16(ip + 5);
sv_ic_entry_t *slot_ic = NULL;
uint32_t slot_idx = 0;
if (obj_is_this && guarded_this_shape && r_guarded_this_obj &&
jit_ic_direct_this_slot(callee, ic_idx, atom, guarded_this_shape,
false, &slot_ic, &slot_idx)) {
char guard_name[48], rn_ic[48], rn_ic_shape[48];
snprintf(guard_name, sizeof(guard_name), "inl%d_gf_epoch_%d", id, inl_bc_off);
snprintf(rn_ic, sizeof(rn_ic), "inl%d_gf_ic_%d", id, inl_bc_off);
snprintf(rn_ic_shape, sizeof(rn_ic_shape), "inl%d_gf_shape_%d", id, inl_bc_off);
mir_emit_ic_active_epoch_guard(ctx, jit_func, slot_ic, r_global_epoch,
slow, guard_name);
MIR_reg_t r_ic = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_ic);
MIR_reg_t r_ic_shape = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_ic_shape);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)slot_ic)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_shape),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_shape), r_ic, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_guarded_this_shape),
MIR_new_reg_op(ctx, r_ic_shape)));
mir_emit_this_slot_load(ctx, jit_func, dst, r_guarded_this_obj,
slot_idx, slow, id, inl_bc_off);
break;
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, gf_proto),
MIR_new_ref_op(ctx, imp_get_field),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)atom->len),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)callee),
MIR_new_int_op(ctx, (int64_t)inl_bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, dst),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
break;
}
case OP_GET_FIELD2: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)callee->atom_count) return false;
sv_atom_t *atom = &callee->atoms[idx];
bool obj_is_this = inl_is_this[isp - 1];
MIR_reg_t obj = inl_vs[isp - 1];
int dst_i = isp;
MIR_reg_t dst = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
uint16_t ic_idx = sv_get_u16(ip + 5);
sv_ic_entry_t *slot_ic = NULL;
uint32_t slot_idx = 0;
if (obj_is_this && guarded_this_shape && r_guarded_this_obj &&
jit_ic_direct_this_slot(callee, ic_idx, atom, guarded_this_shape,
false, &slot_ic, &slot_idx)) {
char guard_name[48], rn_ic[48], rn_ic_shape[48];
snprintf(guard_name, sizeof(guard_name), "inl%d_gf2_epoch_%d", id, inl_bc_off);
snprintf(rn_ic, sizeof(rn_ic), "inl%d_gf2_ic_%d", id, inl_bc_off);
snprintf(rn_ic_shape, sizeof(rn_ic_shape), "inl%d_gf2_shape_%d", id, inl_bc_off);
mir_emit_ic_active_epoch_guard(ctx, jit_func, slot_ic, r_global_epoch,
slow, guard_name);
MIR_reg_t r_ic = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_ic);
MIR_reg_t r_ic_shape = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_ic_shape);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)slot_ic)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_shape),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_shape), r_ic, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_guarded_this_shape),
MIR_new_reg_op(ctx, r_ic_shape)));
mir_emit_this_slot_load(ctx, jit_func, dst, r_guarded_this_obj,
slot_idx, slow, id, inl_bc_off);
break;
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, gf_proto),
MIR_new_ref_op(ctx, imp_get_field),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)atom->len),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)callee),
MIR_new_int_op(ctx, (int64_t)inl_bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, dst),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
break;
}
case OP_PUT_FIELD: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)callee->atom_count) return false;
sv_atom_t *atom = &callee->atoms[idx];
int val_i = --isp;
MIR_reg_t val = inl_vs[val_i];
bool val_is_num = inl_slot_type[val_i] == SLOT_NUM;
int obj_i = --isp;
MIR_reg_t obj = inl_vs[obj_i];
bool obj_is_this = inl_is_this[obj_i];
uint16_t ic_idx = sv_get_u16(ip + 5);
sv_ic_entry_t *slot_ic = NULL;
uint32_t slot_idx = 0;
bool direct_slot = false;
if (obj_is_this && val_is_num && guarded_this_shape && r_guarded_this_obj) {
direct_slot = jit_ic_direct_this_slot(callee, ic_idx, atom, guarded_this_shape,
true, &slot_ic, &slot_idx);
if (!direct_slot)
direct_slot = jit_shape_direct_this_slot(atom, guarded_this_shape,
true, &slot_idx);
}
if (direct_slot) {
char guard_name[48], rn_ic[48], rn_ic_shape[48];
snprintf(guard_name, sizeof(guard_name), "inl%d_pf_epoch_%d", id, inl_bc_off);
snprintf(rn_ic, sizeof(rn_ic), "inl%d_pf_ic_%d", id, inl_bc_off);
snprintf(rn_ic_shape, sizeof(rn_ic_shape), "inl%d_pf_shape_%d", id, inl_bc_off);
if (slot_ic) {
mir_emit_ic_epoch_guard(ctx, jit_func, slot_ic, r_global_epoch,
slow, guard_name);
MIR_reg_t r_ic = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_ic);
MIR_reg_t r_ic_shape = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_ic_shape);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)slot_ic)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_shape),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_shape), r_ic, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_guarded_this_shape),
MIR_new_reg_op(ctx, r_ic_shape)));
}
mir_emit_this_slot_store_num(ctx, jit_func, val, r_guarded_this_obj,
slot_idx, slow, r_bool, id, inl_bc_off);
break;
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, put_field_proto),
MIR_new_ref_op(ctx, imp_put_field),
MIR_new_reg_op(ctx, result),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj),
MIR_new_reg_op(ctx, val),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)atom->len)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, result),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
break;
}
case OP_GET_GLOBAL: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)callee->atom_count) return false;
sv_atom_t *atom = &callee->atoms[idx];
int dst_i = isp;
MIR_reg_t dst = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 7,
MIR_new_ref_op(ctx, gg_proto),
MIR_new_ref_op(ctx, imp_gg),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_js),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)callee),
MIR_new_int_op(ctx, (int64_t)inl_bc_off)));
break;
}
case OP_RETURN: {
MIR_reg_t ret = inl_vs[--isp];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, result),
MIR_new_reg_op(ctx, ret)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, join)));
break;
}
case OP_RETURN_UNDEF:
mir_load_imm(ctx, jit_func, result, mkval(T_UNDEF, 0));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, join)));
break;
case OP_SPECIAL_OBJ: {
uint8_t which = sv_get_u8(ip + 1);
int dst_i = isp;
MIR_reg_t dst = inl_vs[isp++];
INL_RESET_SLOT(dst_i);
if (which == 1) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_inl_new_target)));
} else if (which == 2) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_inl_super)));
} else if (which == 3) {
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 6,
MIR_new_ref_op(ctx, special_obj_proto),
MIR_new_ref_op(ctx, imp_special_obj),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_int_op(ctx, (int64_t)which)));
} else {
mir_load_imm(ctx, jit_func, dst, mkval(T_UNDEF, 0));
}
break;
}
case OP_NOP: case OP_LINE_NUM: case OP_COL_NUM: case OP_LABEL:
break;
default:
return false;
}
ip += sz;
}
#undef INL_MARK_NUM
#undef INL_RESET_SLOT
return true;
}
static void scan_branch_targets(sv_func_t *func, jit_label_map_t *lm,
MIR_context_t ctx) {
uint8_t *ip = func->code;
uint8_t *end = func->code + func->code_len;
while (ip < end) {
sv_op_t op = (sv_op_t)*ip;
int sz = sv_op_size[op];
if (sz == 0) break;
switch (op) {
case OP_JMP:
case OP_JMP_FALSE:
case OP_JMP_TRUE:
case OP_JMP_FALSE_PEEK:
case OP_JMP_TRUE_PEEK:
case OP_JMP_NOT_NULLISH:
case OP_TRY_PUSH:
case OP_CATCH:
case OP_FINALLY: {
int off = (int)(ip - func->code) + sv_get_i32(ip + 1) + sz;
label_for_offset(ctx, lm, off);
break;
}
case OP_JMP8:
case OP_JMP_FALSE8:
case OP_JMP_TRUE8: {
int off = (int)(ip - func->code) + (int8_t)sv_get_i8(ip + 1) + sz;
label_for_offset(ctx, lm, off);
break;
}
default: break;
}
ip += sz;
}
}
typedef struct {
bool needs_bailout;
bool needs_inc_local;
bool needs_args_buf;
bool needs_iter_roots;
bool needs_close_upval;
bool needs_tco_args;
bool needs_ic_epoch;
} jit_features_t;
static jit_features_t jit_prescan_features(sv_func_t *func) {
jit_features_t f = {0};
uint8_t *ip = func->code;
uint8_t *end = func->code + func->code_len;
while (ip < end) {
sv_op_t op = (sv_op_t)*ip;
int sz = sv_op_size[op];
if (sz == 0) break;
switch (op) {
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD:
case OP_ADD_NUM: case OP_SUB_NUM: case OP_MUL_NUM: case OP_DIV_NUM:
case OP_NEG:
case OP_LT: case OP_LE: case OP_GT: case OP_GE:
case OP_BAND: case OP_BOR: case OP_BXOR: case OP_BNOT:
case OP_SHL: case OP_SHR: case OP_USHR:
case OP_TYPEOF:
case OP_ADD_LOCAL:
case OP_STR_APPEND_LOCAL:
case OP_STR_ALC_SNAPSHOT:
case OP_STR_FLUSH_LOCAL:
f.needs_bailout = true;
break;
case OP_INC_LOCAL: case OP_DEC_LOCAL:
case OP_POST_INC:
f.needs_inc_local = true;
break;
case OP_CALL: case OP_CALL_METHOD: case OP_CALL_ARRAY_INCLUDES:
case OP_TAIL_CALL: case OP_TAIL_CALL_METHOD:
case OP_ARRAY: case OP_NEW:
case OP_APPLY: case OP_NEW_APPLY:
f.needs_args_buf = true;
if (op == OP_TAIL_CALL || op == OP_TAIL_CALL_METHOD)
f.needs_tco_args = true;
break;
case OP_FOR_OF:
case OP_DESTRUCTURE_INIT: case OP_DESTRUCTURE_NEXT: case OP_DESTRUCTURE_CLOSE:
f.needs_args_buf = true;
f.needs_iter_roots = true;
break;
case OP_CLOSE_UPVAL: case OP_CLOSURE:
f.needs_close_upval = true;
break;
case OP_SET_ARG:
f.needs_bailout = true;
break;
case OP_GET_FIELD: case OP_GET_FIELD2: case OP_PUT_FIELD:
case OP_INSTANCEOF: case OP_CALL_IS_PROTO:
f.needs_ic_epoch = true;
break;
default: break;
}
ip += sz;
}
if (f.needs_bailout) f.needs_args_buf = true;
return f;
}
static bool jit_is_eligible(sv_func_t *func) {
if (func->is_async || func->is_generator) return false;
bool eligible = true;
uint8_t *ip = func->code;
uint8_t *end = func->code + func->code_len;
while (ip < end) {
sv_op_t op = (sv_op_t)*ip;
int sz = sv_op_size[op];
if (sz == 0) return false;
switch (op) {
case OP_CONST_I8: case OP_CONST: case OP_CONST8:
case OP_UNDEF: case OP_NULL: case OP_TRUE: case OP_FALSE:
case OP_THIS:
case OP_GET_ARG: case OP_SET_ARG:
case OP_GET_LOCAL: case OP_PUT_LOCAL: case OP_SET_LOCAL:
case OP_GET_LOCAL8: case OP_PUT_LOCAL8: case OP_SET_LOCAL8:
case OP_SET_LOCAL_UNDEF:
case OP_GET_SLOT_RAW:
case OP_GET_UPVAL: case OP_PUT_UPVAL: case OP_SET_UPVAL:
case OP_CLOSE_UPVAL:
case OP_REST:
case OP_POP: case OP_DUP: case OP_DUP2:
case OP_INSERT2: case OP_INSERT3:
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD:
case OP_ADD_NUM: case OP_SUB_NUM: case OP_MUL_NUM: case OP_DIV_NUM:
case OP_POST_INC:
case OP_NEG: case OP_IS_UNDEF: case OP_IS_NULL:
case OP_LT: case OP_LE: case OP_GT: case OP_GE:
case OP_NE: case OP_SNE:
case OP_BAND: case OP_BOR: case OP_BXOR: case OP_BNOT:
case OP_SHL: case OP_SHR: case OP_USHR:
case OP_NOT: case OP_TYPEOF: case OP_VOID:
case OP_DELETE:
case OP_INSTANCEOF:
case OP_NEW:
case OP_JMP: case OP_JMP8:
case OP_JMP_FALSE: case OP_JMP_FALSE8:
case OP_JMP_TRUE: case OP_JMP_TRUE8:
case OP_JMP_FALSE_PEEK: case OP_JMP_TRUE_PEEK:
case OP_CALL: case OP_CALL_METHOD:
case OP_CALL_IS_PROTO: case OP_CALL_ARRAY_INCLUDES:
case OP_TAIL_CALL: case OP_TAIL_CALL_METHOD:
case OP_APPLY: case OP_NEW_APPLY:
case OP_GET_GLOBAL: case OP_GET_GLOBAL_UNDEF:
case OP_PUT_GLOBAL:
case OP_GET_FIELD: case OP_GET_FIELD2: case OP_PUT_FIELD:
case OP_GET_ELEM: case OP_GET_ELEM2: case OP_PUT_ELEM:
case OP_OBJECT: case OP_ARRAY: case OP_SET_PROTO:
case OP_SWAP: case OP_ROT3L:
case OP_IN: case OP_GET_LENGTH:
case OP_DEFINE_FIELD: case OP_DEFINE_METHOD_COMP: case OP_SEQ: case OP_EQ:
case OP_FOR_OF:
case OP_DESTRUCTURE_INIT: case OP_DESTRUCTURE_NEXT: case OP_DESTRUCTURE_CLOSE:
case OP_INC_LOCAL: case OP_DEC_LOCAL: case OP_ADD_LOCAL:
case OP_STR_APPEND_LOCAL:
case OP_STR_ALC_SNAPSHOT:
case OP_TO_PROPKEY:
case OP_RETURN: case OP_RETURN_UNDEF:
case OP_SET_NAME:
case OP_TRY_PUSH: case OP_TRY_POP:
case OP_THROW: case OP_THROW_ERROR:
case OP_CATCH: case OP_NIP_CATCH:
case OP_NOP: case OP_HALT:
case OP_LINE_NUM: case OP_COL_NUM: case OP_LABEL:
break;
case OP_CLOSURE: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)func->const_count) return false;
ant_value_t cv = func->constants[idx];
if (vtype(cv) != T_NTARG) return false;
break;
}
case OP_RE_EXEC_TRUTHY:
eligible = false;
break;
case OP_SPECIAL_OBJ:
if (sv_get_u8(ip + 1) == 0) {
if (sv_jit_warn_unlikely)
fprintf(stderr, "jit: ineligible op SPECIAL_OBJ(%d) in %s\n",
sv_get_u8(ip + 1),
func->name ? func->name : "<anonymous>");
eligible = false;
}
break;
default:
if (sv_jit_warn_unlikely)
fprintf(stderr, "jit: ineligible op %s in %s\n",
(op < OP__COUNT && sv_op_name[op]) ? sv_op_name[op] : "???",
func->name ? func->name : "<anonymous>");
eligible = false;
break;
}
ip += sz;
}
return eligible;
}
sv_jit_func_t sv_jit_compile(ant_t *js, sv_func_t *func, sv_closure_t *hint_closure) {
if (func->jit_compile_failed || func->jit_compiling) return NULL;
if (func->jit_code == NULL && func->jit_compiled_tfb_ver != 0 &&
func->tfb_version == func->jit_compiled_tfb_ver) {
func->jit_compile_failed = true;
return NULL;
}
if (!jit_is_eligible(func)) { func->jit_compile_failed = true; return NULL; }
func->jit_compiling = true;
sv_jit_ctx_t *jc = jit_ctx_get(js);
if (!jc) { sv_jit_init(js); jc = jit_ctx_get(js); }
if (!jc) { func->jit_compiling = false; return NULL; }
jit_load_externals_once(jc);
MIR_context_t ctx = jc->ctx;
char fname[128];
snprintf(fname, sizeof(fname), "jit_%s_%p",
func->name ? func->name : "anon", (void *)func);
MIR_module_t mod = MIR_new_module(ctx, fname);
MIR_type_t ret_type = MIR_JSVAL;
MIR_item_t self_proto = MIR_new_proto(ctx, "jit_proto",
1, &ret_type,
7,
MIR_T_I64, "vm",
MIR_JSVAL, "this_val",
MIR_JSVAL, "new_target",
MIR_JSVAL, "super_val",
MIR_T_P, "args",
MIR_T_I32, "argc",
MIR_T_P, "closure");
MIR_type_t h2_ret = MIR_JSVAL;
MIR_item_t helper2_proto = MIR_new_proto(ctx, "helper2_proto",
1, &h2_ret,
4,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "l",
MIR_JSVAL, "r");
MIR_type_t call_ret = MIR_JSVAL;
MIR_item_t call_proto = MIR_new_proto(ctx, "call_proto",
1, &call_ret,
6,
MIR_T_I64, "vm",
MIR_T_I64, "js_p",
MIR_JSVAL, "func",
MIR_JSVAL, "this_val",
MIR_T_P, "args",
MIR_T_I32, "argc");
MIR_type_t call_method_ret = MIR_JSVAL;
MIR_item_t call_method_proto = MIR_new_proto(ctx, "callm_proto",
1, &call_method_ret,
9,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "func",
MIR_JSVAL, "this_val",
MIR_T_P, "args",
MIR_T_I32, "argc",
MIR_JSVAL, "super_val",
MIR_JSVAL, "new_target",
MIR_T_P, "out_this");
MIR_type_t gg_ret = MIR_JSVAL;
MIR_item_t gg_proto = MIR_new_proto(ctx, "gg_proto",
1, &gg_ret, 4,
MIR_T_I64, "js",
MIR_T_P, "str",
MIR_T_P, "func",
MIR_T_I32, "bc_off");
MIR_type_t rest_ret = MIR_JSVAL;
MIR_item_t rest_proto = MIR_new_proto(ctx, "rest_proto",
1, &rest_ret, 5,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_T_P, "args",
MIR_T_I32, "argc",
MIR_T_I32, "start");
MIR_type_t gf_ret = MIR_JSVAL;
MIR_item_t gf_proto = MIR_new_proto(ctx, "gf_proto",
1, &gf_ret, 7,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "obj",
MIR_T_P, "str",
MIR_T_I32, "len",
MIR_T_P, "func",
MIR_T_I32, "bc_off");
MIR_type_t ge_ret = MIR_JSVAL;
MIR_item_t ge_proto = MIR_new_proto(ctx, "ge_proto",
1, &ge_ret, 6,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "obj",
MIR_JSVAL, "key",
MIR_T_P, "func",
MIR_T_I32, "bc_off");
MIR_type_t inst_ret = MIR_JSVAL;
MIR_item_t inst_proto = MIR_new_proto(ctx, "inst_proto",
1, &inst_ret, 6,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "l",
MIR_JSVAL, "r",
MIR_T_P, "func",
MIR_T_I32, "bc_off");
MIR_type_t cip_ret = MIR_JSVAL;
MIR_item_t call_is_proto = MIR_new_proto(ctx, "cip_proto",
1, &cip_ret, 7,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "this_val",
MIR_JSVAL, "func_val",
MIR_JSVAL, "arg",
MIR_T_P, "func",
MIR_T_I32, "bc_off");
MIR_type_t h1_ret = MIR_JSVAL;
MIR_item_t helper1_proto = MIR_new_proto(ctx, "helper1_proto",
1, &h1_ret, 3,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "v");
MIR_type_t sal_ret = MIR_JSVAL;
MIR_item_t str_append_local_proto = MIR_new_proto(ctx, "sal_proto",
1, &sal_ret, 8,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_T_P, "func",
MIR_T_P, "args",
MIR_T_I32, "argc",
MIR_T_P, "locals",
MIR_T_I32, "slot_idx",
MIR_JSVAL, "rhs");
MIR_type_t sals_ret = MIR_JSVAL;
MIR_item_t str_append_local_snapshot_proto = MIR_new_proto(ctx, "sals_proto",
1, &sals_ret, 9,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_T_P, "func",
MIR_T_P, "args",
MIR_T_I32, "argc",
MIR_T_P, "locals",
MIR_T_I32, "slot_idx",
MIR_JSVAL, "lhs",
MIR_JSVAL, "rhs");
MIR_type_t sfl_ret = MIR_JSVAL;
MIR_item_t str_flush_local_proto = MIR_new_proto(ctx, "sfl_proto",
1, &sfl_ret, 7,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_T_P, "func",
MIR_T_P, "args",
MIR_T_I32, "argc",
MIR_T_P, "locals",
MIR_T_I32, "slot_idx");
MIR_type_t truthy_ret = MIR_T_I64;
MIR_item_t truthy_proto = MIR_new_proto(ctx, "truthy_proto",
1, &truthy_ret, 2,
MIR_T_I64, "js",
MIR_JSVAL, "v");
MIR_type_t br_ret = MIR_JSVAL;
MIR_item_t resume_proto = MIR_new_proto(ctx, "resume_proto",
1, &br_ret, 10,
MIR_T_I64, "vm",
MIR_T_P, "closure",
MIR_JSVAL, "this_val",
MIR_T_P, "args",
MIR_T_I32, "argc",
MIR_T_P, "vstack",
MIR_T_I64, "vstack_sp",
MIR_T_P, "locals",
MIR_T_I64, "n_locals",
MIR_T_I64, "bc_offset");
MIR_type_t cl_ret = MIR_JSVAL;
MIR_item_t closure_proto = MIR_new_proto(ctx, "closure_proto",
1, &cl_ret, 8,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_T_P, "parent",
MIR_JSVAL, "this_val",
MIR_T_P, "slots",
MIR_T_I32, "slot_base",
MIR_T_I32, "slot_count",
MIR_T_I32, "const_idx");
MIR_item_t close_upval_proto = MIR_new_proto(ctx, "close_upval_proto",
0, NULL, 4,
MIR_T_I64, "vm",
MIR_T_I32, "slot_idx",
MIR_T_P, "slots",
MIR_T_I32, "slot_count");
MIR_item_t set_name_proto = MIR_new_proto(ctx, "sn_proto",
0, NULL, 5,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "fn",
MIR_T_P, "str",
MIR_T_I32, "len");
MIR_type_t so_ret = MIR_T_I64;
MIR_item_t stack_ovf_proto = MIR_new_proto(ctx, "so_proto",
1, &so_ret, 1,
MIR_T_I64, "js");
MIR_type_t soe_ret = MIR_JSVAL;
MIR_item_t stack_ovf_err_proto = MIR_new_proto(ctx, "soe_proto",
1, &soe_ret, 2,
MIR_T_I64, "vm",
MIR_T_I64, "js");
MIR_item_t define_field_proto = MIR_new_proto(ctx, "df_proto",
0, NULL, 6,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "obj",
MIR_JSVAL, "val",
MIR_T_P, "str",
MIR_T_I32, "len");
MIR_item_t define_method_comp_proto = MIR_new_proto(ctx, "dmc_proto",
0, NULL, 5,
MIR_T_I64, "js",
MIR_JSVAL, "obj",
MIR_JSVAL, "key",
MIR_JSVAL, "fn",
MIR_T_I32, "flags");
MIR_type_t pf_ret = MIR_JSVAL;
MIR_item_t put_field_proto = MIR_new_proto(ctx, "pf_proto",
1, &pf_ret, 6,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "obj",
MIR_JSVAL, "val",
MIR_T_P, "str",
MIR_T_I32, "len");
MIR_type_t pe_ret = MIR_JSVAL;
MIR_item_t put_elem_proto = MIR_new_proto(ctx, "pe_proto",
1, &pe_ret, 5,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "obj",
MIR_JSVAL, "key",
MIR_JSVAL, "val");
MIR_type_t pg_ret = MIR_JSVAL;
MIR_item_t put_global_proto = MIR_new_proto(ctx, "pg_proto",
1, &pg_ret, 6,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "val",
MIR_T_P, "str",
MIR_T_I32, "len",
MIR_T_I32, "strict");
MIR_type_t obj_ret = MIR_JSVAL;
MIR_item_t object_proto = MIR_new_proto(ctx, "obj_proto",
1, &obj_ret, 2,
MIR_T_I64, "vm",
MIR_T_I64, "js");
MIR_type_t arr_ret = MIR_JSVAL;
MIR_item_t array_proto = MIR_new_proto(ctx, "arr_proto",
1, &arr_ret, 4,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_T_P, "elements",
MIR_T_I32, "count");
MIR_type_t te_ret = MIR_JSVAL;
MIR_item_t throw_error_proto = MIR_new_proto(ctx, "te_proto",
1, &te_ret, 5,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_T_P, "str",
MIR_T_I32, "len",
MIR_T_I32, "err_type");
MIR_type_t nw_ret = MIR_JSVAL;
MIR_item_t new_proto = MIR_new_proto(ctx, "new_proto",
1, &nw_ret, 6,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "func",
MIR_JSVAL, "new_target",
MIR_T_P, "args",
MIR_T_I32, "argc");
MIR_type_t special_obj_ret = MIR_JSVAL;
MIR_item_t special_obj_proto = MIR_new_proto(ctx, "soj_proto",
1, &special_obj_ret, 3,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_T_I32, "which");
MIR_type_t for_of_ret = MIR_JSVAL;
MIR_item_t for_of_proto = MIR_new_proto(ctx, "fo_proto",
1, &for_of_ret, 4,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_JSVAL, "iterable",
MIR_T_P, "iter_buf");
MIR_item_t destructure_close_proto = MIR_new_proto(ctx, "dclose_proto",
0, NULL, 3,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_T_P, "iter_buf");
MIR_type_t destructure_next_ret = MIR_JSVAL;
MIR_item_t destructure_next_proto = MIR_new_proto(ctx, "dnext_proto",
1, &destructure_next_ret, 3,
MIR_T_I64, "vm",
MIR_T_I64, "js",
MIR_T_P, "iter_buf");
MIR_item_t imp_add = MIR_new_import(ctx, "jit_helper_add");
MIR_item_t imp_sub = MIR_new_import(ctx, "jit_helper_sub");
MIR_item_t imp_mul = MIR_new_import(ctx, "jit_helper_mul");
MIR_item_t imp_div = MIR_new_import(ctx, "jit_helper_div");
MIR_item_t imp_mod = MIR_new_import(ctx, "jit_helper_mod");
MIR_item_t imp_str_append_local =
MIR_new_import(ctx, "jit_helper_str_append_local");
MIR_item_t imp_str_append_local_snapshot =
MIR_new_import(ctx, "jit_helper_str_append_local_snapshot");
MIR_item_t imp_str_flush_local =
MIR_new_import(ctx, "jit_helper_str_flush_local");
MIR_item_t imp_lt = MIR_new_import(ctx, "jit_helper_lt");
MIR_item_t imp_le = MIR_new_import(ctx, "jit_helper_le");
MIR_item_t imp_gt = MIR_new_import(ctx, "jit_helper_gt");
MIR_item_t imp_ge = MIR_new_import(ctx, "jit_helper_ge");
MIR_item_t imp_call = MIR_new_import(ctx, "jit_helper_call");
MIR_item_t imp_call_method = MIR_new_import(ctx, "jit_helper_call_method");
MIR_item_t imp_call_array_includes = MIR_new_import(ctx, "jit_helper_call_array_includes");
MIR_item_t imp_apply = MIR_new_import(ctx, "jit_helper_apply");
MIR_item_t imp_rest = MIR_new_import(ctx, "jit_helper_rest");
MIR_item_t imp_special_obj = MIR_new_import(ctx, "jit_helper_special_obj");
MIR_item_t imp_for_of = MIR_new_import(ctx, "jit_helper_for_of");
MIR_item_t imp_dnext = MIR_new_import(ctx, "jit_helper_destructure_next");
MIR_item_t imp_dclose = MIR_new_import(ctx, "jit_helper_destructure_close");
MIR_item_t imp_gg = MIR_new_import(ctx, "jit_helper_get_global");
MIR_item_t imp_get_field = MIR_new_import(ctx, "jit_helper_get_field");
MIR_item_t imp_to_propkey = MIR_new_import(ctx, "jit_helper_to_propkey");
MIR_item_t imp_resume = MIR_new_import(ctx, "jit_helper_bailout_resume");
MIR_item_t imp_close_upval = MIR_new_import(ctx, "jit_helper_close_upval");
MIR_item_t imp_closure = MIR_new_import(ctx, "jit_helper_closure");
MIR_item_t imp_in = MIR_new_import(ctx, "jit_helper_in");
MIR_item_t imp_get_length = MIR_new_import(ctx, "jit_helper_get_length");
MIR_item_t imp_define_field = MIR_new_import(ctx, "jit_helper_define_field");
MIR_item_t imp_define_method_comp = MIR_new_import(ctx, "jit_helper_define_method_comp");
MIR_item_t imp_seq = MIR_new_import(ctx, "jit_helper_seq");
MIR_item_t imp_eq = MIR_new_import(ctx, "jit_helper_eq");
MIR_item_t imp_ne = MIR_new_import(ctx, "jit_helper_ne");
MIR_item_t imp_sne = MIR_new_import(ctx, "jit_helper_sne");
MIR_item_t imp_put_field = MIR_new_import(ctx, "jit_helper_put_field");
MIR_item_t imp_get_elem = MIR_new_import(ctx, "jit_helper_get_elem");
MIR_item_t imp_put_elem = MIR_new_import(ctx, "jit_helper_put_elem");
MIR_item_t imp_put_global = MIR_new_import(ctx, "jit_helper_put_global");
MIR_item_t imp_object = MIR_new_import(ctx, "jit_helper_object");
MIR_item_t imp_array = MIR_new_import(ctx, "jit_helper_array");
MIR_item_t imp_catch_value = MIR_new_import(ctx, "jit_helper_catch_value");
MIR_item_t imp_throw = MIR_new_import(ctx, "jit_helper_throw");
MIR_item_t imp_throw_error = MIR_new_import(ctx, "jit_helper_throw_error");
MIR_item_t imp_set_proto = MIR_new_import(ctx, "jit_helper_set_proto");
MIR_item_t imp_get_elem2 = MIR_new_import(ctx, "jit_helper_get_elem2");
MIR_item_t imp_band = MIR_new_import(ctx, "jit_helper_band");
MIR_item_t imp_bor = MIR_new_import(ctx, "jit_helper_bor");
MIR_item_t imp_bxor = MIR_new_import(ctx, "jit_helper_bxor");
MIR_item_t imp_bnot = MIR_new_import(ctx, "jit_helper_bnot");
MIR_item_t imp_shl = MIR_new_import(ctx, "jit_helper_shl");
MIR_item_t imp_shr = MIR_new_import(ctx, "jit_helper_shr");
MIR_item_t imp_ushr = MIR_new_import(ctx, "jit_helper_ushr");
MIR_item_t imp_not = MIR_new_import(ctx, "jit_helper_not");
MIR_item_t imp_is_truthy = MIR_new_import(ctx, "jit_helper_is_truthy");
MIR_item_t imp_typeof = MIR_new_import(ctx, "jit_helper_typeof");
MIR_item_t imp_new = MIR_new_import(ctx, "jit_helper_new");
MIR_item_t imp_instanceof = MIR_new_import(ctx, "jit_helper_instanceof");
MIR_item_t imp_call_is_proto = MIR_new_import(ctx, "jit_helper_call_is_proto");
MIR_item_t imp_delete = MIR_new_import(ctx, "jit_helper_delete");
MIR_item_t imp_set_name = MIR_new_import(ctx, "jit_helper_set_name");
MIR_item_t imp_stack_ovf = MIR_new_import(ctx, "jit_helper_stack_overflow");
MIR_item_t imp_stack_ovf_err = MIR_new_import(ctx, "jit_helper_stack_overflow_error");
MIR_item_t jit_func = MIR_new_func(ctx, fname,
1, &ret_type,
7,
MIR_T_I64, "vm",
MIR_JSVAL, "this_val",
MIR_JSVAL, "new_target",
MIR_JSVAL, "super_val",
MIR_T_P, "args",
MIR_T_I32, "argc",
MIR_T_P, "closure");
MIR_reg_t r_vm = MIR_reg(ctx, "vm", jit_func->u.func);
MIR_reg_t r_this = MIR_reg(ctx, "this_val", jit_func->u.func);
MIR_reg_t r_new_target = MIR_reg(ctx, "new_target", jit_func->u.func);
MIR_reg_t r_super_val = MIR_reg(ctx, "super_val", jit_func->u.func);
MIR_reg_t r_args = MIR_reg(ctx, "args", jit_func->u.func);
MIR_reg_t r_argc = MIR_reg(ctx, "argc", jit_func->u.func);
MIR_reg_t r_closure = MIR_reg(ctx, "closure", jit_func->u.func);
MIR_reg_t r_this_curr = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, "this_curr");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_this_curr),
MIR_new_reg_op(ctx, r_this)));
MIR_reg_t r_js = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "js_ptr");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_js),
MIR_new_mem_op(ctx, MIR_T_I64, 0, r_vm, 0, 1)));
{
MIR_reg_t r_ovf = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "stk_ovf");
MIR_label_t no_overflow = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 4,
MIR_new_ref_op(ctx, stack_ovf_proto),
MIR_new_ref_op(ctx, imp_stack_ovf),
MIR_new_reg_op(ctx, r_ovf),
MIR_new_reg_op(ctx, r_js)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, no_overflow),
MIR_new_reg_op(ctx, r_ovf),
MIR_new_int_op(ctx, 0)));
MIR_reg_t r_ovf_err = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, "stk_err");
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 5,
MIR_new_ref_op(ctx, stack_ovf_err_proto),
MIR_new_ref_op(ctx, imp_stack_ovf_err),
MIR_new_reg_op(ctx, r_ovf_err),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js)));
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_ovf_err)));
MIR_append_insn(ctx, jit_func, no_overflow);
}
jit_vstack_t vs = {0};
vs.max = func->max_stack > 0 ? func->max_stack : 32;
vs.regs = calloc((size_t)vs.max, sizeof(MIR_reg_t));
vs.known_func = calloc((size_t)vs.max, sizeof(sv_func_t *));
vs.method_ic = calloc((size_t)vs.max, sizeof(jit_method_ic_info_t));
vs.d_regs = calloc((size_t)vs.max, sizeof(MIR_reg_t));
vs.slot_type = calloc((size_t)vs.max, sizeof(uint8_t));
vs.known_const = calloc((size_t)vs.max, sizeof(uint64_t));
vs.has_const = calloc((size_t)vs.max, sizeof(bool));
if (!vs.regs || !vs.known_func || !vs.method_ic || !vs.d_regs || !vs.slot_type || !vs.known_const || !vs.has_const) {
free(vs.regs); free(vs.known_func); free(vs.method_ic); free(vs.d_regs); free(vs.slot_type);
free(vs.known_const); free(vs.has_const);
MIR_finish_func(ctx); MIR_finish_module(ctx); func->jit_compiling = false; return NULL;
}
for (int i = 0; i < vs.max; i++) {
char rname[32];
snprintf(rname, sizeof(rname), "s%d", i);
vs.regs[i] = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rname);
}
for (int i = 0; i < vs.max; i++) {
char dname[32];
snprintf(dname, sizeof(dname), "sd%d", i);
vs.d_regs[i] = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, dname);
}
int n_locals = func->max_locals;
MIR_reg_t *local_regs = NULL;
MIR_reg_t *local_d_regs = NULL;
sv_func_t **known_func_locals = NULL;
uint8_t *known_type_locals = NULL;
if (n_locals > 0) {
local_regs = calloc((size_t)n_locals, sizeof(MIR_reg_t));
local_d_regs = calloc((size_t)n_locals, sizeof(MIR_reg_t));
known_func_locals = calloc((size_t)n_locals, sizeof(sv_func_t *));
known_type_locals = calloc((size_t)n_locals, sizeof(uint8_t));
if (!local_regs || !local_d_regs || !known_func_locals || !known_type_locals) {
free(vs.regs); free(vs.known_func); free(vs.method_ic); free(vs.d_regs); free(vs.slot_type);
free(vs.known_const); free(vs.has_const);
free(local_regs); free(local_d_regs); free(known_func_locals); free(known_type_locals);
MIR_finish_func(ctx); MIR_finish_module(ctx); return NULL;
}
if (func->local_types && func->local_type_count > 0) {
int ncopy = func->local_type_count < n_locals ? func->local_type_count : n_locals;
for (int i = 0; i < ncopy; i++)
known_type_locals[i] = func->local_types[i].type;
}
if (func->local_type_feedback) {
for (int i = 0; i < n_locals; i++) {
uint8_t ltf = func->local_type_feedback[i];
if (ltf && !(ltf & ~SV_TFB_NUM))
known_type_locals[i] = SV_TI_NUM;
}
}
for (int i = 0; i < n_locals; i++) {
char rname[32], dname[32];
snprintf(rname, sizeof(rname), "l%d", i);
snprintf(dname, sizeof(dname), "ld%d", i);
local_regs[i] = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rname);
local_d_regs[i] = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, dname);
mir_load_imm(ctx, jit_func, local_regs[i],
mkval(T_UNDEF, 0));
}
}
MIR_reg_t r_tmp = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, "tmp");
MIR_reg_t r_tmp2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, "tmp2");
MIR_reg_t r_bool = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "bool_tmp");
MIR_reg_t r_err_tmp = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, "err_tmp");
mir_load_imm(ctx, jit_func, r_tmp2, 0);
jit_features_t feat = jit_prescan_features(func);
MIR_reg_t r_d_slot = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "d_slot");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, r_d_slot),
MIR_new_uint_op(ctx, 8)));
MIR_reg_t r_d_one = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, "d_one");
if (feat.needs_inc_local) {
union { double d; uint64_t u; } one = {1.0};
mir_load_imm(ctx, jit_func, r_bool, one.u);
mir_i64_to_d(ctx, jit_func, r_d_one, r_bool, r_d_slot);
}
MIR_reg_t r_args_buf = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "args_buf");
if (feat.needs_args_buf) {
int scratch_slots = 16;
if (vs.max > scratch_slots) scratch_slots = vs.max;
if (n_locals > scratch_slots) scratch_slots = n_locals;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, r_args_buf),
MIR_new_uint_op(ctx, (uint64_t)scratch_slots * sizeof(ant_value_t))));
} else {
mir_load_imm(ctx, jit_func, r_args_buf, 0);
}
MIR_reg_t r_call_out_this = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "call_out_this");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, r_call_out_this),
MIR_new_uint_op(ctx, sizeof(ant_value_t))));
MIR_reg_t r_iter_roots = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "iter_roots");
if (feat.needs_iter_roots && vs.max > 0) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, r_iter_roots),
MIR_new_uint_op(ctx, (uint64_t)vs.max * sizeof(ant_value_t))));
for (int i = 0; i < vs.max; i++) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_iter_roots, 0, 1),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0))));
}
} else {
mir_load_imm(ctx, jit_func, r_iter_roots, 0);
}
MIR_reg_t r_tco_args = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "tco_args");
MIR_reg_t r_cond_d = 0, r_cond_nan = 0, r_cond_zd = 0, r_cond_zero = 0;
bool needs_bailout = feat.needs_bailout;
MIR_reg_t r_ic_epoch_val = 0;
if (feat.needs_ic_epoch) {
r_ic_epoch_val = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "ic_ep_ptr");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_epoch_val),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)&ant_ic_epoch_counter)));
}
MIR_reg_t r_bailout_val = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, "bail_val");
MIR_reg_t r_bailout_off = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "bail_off");
MIR_reg_t r_bailout_sp = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "bail_sp");
MIR_label_t bailout_tramp = needs_bailout ? MIR_new_label(ctx) : NULL;
int param_count = func->param_count;
bool *captured_params = scan_captured_params(func);
bool *captured_locals = scan_captured_locals(func, n_locals);
bool has_captured_params = false;
bool has_captures = false;
if (captured_params) {
for (int i = 0; i < param_count; i++)
if (captured_params[i]) { has_captured_params = true; break; }
}
if (captured_locals) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i]) { has_captures = true; break; }
}
bool has_captured_slots = has_captured_params || has_captures;
bool use_unified_slotbuf = has_captured_slots && has_captures;
int slotbuf_count = use_unified_slotbuf ? (param_count + n_locals) : param_count;
if (has_captured_params && needs_bailout) {
free(vs.regs); free(vs.known_func); free(vs.method_ic); free(vs.d_regs); free(vs.slot_type);
free(vs.known_const); free(vs.has_const);
free(local_regs); free(local_d_regs); free(known_func_locals); free(known_type_locals);
free(captured_params); free(captured_locals);
MIR_finish_func(ctx); MIR_finish_module(ctx); func->jit_compiling = false; return NULL;
}
MIR_reg_t r_slotbuf = r_tmp2;
if (has_captured_slots && slotbuf_count > 0) {
r_slotbuf = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "slotbuf");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, r_slotbuf),
MIR_new_uint_op(ctx, (uint64_t)slotbuf_count * sizeof(ant_value_t))));
mir_emit_fill_param_slots_from_args(ctx, jit_func, r_slotbuf, r_args, r_argc, captured_params, param_count);
}
bool needs_lbuf = needs_bailout || feat.needs_close_upval || has_captures;
MIR_reg_t r_lbuf = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "lbuf");
if (use_unified_slotbuf && n_locals > 0) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ADD,
MIR_new_reg_op(ctx, r_lbuf),
MIR_new_reg_op(ctx, r_slotbuf),
MIR_new_int_op(ctx, (int64_t)param_count * (int64_t)sizeof(ant_value_t))));
} else if (needs_lbuf && n_locals > 0) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, r_lbuf),
MIR_new_uint_op(ctx, (uint64_t)n_locals * sizeof(ant_value_t))));
} else {
mir_load_imm(ctx, jit_func, r_lbuf, 0);
}
if (feat.needs_tco_args && param_count > 0) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, r_tco_args),
MIR_new_uint_op(ctx, (uint64_t)param_count * sizeof(ant_value_t))));
} else mir_load_imm(ctx, jit_func, r_tco_args, 0);
jit_label_map_t lm = {0};
scan_branch_targets(func, &lm, ctx);
osr_entry_map_t osr_map = {0};
scan_osr_entries(func, &osr_map);
if (osr_map.count > 0) {
MIR_label_t normal_entry = MIR_new_label(ctx);
MIR_disp_t osr_base = (MIR_disp_t)offsetof(struct sv_vm, jit_osr);
MIR_reg_t r_osr_active = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, "osr_active");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_osr_active),
MIR_new_mem_op(ctx, MIR_T_U8,
osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, active),
r_vm, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, normal_entry),
MIR_new_reg_op(ctx, r_osr_active),
MIR_new_int_op(ctx, 0)));
MIR_reg_t r_osr_locals = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, "osr_locals");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_osr_locals),
MIR_new_mem_op(ctx, MIR_T_P,
osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, locals),
r_vm, 0, 1)));
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)),
r_osr_locals, 0, 1)));
if (has_captures) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_lbuf),
MIR_new_mem_op(ctx, MIR_T_P,
osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, lp),
r_vm, 0, 1)));
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_U8,
osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, active),
r_vm, 0, 1),
MIR_new_int_op(ctx, 0)));
MIR_reg_t r_osr_off = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, "osr_off");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_osr_off),
MIR_new_mem_op(ctx, MIR_T_I32,
osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, bc_offset),
r_vm, 0, 1)));
for (int i = 0; i < osr_map.count; i++) {
MIR_label_t target_lbl = label_for_offset(ctx, &lm, osr_map.offsets[i]);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, target_lbl),
MIR_new_reg_op(ctx, r_osr_off),
MIR_new_int_op(ctx, osr_map.offsets[i])));
}
MIR_append_insn(ctx, jit_func, normal_entry);
}
#define JIT_TRY_MAX 16
typedef struct {
MIR_label_t catch_label;
int catch_bc_off;
int saved_sp;
} jit_try_entry_t;
jit_try_entry_t jit_try_stack[JIT_TRY_MAX];
int jit_try_depth = 0;
typedef struct { int bc_off; int saved_sp; } jit_catch_sp_t;
jit_catch_sp_t catch_sp_map[JIT_TRY_MAX];
int catch_sp_count = 0;
MIR_label_t self_tail_entry = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func, self_tail_entry);
MIR_reg_t r_result = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, "result");
mir_load_imm(ctx, jit_func, r_result, mkval(T_UNDEF, 0));
uint8_t *ip = func->code;
uint8_t *end = func->code + func->code_len;
bool ok = true;
int call_n = 0;
int upval_n = 0;
int arith_n = 0;
int inline_depth = 0;
int inline_budget = JIT_INLINE_BUDGET;
while (ip < end) {
int bc_off = (int)(ip - func->code);
sv_op_t op = (sv_op_t)*ip;
int sz = sv_op_size[op];
if (sz == 0) { ok = false; break; }
for (int i = 0; i < lm.count; i++) {
if (lm.entries[i].bc_off == bc_off) {
MIR_append_insn(ctx, jit_func, lm.entries[i].label);
if (lm.entries[i].sp >= 0)
vs.sp = lm.entries[i].sp;
if (vs.slot_type)
memset(vs.slot_type, SLOT_BOXED, (size_t)vs.max);
if (vs.known_func)
memset(vs.known_func, 0, (size_t)vs.max * sizeof(sv_func_t *));
if (vs.method_ic)
memset(vs.method_ic, 0, (size_t)vs.max * sizeof(jit_method_ic_info_t));
if (vs.has_const)
memset(vs.has_const, 0, (size_t)vs.max * sizeof(bool));
if (known_type_locals && local_d_regs) {
for (int li = 0; li < n_locals; li++)
if (known_type_locals[li] == SV_TI_NUM)
mir_i64_to_d(ctx, jit_func, local_d_regs[li],
local_regs[li], r_d_slot);
}
}
}
switch (op) {
case OP_CONST_I8: {
double d = (double)(int8_t)sv_get_i8(ip + 1);
union { double d; uint64_t u; } u = {d};
MIR_reg_t dst = vstack_push(&vs);
mir_load_imm(ctx, jit_func, dst, u.u);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, vs.d_regs[vs.sp - 1]),
MIR_new_double_op(ctx, d)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
break;
}
case OP_CONST: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)func->const_count) { ok = false; break; }
ant_value_t cv = func->constants[idx];
MIR_reg_t dst = vstack_push(&vs);
if (jit_const_is_heap(cv))
mir_load_const_slot(ctx, jit_func, dst, &func->constants[idx]);
else {
mir_load_imm(ctx, jit_func, dst, cv);
if (vtype(cv) == T_NUM) {
union { uint64_t u; double d; } u = {cv};
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, vs.d_regs[vs.sp - 1]),
MIR_new_double_op(ctx, u.d)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
}
}
break;
}
case OP_CONST8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)func->const_count) { ok = false; break; }
ant_value_t cv = func->constants[idx];
MIR_reg_t dst = vstack_push(&vs);
if (jit_const_is_heap(cv))
mir_load_const_slot(ctx, jit_func, dst, &func->constants[idx]);
else {
mir_load_imm(ctx, jit_func, dst, cv);
if (vtype(cv) == T_NUM) {
union { uint64_t u; double d; } u = {cv};
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, vs.d_regs[vs.sp - 1]),
MIR_new_double_op(ctx, u.d)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
}
}
break;
}
case OP_UNDEF:
mir_load_imm(ctx, jit_func, vstack_push_const(&vs, mkval(T_UNDEF, 0)), mkval(T_UNDEF, 0));
break;
case OP_NULL:
mir_load_imm(ctx, jit_func, vstack_push_const(&vs, mkval(T_NULL, 0)), mkval(T_NULL, 0));
break;
case OP_TRUE:
mir_load_imm(ctx, jit_func, vstack_push_const(&vs, js_true), js_true);
break;
case OP_FALSE:
mir_load_imm(ctx, jit_func, vstack_push_const(&vs, js_false), js_false);
break;
case OP_THIS: {
MIR_reg_t dst = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_this_curr)));
break;
}
case OP_GET_ARG: {
uint16_t idx = sv_get_u16(ip + 1);
MIR_reg_t dst = vstack_push(&vs);
if (has_captured_params && captured_params && idx < (uint16_t)param_count && captured_params[idx]) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(idx * (int)sizeof(ant_value_t)),
r_slotbuf, 0, 1)));
} else {
MIR_label_t arg_in_range = MIR_new_label(ctx);
MIR_label_t arg_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_UBGT,
MIR_new_label_op(ctx, arg_in_range),
MIR_new_reg_op(ctx, r_argc),
MIR_new_int_op(ctx, (int64_t)idx)));
mir_load_imm(ctx, jit_func, dst, mkval(T_UNDEF, 0));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, arg_done)));
MIR_append_insn(ctx, jit_func, arg_in_range);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(idx * (int)sizeof(ant_value_t)),
r_args, 0, 1)));
MIR_append_insn(ctx, jit_func, arg_done);
}
break;
}
case OP_SET_ARG: {
uint16_t idx = sv_get_u16(ip + 1);
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t val = vstack_top(&vs);
if (has_captured_params && captured_params && idx < (uint16_t)param_count && captured_params[idx]) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(idx * (int)sizeof(ant_value_t)),
r_slotbuf, 0, 1),
MIR_new_reg_op(ctx, val)));
if (idx < (uint16_t)param_count) {
MIR_label_t arg_in_range = MIR_new_label(ctx);
MIR_label_t arg_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_UBGT,
MIR_new_label_op(ctx, arg_in_range),
MIR_new_reg_op(ctx, r_argc),
MIR_new_int_op(ctx, (int64_t)idx)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, arg_done)));
MIR_append_insn(ctx, jit_func, arg_in_range);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(idx * (int)sizeof(ant_value_t)),
r_args, 0, 1),
MIR_new_reg_op(ctx, val)));
MIR_append_insn(ctx, jit_func, arg_done);
}
} else {
MIR_label_t arg_in_range = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_UBGT,
MIR_new_label_op(ctx, arg_in_range),
MIR_new_reg_op(ctx, r_argc),
MIR_new_int_op(ctx, (int64_t)idx)));
mir_load_imm(ctx, jit_func, r_bailout_val, (uint64_t)SV_JIT_BAILOUT);
mir_emit_bailout_check(ctx, jit_func, r_bailout_val,
0, r_bailout_off, bc_off,
r_bailout_sp, vs.sp, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, arg_in_range);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(idx * (int)sizeof(ant_value_t)),
r_args, 0, 1),
MIR_new_reg_op(ctx, val)));
}
break;
}
case OP_REST: {
uint16_t start = sv_get_u16(ip + 1);
MIR_reg_t dst = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 8,
MIR_new_ref_op(ctx, rest_proto),
MIR_new_ref_op(ctx, imp_rest),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_args),
MIR_new_reg_op(ctx, r_argc),
MIR_new_int_op(ctx, (int64_t)start)));
break;
}
case OP_GET_LOCAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)n_locals) { ok = false; break; }
if (has_captures && captured_locals && captured_locals[idx])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[idx]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
MIR_reg_t dst = vstack_push(&vs);
if (known_func_locals) vs.known_func[vs.sp - 1] = known_func_locals[idx];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, local_regs[idx])));
if (known_type_locals && known_type_locals[idx] == SV_TI_NUM) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, vs.d_regs[vs.sp - 1]),
MIR_new_reg_op(ctx, local_d_regs[idx])));
if (vs.slot_type) vs.slot_type[vs.sp - 1] = SLOT_NUM;
}
break;
}
case OP_GET_LOCAL8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)n_locals) { ok = false; break; }
if (has_captures && captured_locals && captured_locals[idx])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[idx]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
MIR_reg_t dst = vstack_push(&vs);
if (known_func_locals) vs.known_func[vs.sp - 1] = known_func_locals[idx];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, local_regs[idx])));
if (known_type_locals && known_type_locals[idx] == SV_TI_NUM) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, vs.d_regs[vs.sp - 1]),
MIR_new_reg_op(ctx, local_d_regs[idx])));
if (vs.slot_type) vs.slot_type[vs.sp - 1] = SLOT_NUM;
}
break;
}
case OP_GET_SLOT_RAW: {
uint16_t slot_idx = sv_get_u16(ip + 1);
if ((int)slot_idx < param_count) {
uint16_t idx = slot_idx;
MIR_reg_t dst = vstack_push(&vs);
if (has_captured_params && captured_params && idx < (uint16_t)param_count &&
captured_params[idx]) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(idx * (int)sizeof(ant_value_t)),
r_slotbuf, 0, 1)));
} else {
MIR_label_t arg_in_range = MIR_new_label(ctx);
MIR_label_t arg_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_UBGT,
MIR_new_label_op(ctx, arg_in_range),
MIR_new_reg_op(ctx, r_argc),
MIR_new_int_op(ctx, (int64_t)idx)));
mir_load_imm(ctx, jit_func, dst, mkval(T_UNDEF, 0));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, arg_done)));
MIR_append_insn(ctx, jit_func, arg_in_range);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(idx * (int)sizeof(ant_value_t)),
r_args, 0, 1)));
MIR_append_insn(ctx, jit_func, arg_done);
}
} else {
uint16_t idx = (uint16_t)(slot_idx - (uint16_t)param_count);
if (idx >= (uint16_t)n_locals) { ok = false; break; }
if (has_captures && captured_locals && captured_locals[idx])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[idx]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
MIR_reg_t dst = vstack_push(&vs);
if (known_func_locals) vs.known_func[vs.sp - 1] = known_func_locals[idx];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, local_regs[idx])));
if (known_type_locals && known_type_locals[idx] == SV_TI_NUM) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, vs.d_regs[vs.sp - 1]),
MIR_new_reg_op(ctx, local_d_regs[idx])));
if (vs.slot_type) vs.slot_type[vs.sp - 1] = SLOT_NUM;
}
}
break;
}
case OP_PUT_LOCAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)n_locals) { ok = false; break; }
sv_func_t *kf = vs.known_func[vs.sp - 1];
bool src_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t src_d = src_is_num ? vs.d_regs[vs.sp - 1] : 0;
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t src = vstack_pop(&vs);
if (known_func_locals) known_func_locals[idx] = kf;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[idx]),
MIR_new_reg_op(ctx, src)));
if (local_d_regs && known_type_locals && known_type_locals[idx] == SV_TI_NUM) {
if (src_is_num)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, local_d_regs[idx]),
MIR_new_reg_op(ctx, src_d)));
else
mir_i64_to_d(ctx, jit_func, local_d_regs[idx], local_regs[idx], r_d_slot);
}
if (has_captures && captured_locals && captured_locals[idx])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, src)));
break;
}
case OP_PUT_LOCAL8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)n_locals) { ok = false; break; }
sv_func_t *kf = vs.known_func[vs.sp - 1];
bool src_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t src_d = src_is_num ? vs.d_regs[vs.sp - 1] : 0;
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t src = vstack_pop(&vs);
if (known_func_locals) known_func_locals[idx] = kf;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[idx]),
MIR_new_reg_op(ctx, src)));
if (local_d_regs && known_type_locals && known_type_locals[idx] == SV_TI_NUM) {
if (src_is_num)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, local_d_regs[idx]),
MIR_new_reg_op(ctx, src_d)));
else
mir_i64_to_d(ctx, jit_func, local_d_regs[idx], local_regs[idx], r_d_slot);
}
if (has_captures && captured_locals && captured_locals[idx])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, src)));
break;
}
case OP_SET_LOCAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)n_locals) { ok = false; break; }
bool src_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t src_d = src_is_num ? vs.d_regs[vs.sp - 1] : 0;
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t src = vstack_top(&vs);
if (known_func_locals) known_func_locals[idx] = vs.known_func[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[idx]),
MIR_new_reg_op(ctx, src)));
if (local_d_regs && known_type_locals && known_type_locals[idx] == SV_TI_NUM) {
if (src_is_num)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, local_d_regs[idx]),
MIR_new_reg_op(ctx, src_d)));
else
mir_i64_to_d(ctx, jit_func, local_d_regs[idx], local_regs[idx], r_d_slot);
}
if (has_captures && captured_locals && captured_locals[idx])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, src)));
break;
}
case OP_SET_LOCAL8: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)n_locals) { ok = false; break; }
bool src_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t src_d = src_is_num ? vs.d_regs[vs.sp - 1] : 0;
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t src = vstack_top(&vs);
if (known_func_locals) known_func_locals[idx] = vs.known_func[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[idx]),
MIR_new_reg_op(ctx, src)));
if (local_d_regs && known_type_locals && known_type_locals[idx] == SV_TI_NUM) {
if (src_is_num)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, local_d_regs[idx]),
MIR_new_reg_op(ctx, src_d)));
else
mir_i64_to_d(ctx, jit_func, local_d_regs[idx], local_regs[idx], r_d_slot);
}
if (has_captures && captured_locals && captured_locals[idx])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, src)));
break;
}
case OP_SET_LOCAL_UNDEF: {
uint16_t idx = sv_get_u16(ip + 1);
if (idx >= (uint16_t)n_locals) { ok = false; break; }
if (known_type_locals) known_type_locals[idx] = SV_TI_UNKNOWN;
break;
}
case OP_POP:
vstack_pop(&vs);
break;
case OP_DUP: {
sv_func_t *kf = vs.known_func[vs.sp - 1];
jit_method_ic_info_t mi = vs.method_ic ? vs.method_ic[vs.sp - 1] : (jit_method_ic_info_t){0};
bool kc = vs.has_const && vs.has_const[vs.sp - 1];
uint64_t kcv = kc ? vs.known_const[vs.sp - 1] : 0;
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t top = vstack_top(&vs);
MIR_reg_t dst = vstack_push(&vs);
vs.known_func[vs.sp - 1] = kf;
if (vs.method_ic) vs.method_ic[vs.sp - 1] = mi;
if (kc && vs.has_const) { vs.has_const[vs.sp - 1] = true; vs.known_const[vs.sp - 1] = kcv; }
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, top)));
break;
}
case OP_DUP2: {
if (vs.sp < 2) { ok = false; break; }
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t ra = vs.regs[vs.sp - 2];
MIR_reg_t rb = vs.regs[vs.sp - 1];
sv_func_t *kf_a = vs.known_func ? vs.known_func[vs.sp - 2] : NULL;
sv_func_t *kf_b = vs.known_func ? vs.known_func[vs.sp - 1] : NULL;
jit_method_ic_info_t mi_a = vs.method_ic ? vs.method_ic[vs.sp - 2] : (jit_method_ic_info_t){0};
jit_method_ic_info_t mi_b = vs.method_ic ? vs.method_ic[vs.sp - 1] : (jit_method_ic_info_t){0};
MIR_reg_t da = vstack_push(&vs);
MIR_reg_t db = vstack_push(&vs);
if (vs.known_func) {
vs.known_func[vs.sp - 2] = kf_a;
vs.known_func[vs.sp - 1] = kf_b;
}
if (vs.method_ic) {
vs.method_ic[vs.sp - 2] = mi_a;
vs.method_ic[vs.sp - 1] = mi_b;
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, da),
MIR_new_reg_op(ctx, ra)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, db),
MIR_new_reg_op(ctx, rb)));
break;
}
case OP_INSERT2: {
if (vs.sp < 2) { ok = false; break; }
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t r_a = vs.regs[vs.sp - 1];
MIR_reg_t r_obj = vs.regs[vs.sp - 2];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_a)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[vs.sp - 1]),
MIR_new_reg_op(ctx, r_obj)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[vs.sp - 2]),
MIR_new_reg_op(ctx, r_tmp)));
MIR_reg_t dup = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dup),
MIR_new_reg_op(ctx, r_tmp)));
break;
}
case OP_INSERT3: {
if (vs.sp < 3) { ok = false; break; }
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 3, ctx, jit_func, r_d_slot);
MIR_reg_t r_a = vs.regs[vs.sp - 1];
MIR_reg_t r_prop = vs.regs[vs.sp - 2];
MIR_reg_t r_obj = vs.regs[vs.sp - 3];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_a)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[vs.sp - 1]),
MIR_new_reg_op(ctx, r_prop)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[vs.sp - 2]),
MIR_new_reg_op(ctx, r_obj)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[vs.sp - 3]),
MIR_new_reg_op(ctx, r_tmp)));
MIR_reg_t dup = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dup),
MIR_new_reg_op(ctx, r_tmp)));
break;
}
case OP_ADD:
case OP_ADD_NUM: {
uint8_t fb = func->type_feedback ? func->type_feedback[bc_off] : 0;
bool force_num_only = (op == OP_ADD_NUM);
bool fb_num_only = force_num_only || (fb && !(fb & ~SV_TFB_NUM));
bool fb_never_num = !force_num_only && fb && !(fb & SV_TFB_NUM);
bool l_is_num = vs.slot_type && vs.slot_type[vs.sp - 2] == SLOT_NUM;
bool r_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t rd = vstack_push(&vs);
if (fb_never_num) {
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
} else if (fb_num_only && l_is_num && r_is_num) {
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_reg_t fd_dst = vs.d_regs[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DADD,
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_r)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
} else if (fb_num_only && (l_is_num || r_is_num)) {
MIR_label_t bail_direct = MIR_new_label(ctx);
MIR_reg_t boxed_reg = l_is_num ? rr : rl;
mir_emit_is_num_guard(ctx, jit_func, r_bool, boxed_reg, bail_direct);
int boxed_idx = l_is_num ? (int)vs.sp : (int)(vs.sp - 1);
mir_i64_to_d(ctx, jit_func, vs.d_regs[boxed_idx],
vs.regs[boxed_idx], r_d_slot);
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_reg_t fd_dst = vs.d_regs[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DADD,
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_r)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else if (fb_num_only) {
MIR_label_t bail_direct = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, bail_direct);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, bail_direct);
int an = arith_n++;
char d1[32], d2[32], d3[32];
snprintf(d1, sizeof(d1), "add_d1_%d", an);
snprintf(d2, sizeof(d2), "add_d2_%d", an);
snprintf(d3, sizeof(d3), "add_d3_%d", an);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d3);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DADD,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, rd, fd3, r_d_slot);
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else {
MIR_label_t slow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
int an = arith_n++;
char d1[32], d2[32], d3[32];
snprintf(d1, sizeof(d1), "add_d1_%d", an);
snprintf(d2, sizeof(d2), "add_d2_%d", an);
snprintf(d3, sizeof(d3), "add_d3_%d", an);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d3);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DADD,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, rd, fd3, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, jit_func, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_add,
r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, done);
}
break;
}
case OP_SUB:
case OP_SUB_NUM: {
uint8_t fb = func->type_feedback ? func->type_feedback[bc_off] : 0;
bool force_num_only = (op == OP_SUB_NUM);
bool fb_num_only = force_num_only || (fb && !(fb & ~SV_TFB_NUM));
bool fb_never_num = !force_num_only && fb && !(fb & SV_TFB_NUM);
bool l_is_num = vs.slot_type && vs.slot_type[vs.sp - 2] == SLOT_NUM;
bool r_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t rd = vstack_push(&vs);
if (fb_never_num) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_sub,
r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
} else if (fb_num_only && l_is_num && r_is_num) {
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_reg_t fd_dst = vs.d_regs[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DSUB,
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_r)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
} else if (fb_num_only && (l_is_num || r_is_num)) {
MIR_label_t bail_direct = MIR_new_label(ctx);
MIR_reg_t boxed_reg = l_is_num ? rr : rl;
mir_emit_is_num_guard(ctx, jit_func, r_bool, boxed_reg, bail_direct);
int boxed_idx = l_is_num ? (int)vs.sp : (int)(vs.sp - 1);
mir_i64_to_d(ctx, jit_func, vs.d_regs[boxed_idx],
vs.regs[boxed_idx], r_d_slot);
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_reg_t fd_dst = vs.d_regs[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DSUB,
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_r)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else if (fb_num_only) {
MIR_label_t bail_direct = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, bail_direct);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, bail_direct);
int sn = arith_n++;
char d1[32], d2[32], d3[32];
snprintf(d1, sizeof(d1), "sub_d1_%d", sn);
snprintf(d2, sizeof(d2), "sub_d2_%d", sn);
snprintf(d3, sizeof(d3), "sub_d3_%d", sn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d3);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DSUB,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, rd, fd3, r_d_slot);
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else {
MIR_label_t slow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
int sn = arith_n++;
char d1[32], d2[32], d3[32];
snprintf(d1, sizeof(d1), "sub_d1_%d", sn);
snprintf(d2, sizeof(d2), "sub_d2_%d", sn);
snprintf(d3, sizeof(d3), "sub_d3_%d", sn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d3);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DSUB,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, rd, fd3, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, jit_func, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_sub, r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, done);
}
break;
}
case OP_MUL:
case OP_MUL_NUM: {
uint8_t fb = func->type_feedback ? func->type_feedback[bc_off] : 0;
bool force_num_only = (op == OP_MUL_NUM);
bool fb_num_only = force_num_only || (fb && !(fb & ~SV_TFB_NUM));
bool fb_never_num = !force_num_only && fb && !(fb & SV_TFB_NUM);
bool l_is_num = vs.slot_type && vs.slot_type[vs.sp - 2] == SLOT_NUM;
bool r_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t rd = vstack_push(&vs);
if (fb_never_num) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_mul,
r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
} else if (fb_num_only && l_is_num && r_is_num) {
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_reg_t fd_dst = vs.d_regs[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMUL,
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_r)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
} else if (fb_num_only && (l_is_num || r_is_num)) {
MIR_label_t bail_direct = MIR_new_label(ctx);
MIR_reg_t boxed_reg = l_is_num ? rr : rl;
mir_emit_is_num_guard(ctx, jit_func, r_bool, boxed_reg, bail_direct);
int boxed_idx = l_is_num ? (int)vs.sp : (int)(vs.sp - 1);
mir_i64_to_d(ctx, jit_func, vs.d_regs[boxed_idx],
vs.regs[boxed_idx], r_d_slot);
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_reg_t fd_dst = vs.d_regs[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMUL,
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_r)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else if (fb_num_only) {
MIR_label_t bail_direct = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, bail_direct);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, bail_direct);
int mn = arith_n++;
char d1[32], d2[32], d3[32];
snprintf(d1, sizeof(d1), "mul_d1_%d", mn);
snprintf(d2, sizeof(d2), "mul_d2_%d", mn);
snprintf(d3, sizeof(d3), "mul_d3_%d", mn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d3);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMUL,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, rd, fd3, r_d_slot);
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else {
MIR_label_t slow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
int mn = arith_n++;
char d1[32], d2[32], d3[32];
snprintf(d1, sizeof(d1), "mul_d1_%d", mn);
snprintf(d2, sizeof(d2), "mul_d2_%d", mn);
snprintf(d3, sizeof(d3), "mul_d3_%d", mn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d3);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMUL,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, rd, fd3, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, jit_func, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_mul, r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, done);
}
break;
}
case OP_DIV:
case OP_DIV_NUM: {
uint8_t fb = func->type_feedback ? func->type_feedback[bc_off] : 0;
bool force_num_only = (op == OP_DIV_NUM);
bool fb_num_only = force_num_only || (fb && !(fb & ~SV_TFB_NUM));
bool fb_never_num = !force_num_only && fb && !(fb & SV_TFB_NUM);
bool l_is_num = vs.slot_type && vs.slot_type[vs.sp - 2] == SLOT_NUM;
bool r_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t rd = vstack_push(&vs);
if (fb_never_num) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_div,
r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
} else if (fb_num_only && l_is_num && r_is_num) {
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_reg_t fd_dst = vs.d_regs[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DDIV,
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_r)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
} else if (fb_num_only && (l_is_num || r_is_num)) {
MIR_label_t bail_direct = MIR_new_label(ctx);
MIR_reg_t boxed_reg = l_is_num ? rr : rl;
mir_emit_is_num_guard(ctx, jit_func, r_bool, boxed_reg, bail_direct);
int boxed_idx = l_is_num ? (int)vs.sp : (int)(vs.sp - 1);
mir_i64_to_d(ctx, jit_func, vs.d_regs[boxed_idx],
vs.regs[boxed_idx], r_d_slot);
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_reg_t fd_dst = vs.d_regs[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DDIV,
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_dst),
MIR_new_reg_op(ctx, fd_r)));
vs.slot_type[vs.sp - 1] = SLOT_NUM;
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else if (fb_num_only) {
MIR_label_t bail_direct = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, bail_direct);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, bail_direct);
int dn = arith_n++;
char d1[32], d2[32], d3[32];
snprintf(d1, sizeof(d1), "dv_d1_%d", dn);
snprintf(d2, sizeof(d2), "dv_d2_%d", dn);
snprintf(d3, sizeof(d3), "dv_d3_%d", dn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d3);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DDIV,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, rd, fd3, r_d_slot);
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else {
MIR_label_t slow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
int dn = arith_n++;
char d1[32], d2[32], d3[32];
snprintf(d1, sizeof(d1), "dv_d1_%d", dn);
snprintf(d2, sizeof(d2), "dv_d2_%d", dn);
snprintf(d3, sizeof(d3), "dv_d3_%d", dn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d3);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DDIV,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, rd, fd3, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, jit_func, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_div, r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, done);
}
break;
}
case OP_MOD: {
vstack_flush_to_boxed(&vs, ctx, jit_func, r_d_slot);
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t rd = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_mod, r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
break;
}
case OP_NEG: {
if (vs.slot_type) vs.slot_type[vs.sp - 1] = SLOT_BOXED;
MIR_reg_t rs = vstack_top(&vs);
MIR_label_t slow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rs, slow);
int nn = arith_n++;
char neg_d1[32], neg_d2[32];
snprintf(neg_d1, sizeof(neg_d1), "neg_d1_%d", nn);
snprintf(neg_d2, sizeof(neg_d2), "neg_d2_%d", nn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, neg_d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, neg_d2);
mir_i64_to_d(ctx, jit_func, fd1, rs, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DNEG,
MIR_new_reg_op(ctx, fd2),
MIR_new_reg_op(ctx, fd1)));
mir_d_to_i64(ctx, jit_func, rs, fd2, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, jit_func, slow);
for (int i = 0; i < vs.sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, vs.sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, done);
break;
}
case OP_POST_INC: {
int top_idx = vs.sp - 1;
vstack_ensure_boxed(&vs, top_idx, ctx, jit_func, r_d_slot);
MIR_reg_t rold = vstack_top(&vs);
MIR_reg_t rnew = vstack_push(&vs);
int pin = arith_n++;
char pi_d1[32], pi_d2[32];
snprintf(pi_d1, sizeof(pi_d1), "pi_d1_%d", pin);
snprintf(pi_d2, sizeof(pi_d2), "pi_d2_%d", pin);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, pi_d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, pi_d2);
mir_i64_to_d(ctx, jit_func, fd1, rold, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DADD,
MIR_new_reg_op(ctx, fd2),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, r_d_one)));
mir_d_to_i64(ctx, jit_func, rnew, fd2, r_d_slot);
break;
}
case OP_IS_UNDEF:
case OP_IS_NULL: {
MIR_reg_t rs = vstack_top(&vs);
uint64_t cmp_val = (op == OP_IS_UNDEF) ? mkval(T_UNDEF, 0) : mkval(T_NULL, 0);
MIR_label_t is_true = MIR_new_label(ctx);
MIR_label_t is_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_true),
MIR_new_reg_op(ctx, rs),
MIR_new_uint_op(ctx, cmp_val)));
mir_load_imm(ctx, jit_func, rs, js_false);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, is_done)));
MIR_append_insn(ctx, jit_func, is_true);
mir_load_imm(ctx, jit_func, rs, js_true);
MIR_append_insn(ctx, jit_func, is_done);
break;
}
case OP_LT: {
uint8_t fb = func->type_feedback ? func->type_feedback[bc_off] : 0;
bool fb_num_only = fb && !(fb & ~SV_TFB_NUM);
bool fb_never_num = fb && !(fb & SV_TFB_NUM);
bool l_is_num = vs.slot_type && vs.slot_type[vs.sp - 2] == SLOT_NUM;
bool r_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t rd = vstack_push(&vs);
if (fb_never_num) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_lt,
r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
} else if (fb_num_only && l_is_num && r_is_num) {
MIR_reg_t fd_l = vs.d_regs[vs.sp - 1];
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DLT,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd_l),
MIR_new_reg_op(ctx, fd_r)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
} else if (fb_num_only && (l_is_num || r_is_num)) {
MIR_label_t bail_direct = MIR_new_label(ctx);
MIR_reg_t boxed_reg = l_is_num ? rr : rl;
mir_emit_is_num_guard(ctx, jit_func, r_bool, boxed_reg, bail_direct);
int boxed_idx = l_is_num ? (int)vs.sp : (int)(vs.sp - 1);
mir_i64_to_d(ctx, jit_func, vs.d_regs[boxed_idx],
vs.regs[boxed_idx], r_d_slot);
MIR_reg_t fd_l = vs.d_regs[vs.sp - 1];
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DLT,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd_l),
MIR_new_reg_op(ctx, fd_r)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else if (fb_num_only) {
MIR_label_t bail_direct = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, bail_direct);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, bail_direct);
int ltn = arith_n++;
char d1[32], d2[32];
snprintf(d1, sizeof(d1), "lt_d1_%d", ltn);
snprintf(d2, sizeof(d2), "lt_d2_%d", ltn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DLT,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else {
MIR_label_t slow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
int ltn = arith_n++;
char d1[32], d2[32];
snprintf(d1, sizeof(d1), "lt_d1_%d", ltn);
snprintf(d2, sizeof(d2), "lt_d2_%d", ltn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DLT,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, jit_func, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_lt, r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, done);
}
break;
}
case OP_LE: {
uint8_t fb = func->type_feedback ? func->type_feedback[bc_off] : 0;
bool fb_num_only = fb && !(fb & ~SV_TFB_NUM);
bool fb_never_num = fb && !(fb & SV_TFB_NUM);
bool l_is_num = vs.slot_type && vs.slot_type[vs.sp - 2] == SLOT_NUM;
bool r_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t rd = vstack_push(&vs);
if (fb_never_num) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_le,
r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
} else if (fb_num_only && l_is_num && r_is_num) {
MIR_reg_t fd_l = vs.d_regs[vs.sp - 1];
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DLE,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd_l),
MIR_new_reg_op(ctx, fd_r)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
} else if (fb_num_only && (l_is_num || r_is_num)) {
MIR_label_t bail_direct = MIR_new_label(ctx);
MIR_reg_t boxed_reg = l_is_num ? rr : rl;
mir_emit_is_num_guard(ctx, jit_func, r_bool, boxed_reg, bail_direct);
int boxed_idx = l_is_num ? (int)vs.sp : (int)(vs.sp - 1);
mir_i64_to_d(ctx, jit_func, vs.d_regs[boxed_idx],
vs.regs[boxed_idx], r_d_slot);
MIR_reg_t fd_l = vs.d_regs[vs.sp - 1];
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DLE,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd_l),
MIR_new_reg_op(ctx, fd_r)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else if (fb_num_only) {
MIR_label_t bail_direct = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, bail_direct);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, bail_direct);
int len = arith_n++;
char d1[32], d2[32];
snprintf(d1, sizeof(d1), "le_d1_%d", len);
snprintf(d2, sizeof(d2), "le_d2_%d", len);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DLE,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else {
MIR_label_t slow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
int len = arith_n++;
char d1[32], d2[32];
snprintf(d1, sizeof(d1), "le_d1_%d", len);
snprintf(d2, sizeof(d2), "le_d2_%d", len);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DLE,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, jit_func, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_le, r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, done);
}
break;
}
case OP_JMP:
case OP_JMP8: {
vstack_flush_to_boxed(&vs, ctx, jit_func, r_d_slot);
bool short_op = (op == OP_JMP8);
int target = bc_off + sz + (short_op ? (int8_t)sv_get_i8(ip + 1)
: sv_get_i32(ip + 1));
MIR_label_t lbl = label_for_branch(ctx, &lm, target, vs.sp);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl)));
break;
}
case OP_JMP_FALSE_PEEK:
case OP_JMP_TRUE_PEEK:
case OP_JMP_FALSE:
case OP_JMP_FALSE8:
case OP_JMP_TRUE:
case OP_JMP_TRUE8: {
vstack_flush_to_boxed(&vs, ctx, jit_func, r_d_slot);
bool is_peek = (op == OP_JMP_FALSE_PEEK || op == OP_JMP_TRUE_PEEK);
MIR_reg_t cond = is_peek ? vstack_top(&vs) : vstack_pop(&vs);
bool short_op = (op == OP_JMP_FALSE8 || op == OP_JMP_TRUE8);
bool is_false_branch = (op == OP_JMP_FALSE || op == OP_JMP_FALSE8
|| op == OP_JMP_FALSE_PEEK);
int target = bc_off + sz + (short_op ? (int8_t)sv_get_i8(ip + 1)
: sv_get_i32(ip + 1));
MIR_label_t lbl = label_for_branch(ctx, &lm, target, vs.sp);
MIR_label_t lbl_not_bool = MIR_new_label(ctx);
MIR_label_t lbl_not_num = MIR_new_label(ctx);
MIR_label_t lbl_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, cond),
MIR_new_uint_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, lbl_not_bool),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, js_false >> NANBOX_TYPE_SHIFT)));
uint64_t cmp_bool = is_false_branch ? js_false : js_true;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl),
MIR_new_reg_op(ctx, cond),
MIR_new_uint_op(ctx, cmp_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_done)));
MIR_append_insn(ctx, jit_func, lbl_not_bool);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_UBGT,
MIR_new_label_op(ctx, lbl_not_num),
MIR_new_reg_op(ctx, cond),
MIR_new_uint_op(ctx, NANBOX_PREFIX)));
if (!r_d_slot) {
r_d_slot = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "d_slot_cond");
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_ALLOCA,
MIR_new_reg_op(ctx, r_d_slot),
MIR_new_uint_op(ctx, 8)));
}
if (!r_cond_d) {
r_cond_d = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, "cond_d");
r_cond_nan = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "cond_nan");
r_cond_zd = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, "zero_d");
r_cond_zero = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "cond_zero");
}
mir_i64_to_d(ctx, jit_func, r_cond_d, cond, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DNE,
MIR_new_reg_op(ctx, r_cond_nan),
MIR_new_reg_op(ctx, r_cond_d),
MIR_new_reg_op(ctx, r_cond_d)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, r_cond_zd),
MIR_new_double_op(ctx, 0.0)));
MIR_reg_t r_is_zero = r_cond_zero;
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DEQ,
MIR_new_reg_op(ctx, r_is_zero),
MIR_new_reg_op(ctx, r_cond_d),
MIR_new_reg_op(ctx, r_cond_zd)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_is_zero),
MIR_new_reg_op(ctx, r_cond_nan)));
if (is_false_branch) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, lbl),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, 0)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, 0)));
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_done)));
MIR_append_insn(ctx, jit_func, lbl_not_num);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 5,
MIR_new_ref_op(ctx, truthy_proto),
MIR_new_ref_op(ctx, imp_is_truthy),
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, cond)));
if (is_false_branch) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, 0)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, lbl),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, 0)));
}
MIR_append_insn(ctx, jit_func, lbl_done);
break;
}
case OP_TAIL_CALL:
case OP_CALL: {
vstack_flush_to_boxed(&vs, ctx, jit_func, r_d_slot);
bool is_tail = (op == OP_TAIL_CALL);
uint16_t call_argc = sv_get_u16(ip + 1);
if (call_argc > 16 || vs.sp < (int)call_argc + 1) { ok = false; break; }
if (!is_tail) {
sv_func_t *inline_callee = vs.known_func[vs.sp - call_argc - 1];
if (!inline_callee)
inline_callee = sv_tfb_get_call_target(func, bc_off);
bool speculative = (inline_callee && !vs.known_func[vs.sp - call_argc - 1]);
if (inline_callee && inline_callee != func &&
inline_depth < JIT_INLINE_MAX_DEPTH &&
inline_budget >= inline_callee->code_len &&
jit_inlineable(inline_callee)
&& jit_inline_body_feasible(inline_callee)) {
int cn = call_n++;
MIR_reg_t inl_arg_regs[call_argc > 0 ? call_argc : 1];
for (int i = (int)call_argc - 1; i >= 0; i--)
inl_arg_regs[i] = vstack_pop(&vs);
MIR_reg_t r_inl_callee = vstack_pop(&vs);
MIR_reg_t r_call_res = vstack_push(&vs);
MIR_label_t inl_slow = MIR_new_label(ctx);
MIR_label_t inl_join = MIR_new_label(ctx);
MIR_reg_t r_inl_cl = 0;
MIR_reg_t r_inl_new_target = 0;
MIR_reg_t r_inl_super = 0;
char inl_this_rn[32], inl_flags_rn[32], inl_bound_rn[32];
snprintf(inl_this_rn, sizeof(inl_this_rn), "inl%d_this", cn);
snprintf(inl_flags_rn, sizeof(inl_flags_rn), "inl%d_flags", cn);
snprintf(inl_bound_rn, sizeof(inl_bound_rn), "inl%d_bound", cn);
MIR_reg_t r_inl_this = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_JSVAL, inl_this_rn);
MIR_reg_t r_inl_flags = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, inl_flags_rn);
MIR_reg_t r_inl_bound = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_JSVAL, inl_bound_rn);
{
char cl_rn[32]; snprintf(cl_rn, sizeof(cl_rn), "inl%d_cl", cn);
r_inl_cl = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cl_rn);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, r_inl_cl),
MIR_new_reg_op(ctx, r_inl_callee),
MIR_new_uint_op(ctx, NANBOX_DATA_MASK)));
}
{
char nt_rn[32], sup_rn[32];
snprintf(nt_rn, sizeof(nt_rn), "inl%d_nt", cn);
snprintf(sup_rn, sizeof(sup_rn), "inl%d_sup", cn);
r_inl_new_target = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_JSVAL, nt_rn);
r_inl_super = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_JSVAL, sup_rn);
mir_load_imm(ctx, jit_func, r_inl_new_target, mkval(T_UNDEF, 0));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_inl_super),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_closure_t, super_val),
r_inl_cl, 0, 1)));
}
if (speculative) {
char gt_rn[32]; snprintf(gt_rn, sizeof(gt_rn), "inl%d_gt", cn);
MIR_reg_t r_guard_tag = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, gt_rn);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_guard_tag),
MIR_new_reg_op(ctx, r_inl_callee),
MIR_new_uint_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, inl_slow),
MIR_new_reg_op(ctx, r_guard_tag),
MIR_new_uint_op(ctx, NANBOX_TFUNC_TAG)));
char gf_rn[32]; snprintf(gf_rn, sizeof(gf_rn), "inl%d_gf", cn);
MIR_reg_t r_guard_fn = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_T_I64, gf_rn);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_guard_fn),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_closure_t, func),
r_inl_cl, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, inl_slow),
MIR_new_reg_op(ctx, r_guard_fn),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)inline_callee)));
}
mir_emit_resolve_call_this(ctx, jit_func, r_inl_this, r_inl_cl,
r_this_curr, r_inl_flags, r_inl_bound);
bool inlined = jit_emit_inline_body(
ctx, jit_func, inline_callee,
inl_arg_regs, (int)call_argc,
r_call_res, inl_slow, inl_join,
r_bool, &r_d_slot, cn,
r_inl_cl, r_inl_this, r_inl_new_target, r_inl_super,
NULL, 0, 0, r_ic_epoch_val,
r_vm, r_js,
helper2_proto, imp_seq, imp_sne, imp_eq, imp_ne,
gf_proto, imp_get_field,
put_field_proto, imp_put_field,
gg_proto, imp_gg,
special_obj_proto, imp_special_obj);
if (inlined) {
inline_budget -= inline_callee->code_len;
MIR_append_insn(ctx, jit_func, inl_slow);
for (int i = 0; i < (int)call_argc; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)),
r_args_buf, 0, 1),
MIR_new_reg_op(ctx, inl_arg_regs[i])));
char rn_sl_this[32];
snprintf(rn_sl_this, sizeof(rn_sl_this), "inl%d_slow_t", cn);
MIR_reg_t r_slow_this = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_JSVAL, rn_sl_this);
mir_load_imm(ctx, jit_func, r_slow_this, mkval(T_UNDEF, 0));
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, call_proto),
MIR_new_ref_op(ctx, imp_call),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_inl_callee),
MIR_new_reg_op(ctx, r_slow_this),
MIR_new_reg_op(ctx, r_args_buf),
MIR_new_int_op(ctx, (int64_t)call_argc)));
MIR_append_insn(ctx, jit_func, inl_join);
break;
}
MIR_append_insn(ctx, jit_func, inl_slow);
MIR_append_insn(ctx, jit_func, inl_join);
vs.sp = vs.sp - 1 + call_argc + 1;
}
}
int cn = call_n++;
char rn_arr[32], rn_this[32], rn_ccl[32], rn_cfn[32], rn_jptr[32], rn_csup[32];
snprintf(rn_arr, sizeof(rn_arr), "arg_arr%d", cn);
snprintf(rn_this, sizeof(rn_this), "call_this%d", cn);
snprintf(rn_ccl, sizeof(rn_ccl), "callee_cl%d", cn);
snprintf(rn_cfn, sizeof(rn_cfn), "callee_func%d", cn);
snprintf(rn_jptr, sizeof(rn_jptr), "jit_ptr%d", cn);
snprintf(rn_csup, sizeof(rn_csup), "callee_super%d", cn);
MIR_reg_t r_arg_arr = r_args_buf;
for (int i = (int)call_argc - 1; i >= 0; i--) {
MIR_reg_t areg = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)),
r_arg_arr, 0, 1),
MIR_new_reg_op(ctx, areg)));
}
sv_func_t *call_known = vs.known_func
? vs.known_func[vs.sp - 1] : NULL;
MIR_reg_t r_call_func = vstack_pop(&vs);
MIR_reg_t r_call_this = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rn_this);
mir_load_imm(ctx, jit_func, r_call_this, mkval(T_UNDEF, 0));
MIR_reg_t r_call_res = vstack_push(&vs);
if (call_known == func) {
if (is_tail && jit_try_depth == 0) {
mir_emit_self_tail(ctx, jit_func, (int)call_argc, param_count,
r_tco_args, r_arg_arr, r_args, r_argc,
local_regs, n_locals, has_captured_slots, r_slotbuf, captured_params,
has_captures,
captured_locals, r_lbuf, self_tail_entry);
break;
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, self_proto),
MIR_new_ref_op(ctx, jit_func),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0)),
MIR_new_reg_op(ctx, r_super_val),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)call_argc),
MIR_new_reg_op(ctx, r_closure)));
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
}
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_result),
MIR_new_reg_op(ctx, r_call_res)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
MIR_append_insn(ctx, jit_func, no_err);
} else {
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_call_res)));
MIR_append_insn(ctx, jit_func, no_err);
}
break;
}
MIR_label_t lbl_self_call = MIR_new_label(ctx);
MIR_label_t lbl_super_call = MIR_new_label(ctx);
MIR_label_t lbl_interp_call = MIR_new_label(ctx);
MIR_label_t lbl_call_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl_super_call),
MIR_new_reg_op(ctx, r_call_func),
MIR_new_reg_op(ctx, r_super_val)));
MIR_reg_t r_callee_cl = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_ccl);
mir_emit_get_closure(ctx, jit_func, r_callee_cl, r_call_func,
r_bool, lbl_interp_call);
MIR_reg_t r_callee_fn = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_cfn);
MIR_reg_t r_callee_super = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rn_csup);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_callee_fn),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_closure_t, func),
r_callee_cl, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_callee_super),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_closure_t, super_val),
r_callee_cl, 0, 1)));
mir_emit_resolve_call_this(ctx, jit_func, r_call_this, r_callee_cl,
r_call_this, r_bool, r_tmp2);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl_interp_call),
MIR_new_reg_op(ctx, r_callee_fn),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl_self_call),
MIR_new_reg_op(ctx, r_callee_cl),
MIR_new_reg_op(ctx, r_closure)));
MIR_reg_t r_jit_ptr = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_jptr);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_jit_ptr),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_func_t, jit_code),
r_callee_fn, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl_interp_call),
MIR_new_reg_op(ctx, r_jit_ptr),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, self_proto),
MIR_new_reg_op(ctx, r_jit_ptr),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0)),
MIR_new_reg_op(ctx, r_callee_super),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)call_argc),
MIR_new_reg_op(ctx, r_callee_cl)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_call_done)));
MIR_append_insn(ctx, jit_func, lbl_self_call);
if (is_tail && jit_try_depth == 0) {
mir_emit_self_tail(ctx, jit_func, (int)call_argc, param_count,
r_tco_args, r_arg_arr, r_args, r_argc,
local_regs, n_locals, has_captured_slots, r_slotbuf, captured_params,
has_captures,
captured_locals, r_lbuf, self_tail_entry);
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, self_proto),
MIR_new_ref_op(ctx, jit_func),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0)),
MIR_new_reg_op(ctx, r_super_val),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)call_argc),
MIR_new_reg_op(ctx, r_closure)));
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_call_done)));
MIR_append_insn(ctx, jit_func, lbl_super_call);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64, 0, r_call_out_this, 0, 1),
MIR_new_reg_op(ctx, r_this_curr)));
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 12,
MIR_new_ref_op(ctx, call_method_proto),
MIR_new_ref_op(ctx, imp_call_method),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_call_func),
MIR_new_reg_op(ctx, r_this_curr),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)call_argc),
MIR_new_reg_op(ctx, r_super_val),
MIR_new_reg_op(ctx, r_new_target),
MIR_new_reg_op(ctx, r_call_out_this)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_this_curr),
MIR_new_mem_op(ctx, MIR_T_I64, 0, r_call_out_this, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_call_done)));
MIR_append_insn(ctx, jit_func, lbl_interp_call);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, call_proto),
MIR_new_ref_op(ctx, imp_call),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_call_func),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)call_argc)));
MIR_append_insn(ctx, jit_func, lbl_call_done);
if (is_tail && jit_try_depth == 0) {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_call_res)));
} else {
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
}
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_call_res)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
MIR_append_insn(ctx, jit_func, no_err);
} else {
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_call_res)));
MIR_append_insn(ctx, jit_func, no_err);
}
if (is_tail) {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_call_res)));
}
}
break;
}
case OP_SPECIAL_OBJ: {
uint8_t which = sv_get_u8(ip + 1);
MIR_reg_t dst = vstack_push(&vs);
if (which == 1) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_new_target)));
} else if (which == 2) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_super_val)));
} else if (which == 3) {
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 6,
MIR_new_ref_op(ctx, special_obj_proto),
MIR_new_ref_op(ctx, imp_special_obj),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_int_op(ctx, (int64_t)which)));
} else mir_load_imm(ctx, jit_func, dst, mkval(T_UNDEF, 0));
break;
}
case OP_GET_UPVAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (vs.known_func && hint_closure &&
idx < (uint16_t)func->upvalue_count &&
hint_closure->upvalues && hint_closure->upvalues[idx]) {
ant_value_t uv_val = *hint_closure->upvalues[idx]->location;
if (vtype(uv_val) == T_FUNC) {
sv_closure_t *ucl = js_func_closure(uv_val);
if (ucl && ucl->func == func) {
MIR_reg_t dst = vstack_push(&vs);
vs.known_func[vs.sp - 1] = func;
uint64_t func_tag = NANBOX_PREFIX
| ((ant_value_t)(T_FUNC & NANBOX_TYPE_MASK) << NANBOX_TYPE_SHIFT);
mir_load_imm(ctx, jit_func, r_tmp, func_tag);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_closure)));
break;
}
}
}
int un = upval_n++;
char rn_uvs[32], rn_uv[32], rn_loc[32];
snprintf(rn_uvs, sizeof(rn_uvs), "upvs%d", un);
snprintf(rn_uv, sizeof(rn_uv), "upv%d", un);
snprintf(rn_loc, sizeof(rn_loc), "uvloc%d", un);
MIR_reg_t r_uvs = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_uvs);
MIR_reg_t r_uv = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_uv);
MIR_reg_t r_loc = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_loc);
MIR_reg_t dst = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_uvs),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_closure_t, upvalues),
r_closure, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_uv),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)((int)idx * (int)sizeof(sv_upvalue_t *)),
r_uvs, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_loc),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_upvalue_t, location),
r_uv, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_JSVAL, 0, r_loc, 0, 1)));
break;
}
case OP_PUT_UPVAL: {
uint16_t idx = sv_get_u16(ip + 1);
int un = upval_n++;
char rn_uvs[32], rn_uv[32], rn_loc[32];
snprintf(rn_uvs, sizeof(rn_uvs), "upvs%d", un);
snprintf(rn_uv, sizeof(rn_uv), "upv%d", un);
snprintf(rn_loc, sizeof(rn_loc), "uvloc%d", un);
MIR_reg_t r_uvs = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_uvs);
MIR_reg_t r_uv = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_uv);
MIR_reg_t r_loc = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_loc);
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t src = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_uvs),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_closure_t, upvalues),
r_closure, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_uv),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)((int)idx * (int)sizeof(sv_upvalue_t *)),
r_uvs, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_loc),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_upvalue_t, location),
r_uv, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL, 0, r_loc, 0, 1),
MIR_new_reg_op(ctx, src)));
break;
}
case OP_SET_UPVAL: {
uint16_t idx = sv_get_u16(ip + 1);
int un = upval_n++;
char rn_uvs[32], rn_uv[32], rn_loc[32];
snprintf(rn_uvs, sizeof(rn_uvs), "upvs%d", un);
snprintf(rn_uv, sizeof(rn_uv), "upv%d", un);
snprintf(rn_loc, sizeof(rn_loc), "uvloc%d", un);
MIR_reg_t r_uvs = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_uvs);
MIR_reg_t r_uv = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_uv);
MIR_reg_t r_loc = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_loc);
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t src = vstack_top(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_uvs),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_closure_t, upvalues),
r_closure, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_uv),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)((int)idx * (int)sizeof(sv_upvalue_t *)),
r_uvs, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_loc),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_upvalue_t, location),
r_uv, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL, 0, r_loc, 0, 1),
MIR_new_reg_op(ctx, src)));
break;
}
case OP_CLOSE_UPVAL: {
uint16_t idx = sv_get_u16(ip + 1);
if (has_captures && n_locals > 0 && r_lbuf) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
}
if (has_captured_params && idx < (uint16_t)param_count)
mir_emit_close_marked_slots(ctx, jit_func,
close_upval_proto, imp_close_upval,
r_vm, r_slotbuf, captured_params, (int)idx, param_count);
if (has_captures)
mir_emit_close_marked_slots(ctx, jit_func,
close_upval_proto, imp_close_upval,
r_vm, r_lbuf, captured_locals,
idx >= (uint16_t)param_count ? (int)idx - param_count : 0, n_locals);
break;
}
case OP_GET_GLOBAL:
case OP_GET_GLOBAL_UNDEF: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)func->atom_count) { ok = false; break; }
sv_atom_t *atom = &func->atoms[idx];
MIR_reg_t dst = vstack_push(&vs);
if (vs.known_func) {
ant_value_t gv = jit_helper_get_global(js, atom->str, func, bc_off);
if (vtype(gv) == T_FUNC) {
sv_closure_t *gcl = js_func_closure(gv);
if (gcl && gcl->func == func) {
vs.known_func[vs.sp - 1] = func;
uint64_t func_tag = NANBOX_PREFIX
| ((ant_value_t)(T_FUNC & NANBOX_TYPE_MASK) << NANBOX_TYPE_SHIFT);
mir_load_imm(ctx, jit_func, r_tmp, func_tag);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_closure)));
break;
}
}
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 7,
MIR_new_ref_op(ctx, gg_proto),
MIR_new_ref_op(ctx, imp_gg),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_js),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_int_op(ctx, (int64_t)bc_off)));
break;
}
case OP_RETURN: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t ret_val = vstack_pop(&vs);
if (has_captured_slots)
mir_emit_close_marked_slots(ctx, jit_func,
close_upval_proto, imp_close_upval,
r_vm, r_slotbuf, captured_params, 0, param_count);
if (has_captures)
mir_emit_close_marked_slots(ctx, jit_func,
close_upval_proto, imp_close_upval,
r_vm, r_lbuf, captured_locals, 0, n_locals);
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, ret_val)));
break;
}
case OP_RETURN_UNDEF: {
if (has_captured_slots)
mir_emit_close_marked_slots(ctx, jit_func,
close_upval_proto, imp_close_upval,
r_vm, r_slotbuf, captured_params, 0, param_count);
if (has_captures)
mir_emit_close_marked_slots(ctx, jit_func,
close_upval_proto, imp_close_upval,
r_vm, r_lbuf, captured_locals, 0, n_locals);
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1,
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0))));
break;
}
case OP_INC_LOCAL: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)n_locals) { ok = false; break; }
if (known_func_locals) known_func_locals[idx] = NULL;
bool loc_is_num = known_type_locals && known_type_locals[idx] == SV_TI_NUM;
int in = arith_n++;
char il_d1[32], il_d2[32];
snprintf(il_d1, sizeof(il_d1), "il_d1_%d", in);
snprintf(il_d2, sizeof(il_d2), "il_d2_%d", in);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, il_d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, il_d2);
if (loc_is_num && local_d_regs)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, local_d_regs[idx])));
else
mir_i64_to_d(ctx, jit_func, fd1, local_regs[idx], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DADD,
MIR_new_reg_op(ctx, fd2),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, r_d_one)));
if (local_d_regs)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, local_d_regs[idx]),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, local_regs[idx], fd2, r_d_slot);
if (has_captures && captured_locals && captured_locals[idx])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[idx])));
break;
}
case OP_DEC_LOCAL: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)n_locals) { ok = false; break; }
if (known_func_locals) known_func_locals[idx] = NULL;
bool loc_is_num = known_type_locals && known_type_locals[idx] == SV_TI_NUM;
int dn = arith_n++;
char dl_d1[32], dl_d2[32];
snprintf(dl_d1, sizeof(dl_d1), "dl_d1_%d", dn);
snprintf(dl_d2, sizeof(dl_d2), "dl_d2_%d", dn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, dl_d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, dl_d2);
if (loc_is_num && local_d_regs)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, local_d_regs[idx])));
else
mir_i64_to_d(ctx, jit_func, fd1, local_regs[idx], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DSUB,
MIR_new_reg_op(ctx, fd2),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, r_d_one)));
if (local_d_regs)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, local_d_regs[idx]),
MIR_new_reg_op(ctx, fd2)));
mir_d_to_i64(ctx, jit_func, local_regs[idx], fd2, r_d_slot);
if (has_captures && captured_locals && captured_locals[idx])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[idx])));
break;
}
case OP_ADD_LOCAL: {
uint8_t idx = sv_get_u8(ip + 1);
if (idx >= (uint8_t)n_locals) { ok = false; break; }
if (known_func_locals) known_func_locals[idx] = NULL;
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t rr = vstack_pop(&vs);
MIR_label_t slow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, local_regs[idx], slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
int an = arith_n++;
char al_d1[32], al_d2[32], al_d3[32];
snprintf(al_d1, sizeof(al_d1), "al_d1_%d", an);
snprintf(al_d2, sizeof(al_d2), "al_d2_%d", an);
snprintf(al_d3, sizeof(al_d3), "al_d3_%d", an);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, al_d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, al_d2);
MIR_reg_t fd3 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, al_d3);
mir_i64_to_d(ctx, jit_func, fd1, local_regs[idx], r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DADD,
MIR_new_reg_op(ctx, fd3),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
if (local_d_regs)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DMOV,
MIR_new_reg_op(ctx, local_d_regs[idx]),
MIR_new_reg_op(ctx, fd3)));
mir_d_to_i64(ctx, jit_func, local_regs[idx], fd3, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, jit_func, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, local_regs[idx])));
mir_call_helper2(ctx, jit_func, local_regs[idx],
helper2_proto, imp_add,
r_vm, r_js, local_regs[idx], rr);
mir_emit_bailout_check(ctx, jit_func, local_regs[idx],
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, done);
if (has_captures && captured_locals && captured_locals[idx])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[idx])));
break;
}
case OP_STR_APPEND_LOCAL: {
uint16_t slot_idx = sv_get_u16(ip + 1);
int pre_op_sp = vs.sp;
if ((int)slot_idx < param_count) {
MIR_label_t arg_in_range = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_UBGT,
MIR_new_label_op(ctx, arg_in_range),
MIR_new_reg_op(ctx, r_argc),
MIR_new_int_op(ctx, (int64_t)slot_idx)));
mir_load_imm(ctx, jit_func, r_bailout_val, (uint64_t)SV_JIT_BAILOUT);
mir_emit_bailout_check(ctx, jit_func, r_bailout_val,
0, r_bailout_off, bc_off,
r_bailout_sp, pre_op_sp, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, arg_in_range);
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t rhs = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 11,
MIR_new_ref_op(ctx, str_append_local_proto),
MIR_new_ref_op(ctx, imp_str_append_local),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_reg_op(ctx, r_args),
MIR_new_reg_op(ctx, r_argc),
MIR_new_uint_op(ctx, 0),
MIR_new_int_op(ctx, (int64_t)slot_idx),
MIR_new_reg_op(ctx, rhs)));
} else {
uint16_t local_idx = (uint16_t)(slot_idx - (uint16_t)param_count);
if (local_idx >= (uint16_t)n_locals) { ok = false; break; }
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t rhs = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)local_idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[local_idx])));
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 11,
MIR_new_ref_op(ctx, str_append_local_proto),
MIR_new_ref_op(ctx, imp_str_append_local),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_uint_op(ctx, 0),
MIR_new_int_op(ctx, (int64_t)param_count),
MIR_new_reg_op(ctx, r_lbuf),
MIR_new_int_op(ctx, (int64_t)slot_idx),
MIR_new_reg_op(ctx, rhs)));
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[local_idx]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)local_idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
if (known_func_locals) known_func_locals[local_idx] = NULL;
if (known_type_locals) known_type_locals[local_idx] = SV_TI_UNKNOWN;
}
mir_emit_bailout_check(ctx, jit_func, r_err_tmp,
0, r_bailout_off, bc_off,
r_bailout_sp, pre_op_sp, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_err_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_err_tmp)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_STR_ALC_SNAPSHOT: {
uint16_t slot_idx = sv_get_u16(ip + 1);
int pre_op_sp = vs.sp;
if ((int)slot_idx < param_count) {
MIR_label_t arg_in_range = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_UBGT,
MIR_new_label_op(ctx, arg_in_range),
MIR_new_reg_op(ctx, r_argc),
MIR_new_int_op(ctx, (int64_t)slot_idx)));
mir_load_imm(ctx, jit_func, r_bailout_val, (uint64_t)SV_JIT_BAILOUT);
mir_emit_bailout_check(ctx, jit_func, r_bailout_val,
0, r_bailout_off, bc_off,
r_bailout_sp, pre_op_sp, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, arg_in_range);
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t rhs = vstack_pop(&vs);
MIR_reg_t lhs = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 12,
MIR_new_ref_op(ctx, str_append_local_snapshot_proto),
MIR_new_ref_op(ctx, imp_str_append_local_snapshot),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_reg_op(ctx, r_args),
MIR_new_reg_op(ctx, r_argc),
MIR_new_uint_op(ctx, 0),
MIR_new_int_op(ctx, (int64_t)slot_idx),
MIR_new_reg_op(ctx, lhs),
MIR_new_reg_op(ctx, rhs)));
} else {
uint16_t local_idx = (uint16_t)(slot_idx - (uint16_t)param_count);
if (local_idx >= (uint16_t)n_locals) { ok = false; break; }
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t rhs = vstack_pop(&vs);
MIR_reg_t lhs = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)local_idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[local_idx])));
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 12,
MIR_new_ref_op(ctx, str_append_local_snapshot_proto),
MIR_new_ref_op(ctx, imp_str_append_local_snapshot),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_uint_op(ctx, 0),
MIR_new_int_op(ctx, (int64_t)param_count),
MIR_new_reg_op(ctx, r_lbuf),
MIR_new_int_op(ctx, (int64_t)slot_idx),
MIR_new_reg_op(ctx, lhs),
MIR_new_reg_op(ctx, rhs)));
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[local_idx]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)local_idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
if (known_func_locals) known_func_locals[local_idx] = NULL;
if (known_type_locals) known_type_locals[local_idx] = SV_TI_UNKNOWN;
}
mir_emit_bailout_check(ctx, jit_func, r_err_tmp,
0, r_bailout_off, bc_off,
r_bailout_sp, pre_op_sp, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_err_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_err_tmp)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_TO_PROPKEY: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t src = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
MIR_label_t is_key = MIR_new_label(ctx);
MIR_label_t pk_done = MIR_new_label(ctx);
MIR_label_t pk_helper = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_UBLE,
MIR_new_label_op(ctx, pk_helper),
MIR_new_reg_op(ctx, src),
MIR_new_uint_op(ctx, NANBOX_PREFIX)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, src),
MIR_new_uint_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, NANBOX_TYPE_MASK)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_key),
MIR_new_reg_op(ctx, r_bool),
MIR_new_int_op(ctx, T_STR)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_key),
MIR_new_reg_op(ctx, r_bool),
MIR_new_int_op(ctx, T_SYMBOL)));
MIR_append_insn(ctx, jit_func, pk_helper);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 6,
MIR_new_ref_op(ctx, helper1_proto),
MIR_new_ref_op(ctx, imp_to_propkey),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, src)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, pk_done)));
MIR_append_insn(ctx, jit_func, is_key);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, src)));
MIR_append_insn(ctx, jit_func, pk_done);
break;
}
case OP_GET_FIELD: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)func->atom_count) { ok = false; break; }
sv_atom_t *atom = &func->atoms[idx];
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t obj = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
uint16_t ic_idx = sv_get_u16(ip + 5);
MIR_label_t no_err = MIR_new_label(ctx);
MIR_label_t slow = MIR_new_label(ctx);
bool has_fast_path = mir_emit_get_field_ic_fastpath(
ctx, jit_func, func, bc_off, ic_idx, atom, obj, dst, slow, r_ic_epoch_val);
if (has_fast_path) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, no_err)));
MIR_append_insn(ctx, jit_func, slow);
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, gf_proto),
MIR_new_ref_op(ctx, imp_get_field),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)atom->len),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_int_op(ctx, (int64_t)bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, dst),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, dst)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, dst)));
}
MIR_append_insn(ctx, jit_func, no_err);
if (vs.known_func && vs.method_ic) {
jit_method_ic_info_t mi = {0};
if (jit_ic_try_resolve_method(func, ic_idx, atom, &mi)) {
vs.known_func[vs.sp - 1] = mi.callee;
vs.method_ic[vs.sp - 1] = mi;
}
}
break;
}
case OP_GET_FIELD2: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)func->atom_count) { ok = false; break; }
sv_atom_t *atom = &func->atoms[idx];
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t obj = vstack_top(&vs);
MIR_reg_t dst = vstack_push(&vs);
uint16_t ic_idx = sv_get_u16(ip + 5);
MIR_label_t no_err = MIR_new_label(ctx);
MIR_label_t slow = MIR_new_label(ctx);
bool has_fast_path = mir_emit_get_field_ic_fastpath(
ctx, jit_func, func, bc_off, ic_idx, atom, obj, dst, slow, r_ic_epoch_val);
if (has_fast_path) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, no_err)));
MIR_append_insn(ctx, jit_func, slow);
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, gf_proto),
MIR_new_ref_op(ctx, imp_get_field),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)atom->len),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_int_op(ctx, (int64_t)bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, dst),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, dst)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, dst)));
}
MIR_append_insn(ctx, jit_func, no_err);
if (vs.known_func && vs.method_ic) {
jit_method_ic_info_t mi = {0};
if (jit_ic_try_resolve_method(func, ic_idx, atom, &mi)) {
vs.known_func[vs.sp - 1] = mi.callee;
vs.method_ic[vs.sp - 1] = mi;
}
}
break;
}
case OP_PUT_FIELD: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)func->atom_count) { ok = false; break; }
sv_atom_t *atom = &func->atoms[idx];
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t val = vstack_pop(&vs);
MIR_reg_t obj = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, put_field_proto),
MIR_new_ref_op(ctx, imp_put_field),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj),
MIR_new_reg_op(ctx, val),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)atom->len)));
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_err_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_err_tmp)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_DEFINE_FIELD: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)func->atom_count) { ok = false; break; }
sv_atom_t *atom = &func->atoms[idx];
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t val = vstack_pop(&vs);
MIR_reg_t obj = vstack_top(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 8,
MIR_new_ref_op(ctx, define_field_proto),
MIR_new_ref_op(ctx, imp_define_field),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj),
MIR_new_reg_op(ctx, val),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)atom->len)));
break;
}
case OP_DEFINE_METHOD_COMP: {
uint8_t flags = sv_get_u8(ip + 1);
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 3, ctx, jit_func, r_d_slot);
MIR_reg_t fn_val = vstack_pop(&vs);
MIR_reg_t key = vstack_pop(&vs);
MIR_reg_t obj = vstack_top(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 7,
MIR_new_ref_op(ctx, define_method_comp_proto),
MIR_new_ref_op(ctx, imp_define_method_comp),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj),
MIR_new_reg_op(ctx, key),
MIR_new_reg_op(ctx, fn_val),
MIR_new_int_op(ctx, (int64_t)flags)));
break;
}
case OP_GET_ELEM: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t key = vstack_pop(&vs);
MIR_reg_t obj = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, ge_proto),
MIR_new_ref_op(ctx, imp_get_elem),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj),
MIR_new_reg_op(ctx, key),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_int_op(ctx, (int64_t)bc_off)));
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, dst),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, dst)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, dst)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_GET_ELEM2: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t key = vstack_pop(&vs);
MIR_reg_t obj = vstack_top(&vs);
MIR_reg_t dst = vstack_push(&vs);
mir_call_helper2(ctx, jit_func, dst,
helper2_proto, imp_get_elem2,
r_vm, r_js, obj, key);
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, dst),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, dst)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, dst)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_PUT_ELEM: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 3, ctx, jit_func, r_d_slot);
MIR_reg_t val = vstack_pop(&vs);
MIR_reg_t key = vstack_pop(&vs);
MIR_reg_t obj = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 8,
MIR_new_ref_op(ctx, put_elem_proto),
MIR_new_ref_op(ctx, imp_put_elem),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj),
MIR_new_reg_op(ctx, key),
MIR_new_reg_op(ctx, val)));
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_err_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_err_tmp)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_FOR_OF:
case OP_DESTRUCTURE_INIT: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t iterable = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 7,
MIR_new_ref_op(ctx, for_of_proto),
MIR_new_ref_op(ctx, imp_for_of),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, iterable),
MIR_new_reg_op(ctx, r_args_buf)));
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_err_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_err_tmp)));
}
MIR_append_insn(ctx, jit_func, no_err);
for (int i = 0; i < 3; i++) {
MIR_reg_t dst = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((vs.sp - 1) * (int)sizeof(ant_value_t)), r_iter_roots, 0, 1),
MIR_new_reg_op(ctx, dst)));
}
break;
}
case OP_DESTRUCTURE_NEXT: {
int iter_base = vs.sp - 3;
for (int i = 0; i < 3; i++) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((iter_base + i) * (int)sizeof(ant_value_t)), r_iter_roots, 0, 1)));
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 6,
MIR_new_ref_op(ctx, destructure_next_proto),
MIR_new_ref_op(ctx, imp_dnext),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_args_buf)));
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_err_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_err_tmp)));
}
MIR_append_insn(ctx, jit_func, no_err);
vstack_pop(&vs);
vstack_pop(&vs);
vstack_pop(&vs);
for (int i = 0; i < 4; i++) {
MIR_reg_t dst = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, dst),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1)));
if (i < 3) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((vs.sp - 1) * (int)sizeof(ant_value_t)), r_iter_roots, 0, 1),
MIR_new_reg_op(ctx, dst)));
}
}
break;
}
case OP_DESTRUCTURE_CLOSE: {
int iter_base = vs.sp - 3;
for (int i = 0; i < 3; i++) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((iter_base + i) * (int)sizeof(ant_value_t)), r_iter_roots, 0, 1)));
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 5,
MIR_new_ref_op(ctx, destructure_close_proto),
MIR_new_ref_op(ctx, imp_dclose),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_args_buf)));
vstack_pop(&vs);
vstack_pop(&vs);
vstack_pop(&vs);
break;
}
case OP_PUT_GLOBAL: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)func->atom_count) { ok = false; break; }
sv_atom_t *atom = &func->atoms[idx];
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t val = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, put_global_proto),
MIR_new_ref_op(ctx, imp_put_global),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, val),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)atom->len),
MIR_new_int_op(ctx, func->is_strict ? 1 : 0)));
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_err_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_err_tmp)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_OBJECT: {
MIR_reg_t dst = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 5,
MIR_new_ref_op(ctx, object_proto),
MIR_new_ref_op(ctx, imp_object),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js)));
break;
}
case OP_ARRAY: {
uint16_t n = sv_get_u16(ip + 1);
if (vs.sp < (int)n) { ok = false; break; }
for (int i = 0; i < (int)n; i++)
vstack_ensure_boxed(&vs, vs.sp - 1 - i, ctx, jit_func, r_d_slot);
for (int i = (int)n - 1; i >= 0; i--) {
MIR_reg_t elem = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)),
r_args_buf, 0, 1),
MIR_new_reg_op(ctx, elem)));
}
MIR_reg_t dst = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 7,
MIR_new_ref_op(ctx, array_proto),
MIR_new_ref_op(ctx, imp_array),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_args_buf),
MIR_new_int_op(ctx, (int64_t)n)));
break;
}
case OP_SET_PROTO: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t proto = vstack_pop(&vs);
MIR_reg_t obj = vstack_top(&vs);
mir_call_helper2(ctx, jit_func, r_err_tmp,
helper2_proto, imp_set_proto,
r_vm, r_js, obj, proto);
break;
}
case OP_SWAP: {
if (vs.sp < 2) { ok = false; break; }
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t ra = vs.regs[vs.sp - 2];
MIR_reg_t rb = vs.regs[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, ra)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, ra),
MIR_new_reg_op(ctx, rb)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, rb),
MIR_new_reg_op(ctx, r_tmp)));
break;
}
case OP_ROT3L: {
if (vs.sp < 3) { ok = false; break; }
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 3, ctx, jit_func, r_d_slot);
MIR_reg_t rx = vs.regs[vs.sp - 3];
MIR_reg_t ra = vs.regs[vs.sp - 2];
MIR_reg_t rb = vs.regs[vs.sp - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, rx)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, rx),
MIR_new_reg_op(ctx, ra)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, ra),
MIR_new_reg_op(ctx, rb)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, rb),
MIR_new_reg_op(ctx, r_tmp)));
break;
}
case OP_IN: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
mir_call_helper2(ctx, jit_func, dst,
helper2_proto, imp_in,
r_vm, r_js, rl, rr);
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, dst),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, dst)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, dst)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_INSTANCEOF: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
uint16_t ic_idx = sv_get_u16(ip + 1);
bool has_ic = func->ic_slots && ic_idx < func->ic_count;
MIR_label_t slow = has_ic ? MIR_new_label(ctx) : NULL;
MIR_label_t no_err = MIR_new_label(ctx);
if (has_ic) {
sv_ic_entry_t *ic = &func->ic_slots[ic_idx];
char inst_ic_name[32], inst_ice_name[32];
char inst_rt_name[32], inst_ro_name[32], inst_ica_name[32], inst_lt_name[32];
char inst_lo_name[32], inst_ls_name[32], inst_ics_name[32], inst_ici_name[32];
snprintf(inst_ic_name, sizeof(inst_ic_name), "inst_ic_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(inst_ice_name, sizeof(inst_ice_name), "inst_ice_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(inst_rt_name, sizeof(inst_rt_name), "inst_rt_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(inst_ro_name, sizeof(inst_ro_name), "inst_ro_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(inst_ica_name, sizeof(inst_ica_name), "inst_ica_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(inst_lt_name, sizeof(inst_lt_name), "inst_lt_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(inst_lo_name, sizeof(inst_lo_name), "inst_lo_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(inst_ls_name, sizeof(inst_ls_name), "inst_ls_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(inst_ics_name, sizeof(inst_ics_name), "inst_ics_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(inst_ici_name, sizeof(inst_ici_name), "inst_ici_%d_%u", bc_off, (unsigned)ic_idx);
MIR_reg_t r_ic = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, inst_ic_name);
MIR_reg_t r_ic_epoch = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, inst_ice_name);
MIR_reg_t r_rhs_tag = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, inst_rt_name);
MIR_reg_t r_rhs_obj = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, inst_ro_name);
MIR_reg_t r_ic_aux = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, inst_ica_name);
MIR_reg_t r_lhs_tag = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, inst_lt_name);
MIR_reg_t r_lhs_obj = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, inst_lo_name);
MIR_reg_t r_lhs_shape = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, inst_ls_name);
MIR_reg_t r_ic_shape = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, inst_ics_name);
MIR_reg_t r_ic_idx_val = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, inst_ici_name);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)ic)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_epoch),
MIR_new_mem_op(ctx, MIR_T_I32,
(MIR_disp_t)offsetof(sv_ic_entry_t, epoch), r_ic, 0, 1)));
{
char ice_cur_name[40];
snprintf(ice_cur_name, sizeof(ice_cur_name), "inst_ce_%d_%u", bc_off, (unsigned)ic_idx);
MIR_reg_t r_cur_ep = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, ice_cur_name);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_cur_ep),
MIR_new_mem_op(ctx, MIR_T_U32, 0, r_ic_epoch_val, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_ic_epoch),
MIR_new_reg_op(ctx, r_cur_ep)));
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_rhs_tag),
MIR_new_reg_op(ctx, rr),
MIR_new_uint_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_rhs_tag),
MIR_new_uint_op(ctx, NANBOX_TFUNC_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, r_rhs_obj),
MIR_new_reg_op(ctx, rr),
MIR_new_uint_op(ctx, NANBOX_DATA_MASK)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_aux),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_aux), r_ic, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_rhs_obj),
MIR_new_reg_op(ctx, r_ic_aux)));
mir_emit_value_to_objptr_or_jmp(
ctx, jit_func, rl, r_lhs_obj, r_lhs_tag, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_lhs_shape),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(ant_object_t, shape), r_lhs_obj, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_shape),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_shape), r_ic, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_lhs_shape),
MIR_new_reg_op(ctx, r_ic_shape)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_idx_val),
MIR_new_mem_op(ctx, MIR_T_I32,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_index), r_ic, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, dst),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_ic_idx_val)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, no_err)));
MIR_append_insn(ctx, jit_func, slow);
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, inst_proto),
MIR_new_ref_op(ctx, imp_instanceof),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, rl),
MIR_new_reg_op(ctx, rr),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_int_op(ctx, (int64_t)bc_off)));
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, dst),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, dst)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, dst)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_CALL_IS_PROTO: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 3, ctx, jit_func, r_d_slot);
MIR_reg_t arg = vstack_pop(&vs);
MIR_reg_t fn = vstack_pop(&vs);
MIR_reg_t this_obj = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
uint16_t ic_idx = sv_get_u16(ip + 1);
bool has_ic = func->ic_slots && ic_idx < func->ic_count;
MIR_label_t slow = has_ic ? MIR_new_label(ctx) : NULL;
MIR_label_t no_err = MIR_new_label(ctx);
if (has_ic) {
sv_ic_entry_t *ic = &func->ic_slots[ic_idx];
char cip_bi_name[32], cip_ic_name[32], cip_ice_name[32];
char cip_pt_name[32], cip_pp_name[32], cip_ot_name[32];
char cip_op_name[32], cip_ich_name[32], cip_ics_name[32], cip_ici_name[32];
snprintf(cip_bi_name, sizeof(cip_bi_name), "cip_bi_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(cip_ic_name, sizeof(cip_ic_name), "cip_ic_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(cip_ice_name, sizeof(cip_ice_name), "cip_ice_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(cip_pt_name, sizeof(cip_pt_name), "cip_pt_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(cip_pp_name, sizeof(cip_pp_name), "cip_pp_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(cip_ot_name, sizeof(cip_ot_name), "cip_ot_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(cip_op_name, sizeof(cip_op_name), "cip_op_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(cip_ich_name, sizeof(cip_ich_name), "cip_ich_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(cip_ics_name, sizeof(cip_ics_name), "cip_ics_%d_%u", bc_off, (unsigned)ic_idx);
snprintf(cip_ici_name, sizeof(cip_ici_name), "cip_ici_%d_%u", bc_off, (unsigned)ic_idx);
MIR_reg_t r_builtin = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_bi_name);
MIR_reg_t r_ic = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_ic_name);
MIR_reg_t r_ic_epoch = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_ice_name);
MIR_reg_t r_proto_tag = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_pt_name);
MIR_reg_t r_proto_ptr = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_pp_name);
MIR_reg_t r_obj_tag = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_ot_name);
MIR_reg_t r_obj_ptr = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_op_name);
MIR_reg_t r_ic_holder = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_ich_name);
MIR_reg_t r_ic_shape = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_ics_name);
MIR_reg_t r_ic_idx_val = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_ici_name);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_builtin),
MIR_new_uint_op(ctx, (uint64_t)js_mkfun(builtin_object_isPrototypeOf))));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, fn),
MIR_new_reg_op(ctx, r_builtin)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)ic)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_epoch),
MIR_new_mem_op(ctx, MIR_T_I32,
(MIR_disp_t)offsetof(sv_ic_entry_t, epoch), r_ic, 0, 1)));
{
char cip_ce_name[40];
snprintf(cip_ce_name, sizeof(cip_ce_name), "cip_ce_%d_%u", bc_off, (unsigned)ic_idx);
MIR_reg_t r_cur_ep = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, cip_ce_name);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_cur_ep),
MIR_new_mem_op(ctx, MIR_T_U32, 0, r_ic_epoch_val, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_ic_epoch),
MIR_new_reg_op(ctx, r_cur_ep)));
}
mir_emit_value_to_objptr_or_jmp(
ctx, jit_func, this_obj, r_proto_ptr, r_proto_tag, slow);
mir_emit_value_to_objptr_or_jmp(
ctx, jit_func, arg, r_obj_ptr, r_obj_tag, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_holder),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_holder), r_ic, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_proto_ptr),
MIR_new_reg_op(ctx, r_ic_holder)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_shape),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_shape), r_ic, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, slow),
MIR_new_reg_op(ctx, r_obj_ptr),
MIR_new_reg_op(ctx, r_ic_shape)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_ic_idx_val),
MIR_new_mem_op(ctx, MIR_T_I32,
(MIR_disp_t)offsetof(sv_ic_entry_t, cached_index), r_ic, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, dst),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_ic_idx_val)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, no_err)));
MIR_append_insn(ctx, jit_func, slow);
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, call_is_proto),
MIR_new_ref_op(ctx, imp_call_is_proto),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, this_obj),
MIR_new_reg_op(ctx, fn),
MIR_new_reg_op(ctx, arg),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_int_op(ctx, (int64_t)bc_off)));
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, dst),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, dst)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, dst)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_GET_LENGTH: {
MIR_reg_t obj = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
char gl_tag_name[32], gl_ptr_name[32], gl_len_name[32], gl_dbl_name[32];
snprintf(gl_tag_name, sizeof(gl_tag_name), "gl_tag_%d", bc_off);
snprintf(gl_ptr_name, sizeof(gl_ptr_name), "gl_ptr_%d", bc_off);
snprintf(gl_len_name, sizeof(gl_len_name), "gl_len_%d", bc_off);
snprintf(gl_dbl_name, sizeof(gl_dbl_name), "gl_dbl_%d", bc_off);
MIR_reg_t gl_tag = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, gl_tag_name);
MIR_reg_t gl_ptr = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, gl_ptr_name);
MIR_reg_t gl_len = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, gl_len_name);
MIR_reg_t gl_dbl = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, gl_dbl_name);
MIR_label_t gl_slow = MIR_new_label(ctx);
MIR_label_t gl_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, gl_tag),
MIR_new_reg_op(ctx, obj),
MIR_new_uint_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, gl_slow),
MIR_new_reg_op(ctx, gl_tag),
MIR_new_uint_op(ctx, NANBOX_TARR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, gl_ptr),
MIR_new_reg_op(ctx, obj),
MIR_new_uint_op(ctx, NANBOX_DATA_MASK)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, gl_len),
MIR_new_mem_op(ctx, MIR_T_U32,
(MIR_disp_t)offsetof(ant_object_t, u.array.len),
gl_ptr, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_UI2D,
MIR_new_reg_op(ctx, gl_dbl),
MIR_new_reg_op(ctx, gl_len)));
mir_d_to_i64(ctx, jit_func, dst, gl_dbl, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, gl_done)));
MIR_append_insn(ctx, jit_func, gl_slow);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 6,
MIR_new_ref_op(ctx, helper1_proto),
MIR_new_ref_op(ctx, imp_get_length),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, obj)));
MIR_append_insn(ctx, jit_func, gl_done);
break;
}
case OP_SEQ: {
bool r_const = vs.has_const && vs.has_const[vs.sp - 1];
bool l_const = vs.has_const && vs.has_const[vs.sp - 2];
uint64_t cval = r_const ? vs.known_const[vs.sp - 1]
: l_const ? vs.known_const[vs.sp - 2] : 0;
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
if (r_const || l_const) {
MIR_reg_t other = r_const ? rl : rr;
MIR_label_t is_true = MIR_new_label(ctx);
MIR_label_t is_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_true),
MIR_new_reg_op(ctx, other),
MIR_new_uint_op(ctx, cval)));
mir_load_imm(ctx, jit_func, dst, js_false);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, is_done)));
MIR_append_insn(ctx, jit_func, is_true);
mir_load_imm(ctx, jit_func, dst, js_true);
MIR_append_insn(ctx, jit_func, is_done);
} else {
mir_call_helper2(ctx, jit_func, dst,
helper2_proto, imp_seq,
r_vm, r_js, rl, rr);
}
break;
}
case OP_EQ: {
bool r_const = vs.has_const && vs.has_const[vs.sp - 1];
bool l_const = vs.has_const && vs.has_const[vs.sp - 2];
uint64_t cval = r_const ? vs.known_const[vs.sp - 1]
: l_const ? vs.known_const[vs.sp - 2] : 0;
bool is_nullish = (r_const || l_const) &&
(cval == mkval(T_NULL, 0) || cval == mkval(T_UNDEF, 0));
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
if (is_nullish) {
MIR_reg_t other = r_const ? rl : rr;
MIR_label_t is_true = MIR_new_label(ctx);
MIR_label_t is_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_true),
MIR_new_reg_op(ctx, other),
MIR_new_uint_op(ctx, mkval(T_NULL, 0))));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_true),
MIR_new_reg_op(ctx, other),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0))));
mir_load_imm(ctx, jit_func, dst, js_false);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, is_done)));
MIR_append_insn(ctx, jit_func, is_true);
mir_load_imm(ctx, jit_func, dst, js_true);
MIR_append_insn(ctx, jit_func, is_done);
} else {
mir_call_helper2(ctx, jit_func, dst,
helper2_proto, imp_eq,
r_vm, r_js, rl, rr);
}
break;
}
case OP_NE: {
bool r_const = vs.has_const && vs.has_const[vs.sp - 1];
bool l_const = vs.has_const && vs.has_const[vs.sp - 2];
uint64_t cval = r_const ? vs.known_const[vs.sp - 1]
: l_const ? vs.known_const[vs.sp - 2] : 0;
bool is_nullish = (r_const || l_const) &&
(cval == mkval(T_NULL, 0) || cval == mkval(T_UNDEF, 0));
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
if (is_nullish) {
MIR_reg_t other = r_const ? rl : rr;
MIR_label_t is_false = MIR_new_label(ctx);
MIR_label_t is_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_false),
MIR_new_reg_op(ctx, other),
MIR_new_uint_op(ctx, mkval(T_NULL, 0))));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_false),
MIR_new_reg_op(ctx, other),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0))));
mir_load_imm(ctx, jit_func, dst, js_true);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, is_done)));
MIR_append_insn(ctx, jit_func, is_false);
mir_load_imm(ctx, jit_func, dst, js_false);
MIR_append_insn(ctx, jit_func, is_done);
} else {
mir_call_helper2(ctx, jit_func, dst,
helper2_proto, imp_ne,
r_vm, r_js, rl, rr);
}
break;
}
case OP_SNE: {
bool r_const = vs.has_const && vs.has_const[vs.sp - 1];
bool l_const = vs.has_const && vs.has_const[vs.sp - 2];
uint64_t cval = r_const ? vs.known_const[vs.sp - 1]
: l_const ? vs.known_const[vs.sp - 2] : 0;
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
if (r_const || l_const) {
MIR_reg_t other = r_const ? rl : rr;
MIR_label_t is_false = MIR_new_label(ctx);
MIR_label_t is_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, is_false),
MIR_new_reg_op(ctx, other),
MIR_new_uint_op(ctx, cval)));
mir_load_imm(ctx, jit_func, dst, js_true);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, is_done)));
MIR_append_insn(ctx, jit_func, is_false);
mir_load_imm(ctx, jit_func, dst, js_false);
MIR_append_insn(ctx, jit_func, is_done);
} else {
mir_call_helper2(ctx, jit_func, dst,
helper2_proto, imp_sne,
r_vm, r_js, rl, rr);
}
break;
}
case OP_GT: {
uint8_t fb = func->type_feedback ? func->type_feedback[bc_off] : 0;
bool fb_num_only = fb && !(fb & ~SV_TFB_NUM);
bool fb_never_num = fb && !(fb & SV_TFB_NUM);
bool l_is_num = vs.slot_type && vs.slot_type[vs.sp - 2] == SLOT_NUM;
bool r_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t rd = vstack_push(&vs);
if (fb_never_num) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_gt,
r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
} else if (fb_num_only && l_is_num && r_is_num) {
MIR_reg_t fd_l = vs.d_regs[vs.sp - 1];
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DGT,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd_l),
MIR_new_reg_op(ctx, fd_r)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
} else if (fb_num_only && (l_is_num || r_is_num)) {
MIR_label_t bail_direct = MIR_new_label(ctx);
MIR_reg_t boxed_reg = l_is_num ? rr : rl;
mir_emit_is_num_guard(ctx, jit_func, r_bool, boxed_reg, bail_direct);
int boxed_idx = l_is_num ? (int)vs.sp : (int)(vs.sp - 1);
mir_i64_to_d(ctx, jit_func, vs.d_regs[boxed_idx],
vs.regs[boxed_idx], r_d_slot);
MIR_reg_t fd_l = vs.d_regs[vs.sp - 1];
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DGT,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd_l),
MIR_new_reg_op(ctx, fd_r)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else {
MIR_label_t slow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
int gtn = arith_n++;
char d1[32], d2[32];
snprintf(d1, sizeof(d1), "gt_d1_%d", gtn);
snprintf(d2, sizeof(d2), "gt_d2_%d", gtn);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DGT,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, jit_func, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_gt, r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, done);
}
break;
}
case OP_GE: {
uint8_t fb = func->type_feedback ? func->type_feedback[bc_off] : 0;
bool fb_num_only = fb && !(fb & ~SV_TFB_NUM);
bool fb_never_num = fb && !(fb & SV_TFB_NUM);
bool l_is_num = vs.slot_type && vs.slot_type[vs.sp - 2] == SLOT_NUM;
bool r_is_num = vs.slot_type && vs.slot_type[vs.sp - 1] == SLOT_NUM;
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t rd = vstack_push(&vs);
if (fb_never_num) {
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_ge,
r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
} else if (fb_num_only && l_is_num && r_is_num) {
MIR_reg_t fd_l = vs.d_regs[vs.sp - 1];
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DGE,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd_l),
MIR_new_reg_op(ctx, fd_r)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
} else if (fb_num_only && (l_is_num || r_is_num)) {
MIR_label_t bail_direct = MIR_new_label(ctx);
MIR_reg_t boxed_reg = l_is_num ? rr : rl;
mir_emit_is_num_guard(ctx, jit_func, r_bool, boxed_reg, bail_direct);
int boxed_idx = l_is_num ? (int)vs.sp : (int)(vs.sp - 1);
mir_i64_to_d(ctx, jit_func, vs.d_regs[boxed_idx],
vs.regs[boxed_idx], r_d_slot);
MIR_reg_t fd_l = vs.d_regs[vs.sp - 1];
MIR_reg_t fd_r = vs.d_regs[vs.sp];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DGE,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd_l),
MIR_new_reg_op(ctx, fd_r)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
MIR_label_t skip_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, skip_bail)));
MIR_append_insn(ctx, jit_func, bail_direct);
int pre_op_sp = vs.sp + 1;
for (int i = 0; i < pre_op_sp; i++) {
if (vs.slot_type && vs.slot_type[i] == SLOT_NUM)
mir_d_to_i64(ctx, jit_func, vs.regs[i], vs.d_regs[i], r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
}
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, pre_op_sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, skip_bail);
} else {
MIR_label_t slow = MIR_new_label(ctx);
MIR_label_t done = MIR_new_label(ctx);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rl, slow);
mir_emit_is_num_guard(ctx, jit_func, r_bool, rr, slow);
int gen = arith_n++;
char d1[32], d2[32];
snprintf(d1, sizeof(d1), "ge_d1_%d", gen);
snprintf(d2, sizeof(d2), "ge_d2_%d", gen);
MIR_reg_t fd1 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d1);
MIR_reg_t fd2 = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_D, d2);
mir_i64_to_d(ctx, jit_func, fd1, rl, r_d_slot);
mir_i64_to_d(ctx, jit_func, fd2, rr, r_d_slot);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_DGE,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, fd1),
MIR_new_reg_op(ctx, fd2)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_tmp),
MIR_new_reg_op(ctx, r_bool)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_OR,
MIR_new_reg_op(ctx, rd),
MIR_new_uint_op(ctx, js_false),
MIR_new_reg_op(ctx, r_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, done)));
MIR_append_insn(ctx, jit_func, slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp_ge, r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_append_insn(ctx, jit_func, done);
}
break;
}
case OP_BAND: case OP_BOR: case OP_BXOR:
case OP_SHL: case OP_SHR: case OP_USHR: {
int rr_idx = vs.sp - 1;
int rl_idx = vs.sp - 2;
vstack_ensure_boxed(&vs, rl_idx, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, rr_idx, ctx, jit_func, r_d_slot);
MIR_reg_t rr = vstack_pop(&vs);
MIR_reg_t rl = vstack_pop(&vs);
MIR_reg_t rd = vstack_push(&vs);
MIR_item_t imp;
switch (op) {
case OP_BAND: imp = imp_band; break;
case OP_BOR: imp = imp_bor; break;
case OP_BXOR: imp = imp_bxor; break;
case OP_SHL: imp = imp_shl; break;
case OP_SHR: imp = imp_shr; break;
default: imp = imp_ushr; break;
}
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_val),
MIR_new_reg_op(ctx, rl)));
mir_call_helper2(ctx, jit_func, rd,
helper2_proto, imp, r_vm, r_js, rl, rr);
mir_emit_bailout_check(ctx, jit_func, rd,
r_bailout_val, r_bailout_off, bc_off,
r_bailout_sp, vs.sp + 1, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
break;
}
case OP_BNOT: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t rs = vstack_top(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 6,
MIR_new_ref_op(ctx, helper1_proto),
MIR_new_ref_op(ctx, imp_bnot),
MIR_new_reg_op(ctx, rs),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, rs)));
MIR_label_t no_bail = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_bail),
MIR_new_reg_op(ctx, rs),
MIR_new_uint_op(ctx, (uint64_t)SV_JIT_BAILOUT)));
for (int i = 0; i < vs.sp; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, vs.sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
MIR_append_insn(ctx, jit_func, no_bail);
break;
}
case OP_NOT: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t rs = vstack_top(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 6,
MIR_new_ref_op(ctx, helper1_proto),
MIR_new_ref_op(ctx, imp_not),
MIR_new_reg_op(ctx, rs),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, rs)));
break;
}
case OP_TYPEOF: {
MIR_reg_t rs = vstack_top(&vs);
for (int i = 0; i < vs.sp; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1),
MIR_new_reg_op(ctx, vs.regs[i])));
for (int i = 0; i < n_locals; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[i])));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_off),
MIR_new_int_op(ctx, bc_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_int_op(ctx, vs.sp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, bailout_tramp)));
(void)rs; (void)imp_typeof;
break;
}
case OP_VOID: {
MIR_reg_t rs = vstack_top(&vs);
mir_load_imm(ctx, jit_func, rs, mkval(T_UNDEF, 0));
if (vs.has_const) {
vs.has_const[vs.sp - 1] = true;
vs.known_const[vs.sp - 1] = mkval(T_UNDEF, 0);
}
break;
}
case OP_DELETE: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
vstack_ensure_boxed(&vs, vs.sp - 2, ctx, jit_func, r_d_slot);
MIR_reg_t rk = vstack_pop(&vs);
MIR_reg_t ro = vstack_pop(&vs);
MIR_reg_t dst = vstack_push(&vs);
mir_call_helper2(ctx, jit_func, dst,
helper2_proto, imp_delete,
r_vm, r_js, ro, rk);
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, dst),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, dst)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, dst)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_NEW: {
uint16_t new_argc = sv_get_u16(ip + 1);
if (new_argc > 16 || vs.sp < (int)new_argc + 2) { ok = false; break; }
for (int i = 0; i < (int)new_argc + 2; i++)
vstack_ensure_boxed(&vs, vs.sp - 1 - i, ctx, jit_func, r_d_slot);
for (int i = (int)new_argc - 1; i >= 0; i--) {
MIR_reg_t areg = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)),
r_args_buf, 0, 1),
MIR_new_reg_op(ctx, areg)));
}
MIR_reg_t r_ctor_target = vstack_pop(&vs);
MIR_reg_t r_new_func = vstack_pop(&vs);
MIR_reg_t r_new_res = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, new_proto),
MIR_new_ref_op(ctx, imp_new),
MIR_new_reg_op(ctx, r_new_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_new_func),
MIR_new_reg_op(ctx, r_ctor_target),
MIR_new_reg_op(ctx, r_args_buf),
MIR_new_int_op(ctx, (int64_t)new_argc)));
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
}
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_new_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_new_res)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_new_res)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_CALL_ARRAY_INCLUDES: {
vstack_flush_to_boxed(&vs, ctx, jit_func, r_d_slot);
uint16_t call_argc = sv_get_u16(ip + 1);
if (call_argc > 16 || vs.sp < (int)call_argc + 2) { ok = false; break; }
MIR_reg_t r_arg_arr = r_args_buf;
for (int i = (int)call_argc - 1; i >= 0; i--) {
MIR_reg_t areg = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)),
r_arg_arr, 0, 1),
MIR_new_reg_op(ctx, areg)));
}
MIR_reg_t r_call_func = vstack_pop(&vs);
MIR_reg_t r_call_this = vstack_pop(&vs);
MIR_reg_t r_call_res = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, call_proto),
MIR_new_ref_op(ctx, imp_call_array_includes),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_call_func),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)call_argc)));
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
}
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_call_res)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_call_res)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_TAIL_CALL_METHOD:
case OP_CALL_METHOD: {
vstack_flush_to_boxed(&vs, ctx, jit_func, r_d_slot);
bool is_tail = (op == OP_TAIL_CALL_METHOD);
uint16_t call_argc = sv_get_u16(ip + 1);
if (call_argc > 16 || vs.sp < (int)call_argc + 2) { ok = false; break; }
if (!is_tail && vs.method_ic) {
int callee_slot = vs.sp - (int)call_argc - 1;
jit_method_ic_info_t mi = vs.method_ic[callee_slot];
sv_func_t *inline_callee = mi.valid ? mi.callee : NULL;
if (inline_callee && inline_callee != func &&
inline_depth < JIT_INLINE_MAX_DEPTH &&
inline_budget >= inline_callee->code_len &&
jit_inlineable(inline_callee) &&
jit_inline_body_feasible(inline_callee)) {
int cn = call_n++;
MIR_reg_t inl_arg_regs[call_argc > 0 ? call_argc : 1];
for (int i = (int)call_argc - 1; i >= 0; i--)
inl_arg_regs[i] = vstack_pop(&vs);
MIR_reg_t r_call_func = vstack_pop(&vs);
MIR_reg_t r_call_this = vstack_pop(&vs);
MIR_reg_t r_call_res = vstack_push(&vs);
MIR_label_t inl_slow = MIR_new_label(ctx);
MIR_label_t inl_join = MIR_new_label(ctx);
char rn_cl[32], rn_fn[32], rn_sup[32], rn_this[32];
char rn_nt[32], rn_flags[32], rn_bound[32], rn_recv_obj[32];
char rn_recv_shape[32], rn_recv_tag[32];
snprintf(rn_cl, sizeof(rn_cl), "minl%d_cl", cn);
snprintf(rn_fn, sizeof(rn_fn), "minl%d_fn", cn);
snprintf(rn_sup, sizeof(rn_sup), "minl%d_sup", cn);
snprintf(rn_this, sizeof(rn_this), "minl%d_this", cn);
snprintf(rn_nt, sizeof(rn_nt), "minl%d_nt", cn);
snprintf(rn_flags, sizeof(rn_flags), "minl%d_flags", cn);
snprintf(rn_bound, sizeof(rn_bound), "minl%d_bound", cn);
snprintf(rn_recv_obj, sizeof(rn_recv_obj), "minl%d_recv_obj", cn);
snprintf(rn_recv_shape, sizeof(rn_recv_shape), "minl%d_recv_shape_reg", cn);
snprintf(rn_recv_tag, sizeof(rn_recv_tag), "minl%d_recv_tag", cn);
MIR_reg_t r_inl_cl = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_cl);
MIR_reg_t r_inl_fn = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_fn);
MIR_reg_t r_inl_super = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rn_sup);
MIR_reg_t r_inl_this = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rn_this);
MIR_reg_t r_inl_new_target = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rn_nt);
MIR_reg_t r_inl_flags = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_flags);
MIR_reg_t r_inl_bound = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rn_bound);
MIR_reg_t r_recv_obj = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_recv_obj);
MIR_reg_t r_recv_shape = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_recv_shape);
MIR_reg_t r_recv_tag = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_recv_tag);
mir_emit_method_receiver_shape_guard(
ctx, jit_func, &mi, r_call_this, r_recv_obj, r_recv_shape,
r_recv_tag, r_ic_epoch_val, inl_slow, cn);
mir_emit_get_closure(ctx, jit_func, r_inl_cl, r_call_func,
r_bool, inl_slow);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_inl_fn),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_closure_t, func),
r_inl_cl, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, inl_slow),
MIR_new_reg_op(ctx, r_inl_fn),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)inline_callee)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_inl_flags),
MIR_new_mem_op(ctx, MIR_T_U32,
(MIR_disp_t)offsetof(sv_closure_t, call_flags),
r_inl_cl, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_AND,
MIR_new_reg_op(ctx, r_inl_flags),
MIR_new_reg_op(ctx, r_inl_flags),
MIR_new_uint_op(ctx, SV_CALL_HAS_BOUND_ARGS | SV_CALL_IS_ARROW)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, inl_slow),
MIR_new_reg_op(ctx, r_inl_flags),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_inl_bound),
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)offsetof(sv_closure_t, bound_this),
r_inl_cl, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, inl_slow),
MIR_new_reg_op(ctx, r_inl_bound),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0))));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_inl_super),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_closure_t, super_val),
r_inl_cl, 0, 1)));
mir_load_imm(ctx, jit_func, r_inl_new_target, mkval(T_UNDEF, 0));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_inl_this),
MIR_new_reg_op(ctx, r_call_this)));
bool inlined = jit_emit_inline_body(
ctx, jit_func, inline_callee,
inl_arg_regs, (int)call_argc,
r_call_res, inl_slow, inl_join,
r_bool, &r_d_slot, cn,
r_inl_cl, r_inl_this, r_inl_new_target, r_inl_super,
mi.receiver_shape, r_recv_obj, r_recv_shape, r_ic_epoch_val,
r_vm, r_js,
helper2_proto, imp_seq, imp_sne, imp_eq, imp_ne,
gf_proto, imp_get_field,
put_field_proto, imp_put_field,
gg_proto, imp_gg,
special_obj_proto, imp_special_obj);
if (!inlined) { ok = false; break; }
inline_budget -= inline_callee->code_len;
MIR_append_insn(ctx, jit_func, inl_slow);
for (int i = 0; i < (int)call_argc; i++)
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)),
r_args_buf, 0, 1),
MIR_new_reg_op(ctx, inl_arg_regs[i])));
MIR_label_t slow_super = MIR_new_label(ctx);
MIR_label_t slow_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, slow_super),
MIR_new_reg_op(ctx, r_call_func),
MIR_new_reg_op(ctx, r_super_val)));
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, call_proto),
MIR_new_ref_op(ctx, imp_call),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_call_func),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_reg_op(ctx, r_args_buf),
MIR_new_int_op(ctx, (int64_t)call_argc)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, slow_done)));
MIR_append_insn(ctx, jit_func, slow_super);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64, 0, r_call_out_this, 0, 1),
MIR_new_reg_op(ctx, r_call_this)));
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 12,
MIR_new_ref_op(ctx, call_method_proto),
MIR_new_ref_op(ctx, imp_call_method),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_call_func),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_reg_op(ctx, r_args_buf),
MIR_new_int_op(ctx, (int64_t)call_argc),
MIR_new_reg_op(ctx, r_super_val),
MIR_new_reg_op(ctx, r_new_target),
MIR_new_reg_op(ctx, r_call_out_this)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_this_curr),
MIR_new_mem_op(ctx, MIR_T_I64, 0, r_call_out_this, 0, 1)));
MIR_append_insn(ctx, jit_func, slow_done);
MIR_append_insn(ctx, jit_func, inl_join);
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
}
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_call_res)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
MIR_append_insn(ctx, jit_func, no_err);
} else {
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_call_res)));
MIR_append_insn(ctx, jit_func, no_err);
}
break;
}
}
int cn = call_n++;
char rn_arr[32], rn_ccl[32], rn_cfn[32], rn_jptr[32], rn_sup[32];
snprintf(rn_arr, sizeof(rn_arr), "cm_arr%d", cn);
snprintf(rn_ccl, sizeof(rn_ccl), "cm_cl%d", cn);
snprintf(rn_cfn, sizeof(rn_cfn), "cm_fn%d", cn);
snprintf(rn_jptr, sizeof(rn_jptr), "cm_jptr%d", cn);
snprintf(rn_sup, sizeof(rn_sup), "cm_sup%d", cn);
MIR_reg_t r_arg_arr = r_args_buf;
for (int i = (int)call_argc - 1; i >= 0; i--) {
MIR_reg_t areg = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)),
r_arg_arr, 0, 1),
MIR_new_reg_op(ctx, areg)));
}
MIR_reg_t r_call_func = vstack_pop(&vs);
MIR_reg_t r_call_this = vstack_pop(&vs);
MIR_reg_t r_call_res = vstack_push(&vs);
MIR_reg_t r_callee_super = MIR_new_func_reg(ctx, jit_func->u.func, MIR_JSVAL, rn_sup);
MIR_label_t lbl_cm_self = MIR_new_label(ctx);
MIR_label_t lbl_cm_super = MIR_new_label(ctx);
MIR_label_t lbl_cm_interp = MIR_new_label(ctx);
MIR_label_t lbl_cm_done = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl_cm_super),
MIR_new_reg_op(ctx, r_call_func),
MIR_new_reg_op(ctx, r_super_val)));
MIR_reg_t r_callee_cl = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_ccl);
mir_emit_get_closure(ctx, jit_func, r_callee_cl, r_call_func,
r_bool, lbl_cm_interp);
MIR_reg_t r_callee_fn = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_cfn);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_callee_fn),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_closure_t, func),
r_callee_cl, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_callee_super),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)offsetof(sv_closure_t, super_val),
r_callee_cl, 0, 1)));
mir_emit_resolve_call_this(ctx, jit_func, r_call_this, r_callee_cl,
r_call_this, r_bool, r_tmp2);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl_cm_interp),
MIR_new_reg_op(ctx, r_callee_fn),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl_cm_self),
MIR_new_reg_op(ctx, r_callee_cl),
MIR_new_reg_op(ctx, r_closure)));
MIR_reg_t r_jit_ptr = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, rn_jptr);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_jit_ptr),
MIR_new_mem_op(ctx, MIR_T_P,
(MIR_disp_t)offsetof(sv_func_t, jit_code),
r_callee_fn, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BEQ,
MIR_new_label_op(ctx, lbl_cm_interp),
MIR_new_reg_op(ctx, r_jit_ptr),
MIR_new_int_op(ctx, 0)));
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, self_proto),
MIR_new_reg_op(ctx, r_jit_ptr),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0)),
MIR_new_reg_op(ctx, r_callee_super),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)call_argc),
MIR_new_reg_op(ctx, r_callee_cl)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_cm_done)));
MIR_append_insn(ctx, jit_func, lbl_cm_self);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, self_proto),
MIR_new_ref_op(ctx, jit_func),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0)),
MIR_new_reg_op(ctx, r_super_val),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)call_argc),
MIR_new_reg_op(ctx, r_closure)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_cm_done)));
MIR_append_insn(ctx, jit_func, lbl_cm_super);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64, 0, r_call_out_this, 0, 1),
MIR_new_reg_op(ctx, r_call_this)));
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 12,
MIR_new_ref_op(ctx, call_method_proto),
MIR_new_ref_op(ctx, imp_call_method),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_call_func),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)call_argc),
MIR_new_reg_op(ctx, r_super_val),
MIR_new_reg_op(ctx, r_new_target),
MIR_new_reg_op(ctx, r_call_out_this)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, r_this_curr),
MIR_new_mem_op(ctx, MIR_T_I64, 0, r_call_out_this, 0, 1)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, lbl_cm_done)));
MIR_append_insn(ctx, jit_func, lbl_cm_interp);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, call_proto),
MIR_new_ref_op(ctx, imp_call),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_call_func),
MIR_new_reg_op(ctx, r_call_this),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)call_argc)));
MIR_append_insn(ctx, jit_func, lbl_cm_done);
if (is_tail && jit_try_depth == 0) {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_call_res)));
} else {
if (has_captures) {
for (int i = 0; i < n_locals; i++)
if (captured_locals[i])
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[i]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
}
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_call_res)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
MIR_append_insn(ctx, jit_func, no_err);
} else {
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_call_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_call_res)));
MIR_append_insn(ctx, jit_func, no_err);
}
if (is_tail) {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_call_res)));
}
}
break;
}
case OP_APPLY: {
vstack_flush_to_boxed(&vs, ctx, jit_func, r_d_slot);
uint16_t apply_argc = sv_get_u16(ip + 1);
if (apply_argc > 16 || vs.sp < (int)apply_argc + 2) { ok = false; break; }
int cn = call_n++;
MIR_reg_t r_arg_arr = r_args_buf;
for (int i = (int)apply_argc - 1; i >= 0; i--) {
MIR_reg_t areg = vstack_pop(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_JSVAL,
(MIR_disp_t)(i * (int)sizeof(ant_value_t)),
r_arg_arr, 0, 1),
MIR_new_reg_op(ctx, areg)));
}
MIR_reg_t r_apply_this = vstack_pop(&vs);
MIR_reg_t r_apply_func = vstack_pop(&vs);
MIR_reg_t r_apply_res = vstack_push(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 9,
MIR_new_ref_op(ctx, call_proto),
MIR_new_ref_op(ctx, imp_apply),
MIR_new_reg_op(ctx, r_apply_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_apply_func),
MIR_new_reg_op(ctx, r_apply_this),
MIR_new_reg_op(ctx, r_arg_arr),
MIR_new_int_op(ctx, (int64_t)apply_argc)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_apply_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_apply_res)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
MIR_append_insn(ctx, jit_func, no_err);
} else {
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_apply_res),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_apply_res)));
MIR_append_insn(ctx, jit_func, no_err);
}
(void)cn;
break;
}
case OP_NOP:
case OP_HALT:
case OP_LINE_NUM:
case OP_COL_NUM:
case OP_LABEL:
break;
case OP_STR_FLUSH_LOCAL: {
uint16_t slot_idx = sv_get_u16(ip + 1);
int pre_op_sp = vs.sp;
if ((int)slot_idx < param_count) {
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, str_flush_local_proto),
MIR_new_ref_op(ctx, imp_str_flush_local),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_reg_op(ctx, r_args),
MIR_new_reg_op(ctx, r_argc),
MIR_new_uint_op(ctx, 0),
MIR_new_int_op(ctx, (int64_t)slot_idx)));
} else {
uint16_t local_idx = (uint16_t)(slot_idx - (uint16_t)param_count);
if (local_idx >= (uint16_t)n_locals) { ok = false; break; }
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)local_idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1),
MIR_new_reg_op(ctx, local_regs[local_idx])));
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 10,
MIR_new_ref_op(ctx, str_flush_local_proto),
MIR_new_ref_op(ctx, imp_str_flush_local),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)func),
MIR_new_uint_op(ctx, 0),
MIR_new_int_op(ctx, (int64_t)param_count),
MIR_new_reg_op(ctx, r_lbuf),
MIR_new_int_op(ctx, (int64_t)slot_idx)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, local_regs[local_idx]),
MIR_new_mem_op(ctx, MIR_T_I64,
(MIR_disp_t)((int)local_idx * (int)sizeof(ant_value_t)), r_lbuf, 0, 1)));
if (known_func_locals) known_func_locals[local_idx] = NULL;
if (known_type_locals) known_type_locals[local_idx] = SV_TI_UNKNOWN;
}
mir_emit_bailout_check(ctx, jit_func, r_err_tmp,
0, r_bailout_off, bc_off,
r_bailout_sp, pre_op_sp, bailout_tramp,
r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot);
MIR_label_t no_err = MIR_new_label(ctx);
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_URSH,
MIR_new_reg_op(ctx, r_bool),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_int_op(ctx, NANBOX_TYPE_SHIFT)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_BNE,
MIR_new_label_op(ctx, no_err),
MIR_new_reg_op(ctx, r_bool),
MIR_new_uint_op(ctx, JIT_ERR_TAG)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_err_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_err_tmp)));
}
MIR_append_insn(ctx, jit_func, no_err);
break;
}
case OP_SET_NAME: {
uint32_t atom_idx = sv_get_u32(ip + 1);
if (atom_idx >= (uint32_t)func->atom_count) { ok = false; break; }
sv_atom_t *atom = &func->atoms[atom_idx];
MIR_reg_t fn_val = vstack_top(&vs);
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 7,
MIR_new_ref_op(ctx, set_name_proto),
MIR_new_ref_op(ctx, imp_set_name),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, fn_val),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)atom->len)));
break;
}
case OP_TRY_PUSH: {
int32_t off = sv_get_i32(ip + 1);
int catch_off = bc_off + sz + off;
MIR_label_t catch_lbl = label_for_branch(ctx, &lm, catch_off, vs.sp);
if (jit_try_depth < JIT_TRY_MAX) {
jit_try_stack[jit_try_depth].catch_label = catch_lbl;
jit_try_stack[jit_try_depth].catch_bc_off = catch_off;
jit_try_stack[jit_try_depth].saved_sp = vs.sp;
jit_try_depth++;
}
if (catch_sp_count < JIT_TRY_MAX) {
catch_sp_map[catch_sp_count].bc_off = catch_off;
catch_sp_map[catch_sp_count].saved_sp = vs.sp;
catch_sp_count++;
}
break;
}
case OP_TRY_POP:
if (jit_try_depth > 0) jit_try_depth--;
break;
case OP_THROW: {
vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot);
MIR_reg_t thrown = vstack_pop(&vs);
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, thrown)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 6,
MIR_new_ref_op(ctx, helper1_proto),
MIR_new_ref_op(ctx, imp_throw),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, thrown)));
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_err_tmp)));
}
break;
}
case OP_THROW_ERROR: {
uint32_t atom_idx = sv_get_u32(ip + 1);
uint8_t err_type = sv_get_u8(ip + 5);
if (atom_idx >= (uint32_t)func->atom_count) { ok = false; break; }
sv_atom_t *atom = &func->atoms[atom_idx];
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 8,
MIR_new_ref_op(ctx, throw_error_proto),
MIR_new_ref_op(ctx, imp_throw_error),
MIR_new_reg_op(ctx, r_err_tmp),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_uint_op(ctx, (uint64_t)(uintptr_t)atom->str),
MIR_new_uint_op(ctx, (uint64_t)atom->len),
MIR_new_int_op(ctx, (int64_t)err_type)));
if (jit_try_depth > 0) {
jit_try_entry_t *h = &jit_try_stack[jit_try_depth - 1];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, vs.regs[h->saved_sp]),
MIR_new_reg_op(ctx, r_err_tmp)));
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_JMP,
MIR_new_label_op(ctx, h->catch_label)));
} else {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_err_tmp)));
}
break;
}
case OP_CATCH: {
int catch_saved_sp = -1;
for (int i = 0; i < catch_sp_count; i++) {
if (catch_sp_map[i].bc_off == bc_off) {
catch_saved_sp = catch_sp_map[i].saved_sp;
break;
}
}
if (catch_saved_sp >= 0) {
vs.sp = catch_saved_sp + 1;
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 6,
MIR_new_ref_op(ctx, helper1_proto),
MIR_new_ref_op(ctx, imp_catch_value),
MIR_new_reg_op(ctx, vs.regs[catch_saved_sp]),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, vs.regs[catch_saved_sp])));
} else {
ok = false;
}
break;
}
case OP_NIP_CATCH: {
MIR_reg_t a = vs.regs[vs.sp - 1];
MIR_reg_t below = vs.regs[vs.sp - 2];
MIR_append_insn(ctx, jit_func,
MIR_new_insn(ctx, MIR_MOV,
MIR_new_reg_op(ctx, below),
MIR_new_reg_op(ctx, a)));
vs.sp--;
break;
}
case OP_CLOSURE: {
uint32_t idx = sv_get_u32(ip + 1);
if (idx >= (uint32_t)func->const_count) { ok = false; break; }
MIR_reg_t dst = vstack_push(&vs);
ant_value_t cv = func->constants[idx];
sv_func_t *child = (sv_func_t *)(uintptr_t)vdata(cv);
jit_child_kind_t child_kind = classify_child_closure_kind(func, child);
MIR_reg_t r_child_slots = r_tmp2;
int child_slot_base = 0;
int child_slot_count = 0;
vs.known_func[vs.sp - 1] = (sv_func_t *)(uintptr_t)vdata(cv);
switch (child_kind) {
case JIT_CHILD_PLAIN:
case JIT_CHILD_INHERITED_ONLY:
break;
case JIT_CHILD_PARAM_ONLY:
r_child_slots = r_slotbuf;
child_slot_count = param_count;
break;
case JIT_CHILD_LOCAL_ONLY:
mir_emit_spill_child_captured_locals(
ctx, jit_func, func, child, local_regs, n_locals, r_lbuf);
r_child_slots = r_lbuf;
child_slot_base = param_count;
child_slot_count = n_locals;
break;
case JIT_CHILD_MIXED:
mir_emit_spill_child_captured_locals(
ctx, jit_func, func, child, local_regs, n_locals, r_lbuf);
r_child_slots = r_slotbuf;
child_slot_count = slotbuf_count;
break;
}
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 11,
MIR_new_ref_op(ctx, closure_proto),
MIR_new_ref_op(ctx, imp_closure),
MIR_new_reg_op(ctx, dst),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_js),
MIR_new_reg_op(ctx, r_closure),
MIR_new_reg_op(ctx, r_this_curr),
MIR_new_reg_op(ctx, r_child_slots),
MIR_new_int_op(ctx, child_slot_base),
MIR_new_int_op(ctx, child_slot_count),
MIR_new_uint_op(ctx, (uint64_t)idx)));
break;
}
default:
ok = false;
break;
}
if (!ok) break;
ip += sz;
}
if (!ok || vs.sp > 0) {
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1,
MIR_new_uint_op(ctx, mkval(T_UNDEF, 0))));
}
if (needs_bailout) {
MIR_append_insn(ctx, jit_func, bailout_tramp);
MIR_reg_t r_resume_res = MIR_new_func_reg(ctx, jit_func->u.func,
MIR_JSVAL, "resume_res");
MIR_append_insn(ctx, jit_func,
MIR_new_call_insn(ctx, 13,
MIR_new_ref_op(ctx, resume_proto),
MIR_new_ref_op(ctx, imp_resume),
MIR_new_reg_op(ctx, r_resume_res),
MIR_new_reg_op(ctx, r_vm),
MIR_new_reg_op(ctx, r_closure),
MIR_new_reg_op(ctx, r_this_curr),
MIR_new_reg_op(ctx, r_args),
MIR_new_reg_op(ctx, r_argc),
MIR_new_reg_op(ctx, r_args_buf),
MIR_new_reg_op(ctx, r_bailout_sp),
MIR_new_reg_op(ctx, r_lbuf),
MIR_new_int_op(ctx, n_locals),
MIR_new_reg_op(ctx, r_bailout_off)));
MIR_append_insn(ctx, jit_func,
MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, r_resume_res)));
}
MIR_finish_func(ctx);
MIR_finish_module(ctx);
if (sv_dump_jit_unlikely) MIR_output_module(ctx, stderr, mod);
free(vs.regs);
free(vs.d_regs);
free(vs.known_func);
free(vs.method_ic);
free(vs.slot_type);
free(vs.known_const);
free(vs.has_const);
free(local_regs);
free(local_d_regs);
free(known_func_locals);
free(known_type_locals);
free(captured_params);
free(captured_locals);
if (!ok) return NULL;
MIR_load_module(ctx, mod);
MIR_link(ctx, MIR_set_gen_interface, NULL);
func->jit_compiled_tfb_ver = func->tfb_version;
func->jit_compiling = false;
return MIR_gen(ctx, jit_func);
}
static void sv_jit_compile_callees(ant_t *js, sv_func_t *func) {
sv_call_target_fb_t *fb = func->call_target_fb;
int count = func->call_target_fb_count;
for (int i = 0; i < count; i++) {
if (fb[i].disabled || !fb[i].target) continue;
sv_func_t *callee = fb[i].target;
if (callee->jit_code || callee->jit_compile_failed || callee->jit_compiling) continue;
if (callee->call_count < SV_JIT_THRESHOLD / 2) continue;
if (!jit_is_eligible(callee)) continue;
sv_jit_func_t cjit = sv_jit_compile(js, callee, NULL);
if (cjit) callee->jit_code = (void *)cjit;
}
}
ant_value_t sv_jit_try_compile_and_call(
sv_vm_t *vm, ant_t *js,
sv_closure_t *closure, ant_value_t callee_func,
sv_call_ctx_t *ctx, ant_value_t *out_this
) {
sv_func_t *fn = closure->func;
sv_jit_func_t jit = sv_jit_compile(js, fn, closure);
if (!jit) {
fn->call_count = 0;
fn->back_edge_count = 0;
return SV_JIT_RETRY_INTERP;
}
fn->jit_code = (void *)jit;
sv_jit_compile_callees(js, fn);
sv_jit_enter(js);
ant_value_t result = jit(
vm, ctx->this_val, js->new_target,
ctx->super_val, ctx->args, ctx->argc, closure);
sv_jit_leave(js);
if (sv_is_jit_bailout(result)) {
sv_jit_on_bailout(fn);
return SV_JIT_RETRY_INTERP;
}
sv_call_cleanup(js, ctx);
if (out_this) *out_this = ctx->this_val;
return result;
}
ant_value_t sv_jit_try_osr(
sv_vm_t *vm, ant_t *js,
sv_frame_t *frame, sv_func_t *func,
int bc_offset
) {
sv_closure_t osr_closure;
sv_closure_t *closure;
if (vtype(frame->callee) == T_FUNC) {
closure = js_func_closure(frame->callee);
} else {
memset(&osr_closure, 0, sizeof(osr_closure));
osr_closure.func = func;
osr_closure.upvalues = frame->upvalues;
closure = &osr_closure;
}
sv_jit_func_t jit;
if (func->jit_code) {
jit = (sv_jit_func_t)func->jit_code;
} else {
if (func->code_len > 512) {
func->call_count = SV_JIT_THRESHOLD + 1;
func->back_edge_count = 0;
return SV_JIT_RETRY_INTERP;
}
jit = sv_jit_compile(js, func, closure);
if (!jit) return SV_JIT_RETRY_INTERP;
func->jit_code = (void *)jit;
sv_jit_compile_callees(js, func);
}
int nl = func->max_locals;
ant_value_t osr_locals[nl > 0 ? nl : 1];
for (int i = 0; i < nl; i++)
osr_locals[i] = frame->lp[i];
vm->jit_osr.active = true;
vm->jit_osr.bc_offset = bc_offset;
vm->jit_osr.locals = osr_locals;
vm->jit_osr.n_locals = nl;
vm->jit_osr.lp = frame->lp;
sv_jit_enter(js);
ant_value_t result = jit(
vm, frame->this, frame->new_target, frame->super_val,
frame->bp, frame->argc, closure);
sv_jit_leave(js);
if (sv_is_jit_bailout(result)) {
sv_jit_on_bailout(func);
return SV_JIT_RETRY_INTERP;
}
return result;
}
#endif
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 2, 4:30 PM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
544444
Default Alt Text
swarm.c (378 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment