Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536#include "compile.h"#include "silver/feedback.h"
static void jit_discard_setup_module(jit_compile_t *c) { for (int i = 0; i < c->lm.count; i++) MIR_append_insn(c->ctx, c->jit_func, c->lm.entries[i].label); MIR_finish_func(c->ctx); MIR_finish_module(c->ctx); MIR_remove_module(c->ctx, c->mod); free(c->lm.index); free(c->depth); c->lm.index = NULL; c->depth = NULL;}
bool jit_numeric_param_use(sv_func_t *func, uint8_t *ip, uint8_t *end) { if (ip >= end) return false; sv_op_t op = (sv_op_t)*ip; bool other_operand = false; if (op == OP_CONST_I8 || op == OP_CONST || op == OP_CONST8 || op == OP_GET_ARG || op == OP_GET_LOCAL || op == OP_GET_LOCAL8) { ip += sv_op_size[op]; if (ip >= end) return false; op = (sv_op_t)*ip; other_operand = true; } switch (op) { case OP_INC: case OP_DEC: case OP_POST_INC: case OP_POST_DEC: return !other_operand; case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_LT: case OP_LE: case OP_GT: case OP_GE: case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: case OP_USHR: { uint8_t *feedback = sv_func_type_feedback(func); return feedback && (feedback[ip - func->code] & SV_TFB_CLASS_MASK) == SV_TFB_NUM; } default: return false; }}
void jit_emit_entry_counter(jit_compile_t *c, const char *site, MIR_insn_t before) { char fn_name[32], calls_name[32], hot_name[32], res_name[32]; snprintf(fn_name, sizeof fn_name, "tier_fn_%s", site); snprintf(calls_name, sizeof calls_name, "tier_calls_%s", site); snprintf(hot_name, sizeof hot_name, "tier_hot_%s", site); snprintf(res_name, sizeof res_name, "tier_res_%s", site);
MIR_label_t body = MIR_new_label(c->ctx); MIR_reg_t r_fn = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, fn_name); MIR_reg_t r_calls = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, calls_name); MIR_reg_t r_hot = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, hot_name); MIR_reg_t r_res = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, res_name); MIR_op_t call_count = MIR_new_mem_op(c->ctx, MIR_T_U32, (MIR_disp_t)offsetof(sv_func_t, call_count), r_fn, 0, 1); MIR_insn_t insns[] = { MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_fn), MIR_new_uint_op(c->ctx, (uint64_t)(uintptr_t)c->func)), MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_calls), call_count), MIR_new_insn(c->ctx, MIR_ADD, MIR_new_reg_op(c->ctx, r_calls), MIR_new_reg_op(c->ctx, r_calls), MIR_new_int_op(c->ctx, 1)), MIR_new_insn(c->ctx, MIR_MOV, call_count, MIR_new_reg_op(c->ctx, r_calls)), MIR_new_insn(c->ctx, MIR_UBLE, MIR_new_label_op(c->ctx, body), MIR_new_reg_op(c->ctx, r_calls), MIR_new_int_op(c->ctx, SV_JIT_THRESHOLD)), MIR_new_call_insn(c->ctx, 6, MIR_new_ref_op(c->ctx, c->tier_up_proto), MIR_new_ref_op(c->ctx, c->imp_tier_up), MIR_new_reg_op(c->ctx, r_hot), MIR_new_reg_op(c->ctx, c->r_js), MIR_new_reg_op(c->ctx, r_fn), MIR_new_reg_op(c->ctx, c->r_closure)), MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, body), MIR_new_reg_op(c->ctx, r_hot), MIR_new_int_op(c->ctx, 0)), c->r_async_direct ? MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_U8, (MIR_disp_t)offsetof(struct sv_vm, jit.async_direct), c->r_vm, 0, 1), MIR_new_reg_op(c->ctx, c->r_async_direct)) : NULL, MIR_new_call_insn(c->ctx, 10, MIR_new_ref_op(c->ctx, c->self_proto), MIR_new_reg_op(c->ctx, r_hot), MIR_new_reg_op(c->ctx, r_res), MIR_new_reg_op(c->ctx, c->r_vm), MIR_new_reg_op(c->ctx, c->r_this), MIR_new_reg_op(c->ctx, c->r_new_target), MIR_new_reg_op(c->ctx, c->r_super_val), MIR_new_reg_op(c->ctx, c->r_args), MIR_new_reg_op(c->ctx, c->r_argc), MIR_new_reg_op(c->ctx, c->r_closure)), MIR_new_ret_insn(c->ctx, 1, MIR_new_reg_op(c->ctx, r_res)), body, }; for (size_t i = 0; i < sizeof insns / sizeof insns[0]; i++) { if (!insns[i]) continue; if (before) MIR_insert_insn_before(c->ctx, c->jit_func, before, insns[i]); else MIR_append_insn(c->ctx, c->jit_func, insns[i]); }}
static void jit_emit_iter_roots_clear(jit_compile_t *c) { for (int i = 0; i < c->vs.max; i++) MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_I64, (MIR_disp_t)(i * (int)sizeof(ant_value_t)), c->r_iter_roots, 0, 1), MIR_new_uint_op(c->ctx, 0)));}
static void jit_emit_cold_entry_counter(jit_compile_t *c, const char *site) { if (c->cold_tier) jit_emit_entry_counter(c, site, NULL);}
static void jit_emit_entry_local_guards(jit_compile_t *c, MIR_disp_t osr_base, const uint8_t *only) { if (c->known_type_locals && c->local_d_regs) { MIR_label_t osr_types_ok = MIR_new_label(c->ctx); MIR_label_t osr_type_bail = MIR_new_label(c->ctx); bool osr_any_num = false; for (int i = 0; i < c->n_locals; i++) if (c->known_type_locals[i] == SV_TI_NUM && (!only || only[i])) { osr_any_num = true; bool entry_integer = c->entry_integer_regs && c->entry_integer_regs[i]; MIR_label_t osr_local_done = NULL; if (!entry_integer) { osr_local_done = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, osr_local_done), MIR_new_reg_op(c->ctx, c->local_regs[i]), MIR_new_uint_op(c->ctx, mkval(kTypeUndefined, 0)))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, osr_local_done), MIR_new_reg_op(c->ctx, c->local_regs[i]), MIR_new_uint_op(c->ctx, (uint64_t)SV_TDZ))); } mir_emit_is_num_guard(c->ctx, c->jit_func, c->r_bool, c->local_regs[i], osr_type_bail); mir_i64_to_d(c->ctx, c->jit_func, c->local_d_regs[i], c->local_regs[i], c->r_d_slot); if (entry_integer) { jit_integer_range_t range = c->entry_integer_ranges[i]; MIR_reg_t integer = mir_emit_exact_integer_guard( c->ctx, c->jit_func, c->local_regs[i], c->local_d_regs[i], true, c->r_d_slot, (double)range.min, (double)range.max, osr_type_bail, -i - 1); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->entry_integer_regs[i]), MIR_new_reg_op(c->ctx, integer))); } if (osr_local_done) MIR_append_insn(c->ctx, c->jit_func, osr_local_done); } if (osr_any_num) { MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_JMP, MIR_new_label_op(c->ctx, osr_types_ok))); MIR_append_insn(c->ctx, c->jit_func, osr_type_bail); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_U8, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, active), c->r_vm, 0, 1), MIR_new_int_op(c->ctx, 0))); mir_load_imm(c->ctx, c->jit_func, c->r_bailout_val, (uint64_t)SV_JIT_RETRY_INTERP); MIR_append_insn(c->ctx, c->jit_func, MIR_new_ret_insn(c->ctx, 1, MIR_new_reg_op(c->ctx, c->r_bailout_val))); MIR_append_insn(c->ctx, c->jit_func, osr_types_ok); } }}
static void jit_emit_await_resume_entry(jit_compile_t *c, MIR_label_t resume_entry, MIR_disp_t osr_base) { sv_jit_await_map_t *map = sv_func_jit_await_map(c->func); MIR_append_insn(c->ctx, c->jit_func, resume_entry);
MIR_reg_t r_lp = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "await_lp"); MIR_reg_t r_stack = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "await_stack"); MIR_reg_t r_site = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "await_site"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_lp), MIR_new_mem_op(c->ctx, MIR_T_P, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, lp), c->r_vm, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_stack), MIR_new_mem_op(c->ctx, MIR_T_P, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, vstack), c->r_vm, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_site), MIR_new_mem_op(c->ctx, MIR_T_I32, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, bc_offset), c->r_vm, 0, 1)));
MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_U8, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, active), c->r_vm, 0, 1), MIR_new_int_op(c->ctx, SV_JIT_OSR_NONE)));
MIR_label_t reject = MIR_new_label(c->ctx); MIR_label_t *site_labels = calloc((size_t)map->site_count, sizeof(MIR_label_t)); MIR_op_t *ops = calloc((size_t)map->site_count + 1, sizeof(MIR_op_t)); uint8_t *live_mask = calloc((size_t)c->n_locals + 1, 1); if (!site_labels || !ops || !live_mask) { free(site_labels); free(ops); free(live_mask); c->ok = false; return; }
ops[0] = MIR_new_reg_op(c->ctx, r_site); for (int k = 0; k < map->site_count; k++) { int resume_off = (int)map->sites[k].bc_off + sv_op_size[OP_AWAIT]; int depth = resume_off < c->func->code_len ? c->depth[resume_off] : -1; bool usable = map->sites[k].resumable && depth >= 0 && depth <= c->vs.max; site_labels[k] = usable ? MIR_new_label(c->ctx) : NULL; ops[k + 1] = MIR_new_label_op(c->ctx, usable ? site_labels[k] : reject); } MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn_arr(c->ctx, MIR_SWITCH, (size_t)map->site_count + 1, ops)); free(ops);
MIR_append_insn(c->ctx, c->jit_func, reject); mir_load_imm(c->ctx, c->jit_func, c->r_bailout_val, (uint64_t)SV_JIT_RETRY_INTERP); MIR_append_insn(c->ctx, c->jit_func, MIR_new_ret_insn(c->ctx, 1, MIR_new_reg_op(c->ctx, c->r_bailout_val)));
for (int k = 0; k < map->site_count; k++) { if (!site_labels[k]) continue; int resume_off = (int)map->sites[k].bc_off + sv_op_size[OP_AWAIT]; const uint16_t *live = map->live + map->sites[k].live_start; MIR_append_insn(c->ctx, c->jit_func, site_labels[k]); memset(live_mask, 0, (size_t)c->n_locals + 1); for (int j = 0; j < map->sites[k].live_count; j++) if (live[j] < c->n_locals) live_mask[live[j]] = 1; for (int l = 0; l < c->n_locals; l++) MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->local_regs[l]), MIR_new_mem_op(c->ctx, MIR_JSVAL, (MIR_disp_t)(l * (int)sizeof(ant_value_t)), r_lp, 0, 1))); jit_emit_entry_local_guards(c, osr_base, live_mask); for (int j = 0; j < c->depth[resume_off]; j++) { MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->vs.regs[j]), MIR_new_mem_op(c->ctx, MIR_T_I64, (MIR_disp_t)(j * (int)sizeof(ant_value_t)), r_stack, 0, 1))); if (c->feat.needs_iter_roots) MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_I64, (MIR_disp_t)(j * (int)sizeof(ant_value_t)), c->r_iter_roots, 0, 1), MIR_new_reg_op(c->ctx, c->vs.regs[j]))); } MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_JMP, MIR_new_label_op(c->ctx, label_for_offset(c->ctx, &c->lm, resume_off)))); } free(site_labels); free(live_mask);}
typedef struct { uint32_t start, end; bool handler;} jit_dnum_block_t;
static int jit_dnum_local_access(sv_op_t op, const uint8_t *ip, int param_count, bool *writes) { *writes = false; switch (op) { case OP_GET_LOCAL: case OP_GET_LOCAL_CHK: return sv_get_u16(ip + 1); case OP_GET_LOCAL8: return sv_get_u8(ip + 1); case OP_INC_LOCAL: case OP_DEC_LOCAL: case OP_ADD_LOCAL: return sv_get_u8(ip + 1); case OP_GET_SLOT_RAW: case OP_CALL_CALL_SLOT: return (int)sv_get_u16(ip + 1) - param_count; case OP_PUT_LOCAL: case OP_SET_LOCAL: case OP_PUT_LOCAL_CHK: *writes = true; return sv_get_u16(ip + 1); case OP_PUT_LOCAL8: case OP_SET_LOCAL8: *writes = true; return sv_get_u8(ip + 1); default: return -1; }}
static int jit_dnum_block_of(const jit_dnum_block_t *blocks, int count, uint32_t off) { int lo = 0, hi = count - 1; while (lo <= hi) { int mid = (lo + hi) / 2; if (off < blocks[mid].start) hi = mid - 1; else if (off >= blocks[mid].end) lo = mid + 1; else return mid; } return -1;}
static void jit_clear_maybe_unassigned_dnum( sv_func_t *func, uint8_t *dnum, uint8_t *known_type, int n_locals, int param_count) { int *cand = calloc((size_t)n_locals, sizeof(int)); int ncand = 0; for (int i = 0; i < n_locals && cand; i++) cand[i] = (dnum[i] || known_type[i] == SV_TI_NUM) ? ncand++ : -1; uint32_t len = (uint32_t)func->code_len; uint8_t *leader = ncand ? calloc((size_t)len + 1, 1) : NULL; if (!leader) { free(cand); return; }
leader[0] = 1; for (uint32_t off = 0; off < len;) { sv_op_t op = (sv_op_t)func->code[off]; int sz = sv_op_size[op]; if (sz == 0) break; uint16_t flags = sv_op_flags[op]; int64_t target = -1; if (flags & SV_OPF_JIT_BRANCH32) target = (int64_t)off + sz + sv_get_i32(func->code + off + 1); else if (flags & SV_OPF_JIT_BRANCH8) target = (int64_t)off + sz + sv_get_i8(func->code + off + 1); else if (op == OP_TRY_PUSH || op == OP_TRY_PUSH_FINALLY || op == OP_CATCH || op == OP_UNWIND_JMP) target = (int64_t)off + 5 + sv_get_i32(func->code + off + 1); if (target >= 0 && target <= len) leader[target] |= (op == OP_TRY_PUSH || op == OP_TRY_PUSH_FINALLY || op == OP_CATCH || op == OP_UNWIND_JMP) ? 3 : 1; if (target >= 0 || (flags & SV_OPF_TERMINAL)) leader[off + sz < len ? off + sz : len] |= 1; off += (uint32_t)sz; }
int nblocks = 0; for (uint32_t off = 0; off < len; off++) if (leader[off]) nblocks++; int words = (ncand + 63) / 64; jit_dnum_block_t *blocks = calloc((size_t)nblocks, sizeof(*blocks)); uint64_t *in = calloc((size_t)nblocks * (size_t)words, sizeof(uint64_t)); uint64_t *state = calloc((size_t)words, sizeof(uint64_t)); bool *queued = calloc((size_t)nblocks, sizeof(bool)); bool *seen = calloc((size_t)nblocks, sizeof(bool)); int *work = calloc((size_t)nblocks + 1, sizeof(int)); bool *bad = calloc((size_t)ncand, sizeof(bool)); if (!blocks || !in || !state || !queued || !seen || !work || !bad) goto done;
for (uint32_t off = 0, b = 0; off < len; off++) { if (!leader[off]) continue; if (b > 0) blocks[b - 1].end = off; blocks[b] = (jit_dnum_block_t){ .start = off, .end = len, .handler = (leader[off] & 2) != 0 }; b++; }
int wn = 0; for (int b = 0; b < nblocks; b++) if (b == 0 || blocks[b].handler) { memset(in + (size_t)b * words, 0xff, (size_t)words * sizeof(uint64_t)); work[wn++] = b; queued[b] = seen[b] = true; }
for (int pass = 0; pass < 2; pass++) { while (wn > 0) { int b = work[--wn]; queued[b] = false; memcpy(state, in + (size_t)b * words, (size_t)words * sizeof(uint64_t)); bool falls = true; int64_t target = -1; for (uint32_t off = blocks[b].start; off < blocks[b].end;) { sv_op_t op = (sv_op_t)func->code[off]; int sz = sv_op_size[op]; if (sz == 0) { falls = false; break; } bool writes = false; int local = jit_dnum_local_access(op, func->code + off, param_count, &writes); if (local >= 0 && local < n_locals && cand[local] >= 0) { int ci = cand[local]; uint64_t bit = 1ull << (ci & 63); if (!writes && (state[ci >> 6] & bit)) bad[ci] = true; if (op == OP_INC_LOCAL || op == OP_DEC_LOCAL || op == OP_ADD_LOCAL || writes) state[ci >> 6] &= ~bit; } if (op == OP_SET_LOCAL_UNDEF) { uint16_t li = sv_get_u16(func->code + off + 1); if (li < n_locals && cand[li] >= 0) state[cand[li] >> 6] |= 1ull << (cand[li] & 63); } uint16_t flags = sv_op_flags[op]; if (flags & SV_OPF_JIT_BRANCH32) target = (int64_t)off + sz + sv_get_i32(func->code + off + 1); else if (flags & SV_OPF_JIT_BRANCH8) target = (int64_t)off + sz + sv_get_i8(func->code + off + 1); if (flags & SV_OPF_TERMINAL) falls = false; off += (uint32_t)sz; } int succ[2] = { falls && b + 1 < nblocks ? b + 1 : -1, target >= 0 ? jit_dnum_block_of(blocks, nblocks, (uint32_t)target) : -1 }; for (int k = 0; k < 2; k++) { int sb = succ[k]; if (sb < 0) continue; uint64_t *dst = in + (size_t)sb * words; bool changed = !seen[sb]; for (int w = 0; w < words; w++) { uint64_t merged = dst[w] | state[w]; if (merged != dst[w]) { dst[w] = merged; changed = true; } } seen[sb] = true; if (changed && !queued[sb]) { queued[sb] = true; work[wn++] = sb; } } } for (int b = 0; b < nblocks && pass == 0; b++) if (!seen[b]) { memset(in + (size_t)b * words, 0xff, (size_t)words * sizeof(uint64_t)); seen[b] = queued[b] = true; work[wn++] = b; } }
for (int i = 0; i < n_locals; i++) if (cand[i] >= 0 && bad[cand[i]]) { dnum[i] = 0; known_type[i] = SV_TI_UNKNOWN; }
done: free(cand); free(leader); free(blocks); free(in); free(state); free(queued); free(seen); free(work); free(bad);}
_Thread_local jit_call_tagging_t *jit_call_tagging;
bool jit_setup_frame(jit_compile_t *c) { c->hoisted_upvalue = -1; c->hoisted_upvalue_cell = 0; c->hoisted_upvalue_tdz = 0; char fname[128]; snprintf(fname, sizeof(fname), "jit_%s_%p", c->func->debug->name ? c->func->debug->name : "anon", (void *)c->func);
c->mod = MIR_new_module(c->ctx, fname); MIR_type_t ret_type = MIR_JSVAL;
jit_setup_prototypes(c, ret_type);
c->jit_func = MIR_new_func(c->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");
c->lm = (jit_label_map_t){0}; c->depth = sv_func_stack_depth_map(c->func); if (!c->depth || !scan_branch_targets(c->func, &c->lm, c->ctx)) { jit_discard_setup_module(c); c->func->jit_compile_failed = true; c->func->jit_compiling = false; return false; }
c->call_tagging = (jit_call_tagging_t){ .ctx = c->ctx, .bc_off = &c->bc_off }; jit_call_tagging = &c->call_tagging;
c->r_vm = MIR_reg(c->ctx, "vm", c->jit_func->u.func); c->r_this = MIR_reg(c->ctx, "this_val", c->jit_func->u.func); c->r_new_target = MIR_reg(c->ctx, "new_target", c->jit_func->u.func); c->r_super_val = MIR_reg(c->ctx, "super_val", c->jit_func->u.func); c->r_args = MIR_reg(c->ctx, "args", c->jit_func->u.func); c->r_argc = MIR_reg(c->ctx, "argc", c->jit_func->u.func); c->r_closure = MIR_reg(c->ctx, "closure", c->jit_func->u.func);
if (c->func->is_async) { MIR_label_t async_body = MIR_new_label(c->ctx); MIR_reg_t r_entered = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "async_osr"); MIR_reg_t r_promise = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "async_promise"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_entered), MIR_new_mem_op(c->ctx, MIR_T_U8, (MIR_disp_t)(offsetof(struct sv_vm, jit.osr) + offsetof(sv_jit_osr_t, active)), c->r_vm, 0, 1))); MIR_label_t async_start = MIR_new_label(c->ctx); MIR_reg_t r_direct = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "async_direct_req"); MIR_disp_t direct_disp = (MIR_disp_t)offsetof(struct sv_vm, jit.async_direct); c->r_async_direct = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "async_direct"); c->r_async_next_op = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "async_next_op"); mir_load_imm(c->ctx, c->jit_func, c->r_async_direct, 0); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BNE, MIR_new_label_op(c->ctx, async_body), MIR_new_reg_op(c->ctx, r_entered), MIR_new_int_op(c->ctx, 0))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_direct), MIR_new_mem_op(c->ctx, MIR_T_U8, direct_disp, c->r_vm, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, async_start), MIR_new_reg_op(c->ctx, r_direct), MIR_new_int_op(c->ctx, 0))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_U8, direct_disp, c->r_vm, 0, 1), MIR_new_int_op(c->ctx, 0))); mir_load_imm(c->ctx, c->jit_func, c->r_async_direct, 1); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_async_next_op), MIR_new_mem_op(c->ctx, MIR_T_U8, (MIR_disp_t)offsetof(struct sv_vm, jit.async_next_op), c->r_vm, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_JMP, MIR_new_label_op(c->ctx, async_body))); MIR_append_insn(c->ctx, c->jit_func, async_start); MIR_append_insn(c->ctx, c->jit_func, MIR_new_call_insn(c->ctx, 10, MIR_new_ref_op(c->ctx, c->self_proto), MIR_new_ref_op(c->ctx, c->imp_async_start), MIR_new_reg_op(c->ctx, r_promise), MIR_new_reg_op(c->ctx, c->r_vm), MIR_new_reg_op(c->ctx, c->r_this), MIR_new_reg_op(c->ctx, c->r_new_target), MIR_new_reg_op(c->ctx, c->r_super_val), MIR_new_reg_op(c->ctx, c->r_args), MIR_new_reg_op(c->ctx, c->r_argc), MIR_new_reg_op(c->ctx, c->r_closure))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_ret_insn(c->ctx, 1, MIR_new_reg_op(c->ctx, r_promise))); MIR_append_insn(c->ctx, c->jit_func, async_body); }
c->r_cage_base = MIR_new_func_reg( c->ctx, c->jit_func->u.func, MIR_T_I64, "cage_base"); mir_load_imm(c->ctx, c->jit_func, c->r_cage_base, (uint64_t)ant_cage_base());
c->r_this_curr = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "this_curr"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_this_curr), MIR_new_reg_op(c->ctx, c->r_this)));
c->r_js = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "js_ptr"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_js), MIR_new_mem_op(c->ctx, MIR_T_I64, 0, c->r_vm, 0, 1)));
{ MIR_reg_t r_stk_probe = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "stk_probe"); MIR_reg_t r_stk_floor = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "stk_floor"); MIR_label_t no_overflow = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, r_stk_probe), MIR_new_int_op(c->ctx, 8))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_stk_floor), MIR_new_mem_op(c->ctx, MIR_T_I64, (MIR_disp_t)offsetof(ant_t, cstk.floor), c->r_js, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_UBGE, MIR_new_label_op(c->ctx, no_overflow), MIR_new_reg_op(c->ctx, r_stk_probe), MIR_new_reg_op(c->ctx, r_stk_floor))); MIR_reg_t r_ovf_err = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "stk_err"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_call_insn(c->ctx, 5, MIR_new_ref_op(c->ctx, c->stack_ovf_err_proto), MIR_new_ref_op(c->ctx, c->imp_stack_ovf_err), MIR_new_reg_op(c->ctx, r_ovf_err), MIR_new_reg_op(c->ctx, c->r_vm), MIR_new_reg_op(c->ctx, c->r_js))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_ret_insn(c->ctx, 1, MIR_new_reg_op(c->ctx, r_ovf_err))); MIR_append_insn(c->ctx, c->jit_func, no_overflow); }
if (ant_realm_multiple(c->js)) { MIR_reg_t r_realm = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "cur_realm"); MIR_label_t same_realm = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_realm), MIR_new_mem_op(c->ctx, MIR_T_P, (MIR_disp_t)offsetof(ant_t, realm), c->r_js, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, same_realm), MIR_new_reg_op(c->ctx, r_realm), MIR_new_uint_op(c->ctx, (uint64_t)(uintptr_t)c->func->realm))); MIR_reg_t r_reentered = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "realm_result"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_call_insn(c->ctx, 10, MIR_new_ref_op(c->ctx, c->self_proto), MIR_new_ref_op(c->ctx, c->imp_realm_reenter), MIR_new_reg_op(c->ctx, r_reentered), MIR_new_reg_op(c->ctx, c->r_vm), MIR_new_reg_op(c->ctx, c->r_this), MIR_new_reg_op(c->ctx, c->r_new_target), MIR_new_reg_op(c->ctx, c->r_super_val), MIR_new_reg_op(c->ctx, c->r_args), MIR_new_reg_op(c->ctx, c->r_argc), MIR_new_reg_op(c->ctx, c->r_closure))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_ret_insn(c->ctx, 1, MIR_new_reg_op(c->ctx, r_reentered))); MIR_append_insn(c->ctx, c->jit_func, same_realm); }
if (!vstack_alloc(&c->vs, c->func->max_stack + JIT_VSTACK_SLACK)) { jit_discard_setup_module(c);
c->func->jit_compiling = false; return false; }
for (int i = 0; i < c->vs.max; i++) { char rname[32]; snprintf(rname, sizeof(rname), "s%d", i); c->vs.regs[i] = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, rname); } for (int i = 0; i < c->vs.max; i++) { char dname[32]; snprintf(dname, sizeof(dname), "sd%d", i); c->vs.d_regs[i] = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_D, dname); }
c->n_locals = c->func->max_locals; c->local_regs = NULL; c->local_d_regs = NULL; c->known_func_locals = NULL; c->known_type_locals = NULL; if (c->n_locals > 0) { c->local_regs = calloc((size_t)c->n_locals, sizeof(MIR_reg_t)); c->local_d_regs = calloc((size_t)c->n_locals, sizeof(MIR_reg_t)); c->known_func_locals = calloc((size_t)c->n_locals, sizeof(sv_func_t *)); c->known_type_locals = calloc((size_t)c->n_locals, sizeof(uint8_t));
if (!c->local_regs || !c->local_d_regs || !c->known_func_locals || !c->known_type_locals) { vstack_free(&c->vs); free(c->local_regs); free(c->local_d_regs); free(c->known_func_locals); free(c->known_type_locals);
jit_discard_setup_module(c);
c->func->jit_compiling = false; return false; }
sv_type_info_t *local_types = sv_func_local_types(c->func); if (local_types && c->func->local_type_count > 0) { int ncopy = c->func->local_type_count < c->n_locals ? c->func->local_type_count : c->n_locals; for (int i = 0; i < ncopy; i++) c->known_type_locals[i] = local_types[i].type; } if (c->func->local_type_feedback) { for (int i = 0; i < c->n_locals; i++) { uint8_t ltf = c->func->local_type_feedback[i]; if (ltf && !(ltf & ~SV_TFB_NUM)) c->known_type_locals[i] = SV_TI_NUM; } } for (int i = 0; i < c->n_locals; i++) { char rname[32], dname[32]; snprintf(rname, sizeof(rname), "l%d", i); snprintf(dname, sizeof(dname), "ld%d", i); c->local_regs[i] = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, rname); c->local_d_regs[i] = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_D, dname); if (!c->func->is_async) mir_load_imm(c->ctx, c->jit_func, c->local_regs[i], mkval(kTypeUndefined, 0)); } }
c->r_tmp = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "tmp"); c->r_tmp2 = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "tmp2"); c->r_bool = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "bool_tmp"); MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "str_eq_l"); MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "str_eq_r"); MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "str_eq_n"); MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "str_eq_w"); c->r_err_tmp = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "err_tmp"); mir_load_imm(c->ctx, c->jit_func, c->r_tmp2, 0);
c->self_binding_guards = calloc( c->func->code_len > 0 ? (size_t)c->func->code_len : 1u, 1u); c->feat = jit_prescan_features( c->func, c->func->param_count + c->n_locals, c->hint_closure); if (jit_mark_self_binding_guards( c->js, c->func, c->hint_closure, c->self_binding_guards)) { c->feat.needs_bailout = true; c->feat.needs_args_buf = true; }
c->r_d_slot = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "d_slot"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, c->r_d_slot), MIR_new_uint_op(c->ctx, 8)));
c->r_d_one = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_D, "d_one"); if (c->feat.needs_inc_local) { union { double d; uint64_t u; } one = {1.0}; mir_load_imm(c->ctx, c->jit_func, c->r_bool, one.u); mir_i64_to_d(c->ctx, c->jit_func, c->r_d_one, c->r_bool, c->r_d_slot); }
if (c->cold_tier) c->feat.needs_args_buf = true; c->r_args_buf = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "args_buf"); if (c->feat.needs_args_buf) { int scratch_slots = SV_JIT_ARGS_BUF_CAP; if (c->vs.max > scratch_slots) scratch_slots = c->vs.max; if (c->n_locals > scratch_slots) scratch_slots = c->n_locals; c->args_buf_slots = scratch_slots; MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, c->r_args_buf), MIR_new_uint_op(c->ctx, (uint64_t)scratch_slots * sizeof(ant_value_t)))); } else { mir_load_imm(c->ctx, c->jit_func, c->r_args_buf, 0); }
c->inline_ext = (jit_inline_ext_t){ .next_inline_id = &c->call_n, .helper1_proto = c->helper1_proto, .get_length_proto = c->get_length_proto, .object_proto = c->object_proto, .imp_object = c->imp_object, .truthy_proto = c->truthy_proto, .imp_is_truthy = c->imp_is_truthy, .imp_get_length_inline = c->imp_get_length_inline, .imp_get_field = c->imp_get_field, .imp_get_length = c->imp_get_length, .get_elem_inline_proto = c->get_elem_inline_proto, .imp_get_elem_inline = c->imp_get_elem_inline, .put_field_proto = c->put_field_proto, .imp_put_field = c->imp_put_field, .shape_transition_proto = c->shape_transition_proto, .imp_shape_transition = c->imp_shape_transition, .imp_protector_store = c->imp_protector_store, .remember_obj_proto = c->remember_obj_proto, .imp_remember_obj = c->imp_remember_obj, .call_proto = c->call_proto, .imp_call = c->imp_call, .call_method_proto = c->call_method_proto, .imp_call_method = c->imp_call_method, .cfunc_proto = c->cfunc_proto, .native_finish_proto = c->native_finish_proto, .imp_native_finish = c->imp_native_finish, .stable_load_proto = c->stable_load_proto, .imp_load_stable_builtin = c->imp_load_stable_builtin, .stable_call_proto = c->stable_call_proto, .imp_call_stable_builtin = c->imp_call_stable_builtin, .imp_band = c->imp_band, .imp_bor = c->imp_bor, .imp_bxor = c->imp_bxor, .imp_shl = c->imp_shl, .imp_shr = c->imp_shr, .fmod_proto = c->fmod_proto, .imp_fmod = c->imp_fmod, .imp_ushr = c->imp_ushr, .self_proto = c->self_proto, .math1_proto = c->math1_proto, .imp_math = c->imp_math, .r_args_buf = c->r_args_buf, };
c->r_call_out_this = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "call_out_this"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, c->r_call_out_this), MIR_new_uint_op(c->ctx, sizeof(ant_value_t))));
c->normalize_sloppy_this = c->feat.needs_this && !c->func->is_strict && !c->func->is_arrow; c->r_this_root = 0; if (c->normalize_sloppy_this) { c->r_this_root = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "this_root"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, c->r_this_root), MIR_new_uint_op(c->ctx, sizeof(ant_value_t)))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_JSVAL, 0, c->r_this_root, 0, 1), MIR_new_reg_op(c->ctx, c->r_this_curr))); }
c->r_iter_roots = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "iter_roots"); c->r_iter_buf = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "iter_buf"); if (c->feat.needs_iter_roots && c->vs.max > 0) { MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, c->r_iter_roots), MIR_new_uint_op(c->ctx, (uint64_t)c->vs.max * sizeof(ant_value_t)))); if (!c->func->is_async) jit_emit_iter_roots_clear(c); } else { mir_load_imm(c->ctx, c->jit_func, c->r_iter_roots, 0); }
c->r_tco_args = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "tco_args"); c->needs_bailout = c->feat.needs_bailout;
c->r_ic_epoch_val = 0; if (c->feat.needs_ic_epoch) { c->r_ic_epoch_val = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "ic_ep_ptr"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_ic_epoch_val), MIR_new_uint_op(c->ctx, (uint64_t)(uintptr_t)&c->js->ic.epoch))); }
c->r_bailout_val = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "bail_val"); c->r_bailout_off = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "bail_off"); c->r_bailout_sp = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "bail_sp"); c->bailout_tramp = c->needs_bailout ? MIR_new_label(c->ctx) : NULL;
c->param_count = c->func->param_count; c->writes_params = func_writes_params(c->func); c->captured_params = scan_captured_params(c->func); c->captured_locals = scan_captured_locals(c->func, c->n_locals); c->builder_target_slots = c->feat.builder_target_slots; c->has_captured_params = false; c->has_captures = false; if (c->captured_params) { for (int i = 0; i < c->param_count; i++) if (c->captured_params[i]) { c->has_captured_params = true; break; } } if (c->captured_locals) { for (int i = 0; i < c->n_locals; i++) if (c->captured_locals[i]) { c->has_captures = true; if (c->known_type_locals) c->known_type_locals[i] = SV_TI_UNKNOWN; } } c->cached_index_key = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "cached_index_key"); c->cached_index_value = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "cached_index_value"); mir_load_imm(c->ctx, c->jit_func, c->cached_index_key, js_mkundef()); mir_load_imm(c->ctx, c->jit_func, c->cached_index_value, 0); c->cached_element_object = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "cached_element_object"); c->cached_element_key = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "cached_element_key"); c->cached_element_value = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "cached_element_value"); c->cached_element_valid = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "cached_element_valid"); mir_load_imm(c->ctx, c->jit_func, c->cached_element_valid, 0); c->dnum_locals = NULL; if (c->n_locals > 0 && c->local_d_regs && c->known_type_locals) { c->dnum_locals = calloc((size_t)c->n_locals, 1); if (c->dnum_locals) { for (int i = 0; i < c->n_locals; i++) c->dnum_locals[i] = c->known_type_locals[i] == SV_TI_NUM && !(c->captured_locals && c->captured_locals[i]); uint8_t *dp = c->func->code, *de = c->func->code + c->func->code_len; while (dp < de) { sv_op_t dop = (sv_op_t)*dp; int dsz = sv_op_size[dop]; if (dsz == 0) break; if (dop == OP_SET_LOCAL_UNDEF) { uint16_t di = sv_get_u16(dp + 1); if (di < (uint16_t)c->n_locals && jit_local_slot_shared(c->func, di) && !jit_has_immediate_numeric_local_init(c->func, dp + dsz, de, di)) c->dnum_locals[di] = 0; } else if ((sv_op_flags[dop] & SV_OPF_BUILDER_TARGET) != 0) { uint16_t ds = sv_get_u16(dp + 1); if (ds >= (uint16_t)c->param_count && (int)ds - c->param_count < c->n_locals) c->dnum_locals[ds - c->param_count] = 0; } dp += dsz; } } } if (c->dnum_locals) jit_clear_maybe_unassigned_dnum(c->func, c->dnum_locals, c->known_type_locals, c->n_locals, c->param_count); c->entry_integer_ranges = calloc((size_t)c->n_locals, sizeof(jit_integer_range_t)); c->entry_integer_regs = calloc((size_t)c->n_locals, sizeof(MIR_reg_t)); if (c->entry_integer_ranges && c->entry_integer_regs && c->dnum_locals) { jit_entry_integer_ranges(c->func, c->entry_integer_ranges, c->n_locals, c->param_count); for (int i = 0; i < c->n_locals; i++) { if (!c->dnum_locals[i]) continue; if (!c->entry_integer_ranges[i].known) continue; char name[48]; snprintf(name, sizeof(name), "entry_integer_%d", i); c->entry_integer_regs[i] = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, name); } } c->induction_locals = NULL; if (c->dnum_locals && !c->func->has_dynamic_eval) { c->induction_locals = calloc((size_t)c->n_locals, 1); if (c->induction_locals) { jit_induction_locals(c->func, c->induction_locals, c->n_locals, c->param_count); for (int i = 0; i < c->n_locals; i++) if (!c->dnum_locals[i] || (c->entry_integer_regs && c->entry_integer_regs[i])) c->induction_locals[i] = 0; } } c->params_in_slotbuf = c->writes_params || c->has_captured_params; c->has_captured_slots = c->params_in_slotbuf || c->has_captures; c->use_unified_slotbuf = c->has_captured_slots && c->has_captures; c->slotbuf_count = c->use_unified_slotbuf ? (c->param_count + c->n_locals) : c->param_count;
c->r_param_init_argc = c->r_argc; if (c->writes_params && c->param_count > 0) { c->r_param_init_argc = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "param_init_argc"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_param_init_argc), MIR_new_reg_op(c->ctx, c->r_argc)));
MIR_disp_t osr_base = (MIR_disp_t)offsetof(struct sv_vm, jit.osr); MIR_label_t param_argc_done = MIR_new_label(c->ctx); MIR_label_t param_argc_enough = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_bool), MIR_new_mem_op(c->ctx, MIR_T_U8, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, active), c->r_vm, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, param_argc_done), MIR_new_reg_op(c->ctx, c->r_bool), MIR_new_int_op(c->ctx, 0))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_UBGT, MIR_new_label_op(c->ctx, param_argc_enough), MIR_new_reg_op(c->ctx, c->r_param_init_argc), MIR_new_int_op(c->ctx, (int64_t)c->param_count - 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_param_init_argc), MIR_new_int_op(c->ctx, c->param_count))); MIR_append_insn(c->ctx, c->jit_func, param_argc_enough); MIR_append_insn(c->ctx, c->jit_func, param_argc_done); }
c->r_slotbuf = c->r_tmp2; if (c->has_captured_slots && c->slotbuf_count > 0) { c->r_slotbuf = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "slotbuf"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, c->r_slotbuf), MIR_new_uint_op(c->ctx, (uint64_t)c->slotbuf_count * sizeof(ant_value_t)))); mir_emit_fill_param_slots_from_args( c->ctx, c->jit_func, c->r_slotbuf, c->r_args, c->r_param_init_argc, c->captured_params, c->param_count, c->writes_params); }
c->needs_lbuf = c->needs_bailout || c->feat.needs_close_upval || c->has_captures || c->cold_tier; c->r_lbuf = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "lbuf"); if (c->use_unified_slotbuf && c->n_locals > 0) { MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ADD, MIR_new_reg_op(c->ctx, c->r_lbuf), MIR_new_reg_op(c->ctx, c->r_slotbuf), MIR_new_int_op(c->ctx, (int64_t)c->param_count * (int64_t)sizeof(ant_value_t)))); } else if (c->needs_lbuf && c->n_locals > 0) { MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, c->r_lbuf), MIR_new_uint_op(c->ctx, (uint64_t)c->n_locals * sizeof(ant_value_t)))); } else { mir_load_imm(c->ctx, c->jit_func, c->r_lbuf, 0); } if (c->has_captures && c->captured_locals && c->n_locals > 0) { for (int i = 0; i < c->n_locals; i++) if (c->captured_locals[i]) MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_I64, (MIR_disp_t)(i * (int)sizeof(ant_value_t)), c->r_lbuf, 0, 1), MIR_new_uint_op(c->ctx, mkval(kTypeUndefined, 0)))); }
c->use_jit_upvalue_list = c->has_captured_slots; c->r_jit_open_upvalues = 0; if (c->use_jit_upvalue_list) { c->r_jit_open_upvalues = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "jit_open_upvalues"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, c->r_jit_open_upvalues), MIR_new_uint_op(c->ctx, sizeof(sv_upvalue_t *)))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_I64, 0, c->r_jit_open_upvalues, 0, 1), MIR_new_uint_op(c->ctx, 0))); }
c->bailout_ctx = (jit_bailout_emit_t){ .val = c->r_bailout_val, .off = c->r_bailout_off, .sp = c->r_bailout_sp, .tramp = c->bailout_tramp, .spill = c->needs_bailout ? MIR_new_label(c->ctx) : NULL, .args_buf = c->r_args_buf, .vstack = &c->vs, .local_regs = c->local_regs, .local_d_regs = c->local_d_regs, .dnum_locals = c->dnum_locals, .n_locals = c->n_locals, .lbuf = c->r_lbuf, .d_slot = c->r_d_slot, }; if (c->cold_tier) { c->promote_tramp = MIR_new_label(c->ctx); c->promote_ctx = c->bailout_ctx; c->promote_ctx.tramp = c->promote_tramp; c->promote_ctx.spill = MIR_new_label(c->ctx);
c->promote_sites = calloc((size_t)c->func->code_len, 1); if (c->promote_sites) { int (*edges)[2] = NULL; int n = jit_back_edges(c->func, &edges); if (n >= 0) { for (int i = 0; i < n; i++) { bool nested = false, has_inner = false; for (int j = 0; j < n; j++) { if (j == i) continue; if (edges[j][0] <= edges[i][0] && edges[j][1] >= edges[i][1]) nested = true; if (edges[i][0] <= edges[j][0] && edges[j][1] <= edges[i][1]) has_inner = true; } c->promote_sites[edges[i][1]] = nested ? 0 : has_inner ? 2 : 1; } } else { free(c->promote_sites); c->promote_sites = NULL; } free(edges); } c->r_promote = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "promote_countdown"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_promote), MIR_new_int_op(c->ctx, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_call_insn(c->ctx, 3, MIR_new_ref_op(c->ctx, c->promote_start_proto), MIR_new_ref_op(c->ctx, c->imp_promote_start), MIR_new_ref_op(c->ctx, c->cold_ns_item))); }
if (c->feat.needs_tco_args) { MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, c->r_tco_args), MIR_new_uint_op(c->ctx, (uint64_t)SV_JIT_ARGS_BUF_CAP * sizeof(ant_value_t)))); } else mir_load_imm(c->ctx, c->jit_func, c->r_tco_args, 0); c->self_tail_entry = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, c->self_tail_entry);
c->osr_map = (osr_entry_map_t){0}; scan_osr_entries(c->func, &c->osr_map); c->await_park = c->func->is_async && !c->has_captures && !c->has_captured_params && !c->func->has_dynamic_eval; if (c->await_park && !sv_func_jit_await_map(c->func)) { sv_func_sidecar_t *sidecar = sv_func_ensure_sidecar(c->func); if (sidecar) sidecar->jit_await_map = jit_await_map_build(c->func, c->depth); } if (!sv_func_jit_await_map(c->func)) c->await_park = false; c->await_park_block = NULL; if (c->await_park) { c->r_frame_lp = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "frame_lp"); c->r_park_site = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "park_site"); c->r_park_sp = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "park_sp"); c->r_park_value = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "park_value"); c->await_park_block = MIR_new_label(c->ctx); mir_load_imm(c->ctx, c->jit_func, c->r_frame_lp, 0); } memset(c->param_cache, 0, sizeof(c->param_cache)); memset(c->param_d_cache, 0, sizeof(c->param_d_cache)); memset(c->param_num, 0, sizeof(c->param_num)); memset(c->param_num_ok, 0, sizeof(c->param_num_ok)); memset(c->param_shadow, 0, sizeof(c->param_shadow)); c->induction_params = 0; { uint8_t read_mask = 0, written_mask = 0, numeric_mask = 0; uint8_t *pscan = c->func->code, *pend = c->func->code + c->func->code_len; while (pscan < pend) { sv_op_t pop_ = (sv_op_t)*pscan; int psz = sv_op_size[pop_]; if (psz == 0) break; if (pop_ == OP_GET_ARG || pop_ == OP_GET_SLOT_RAW) { uint16_t pidx = sv_get_u16(pscan + 1); if (pidx < JIT_PARAM_HOIST_CAP) { uint8_t bit = (uint8_t)(1u << pidx); read_mask |= bit; if (pop_ == OP_GET_ARG && !(written_mask & bit) && jit_numeric_param_use(c->func, pscan + psz, pend)) numeric_mask |= bit; } } else if (pop_ == OP_PUT_ARG || pop_ == OP_SET_ARG || (sv_op_flags[pop_] & SV_OPF_BUILDER_TARGET)) { uint16_t pidx = sv_get_u16(pscan + 1); if (pidx < JIT_PARAM_HOIST_CAP) written_mask |= (uint8_t)(1u << pidx); } pscan += psz; } uint8_t promote_mask = 0; if (c->writes_params && c->captured_params && c->builder_target_slots && !c->func->has_dynamic_eval && c->osr_map.count && !c->cold_tier && !c->feat.needs_tco_args) { for (int i = 0; i < c->param_count && i < JIT_PARAM_HOIST_CAP; i++) if (!c->captured_params[i] && !c->builder_target_slots[i]) promote_mask |= (uint8_t)(1u << i); promote_mask &= read_mask; if (!(promote_mask & numeric_mask)) promote_mask = 0; } for (int i = 0; i < c->param_count && i < JIT_PARAM_HOIST_CAP; i++) { if (!(read_mask & (1u << i))) continue; if (c->captured_params && c->captured_params[i]) continue; if (c->writes_params && !(promote_mask & (1u << i))) continue; char prn[16]; snprintf(prn, sizeof(prn), "parg%d", i); c->param_cache[i] = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, prn); if (c->writes_params) { MIR_op_t slot = MIR_new_mem_op(c->ctx, MIR_JSVAL, (MIR_disp_t)(i * sizeof(ant_value_t)), c->r_slotbuf, 0, 1); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->param_cache[i]), slot)); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, slot, MIR_new_uint_op(c->ctx, js_mkundef()))); continue; } MIR_label_t in_range = MIR_new_label(c->ctx); MIR_label_t done = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_UBGT, MIR_new_label_op(c->ctx, in_range), MIR_new_reg_op(c->ctx, c->r_argc), MIR_new_int_op(c->ctx, (int64_t)i))); mir_load_imm(c->ctx, c->jit_func, c->param_cache[i], mkval(kTypeUndefined, 0)); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_JMP, MIR_new_label_op(c->ctx, done))); MIR_append_insn(c->ctx, c->jit_func, in_range); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->param_cache[i]), MIR_new_mem_op(c->ctx, MIR_JSVAL, (MIR_disp_t)(i * (int)sizeof(ant_value_t)), c->r_args, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, done); } c->self_tail_reentry = NULL; if (c->feat.needs_tco_args && !c->writes_params) { c->self_tail_reentry = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, c->self_tail_reentry); } if (!c->writes_params && c->needs_bailout) { for (int i = 0; i < c->param_count && i < JIT_PARAM_HOIST_CAP; i++) { if (!c->param_cache[i] || !(numeric_mask & (1u << i))) continue; char name[24]; snprintf(name, sizeof(name), "parg_num%d", i); c->param_num[i] = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_D, name); snprintf(name, sizeof(name), "parg_num_ok%d", i); c->param_num_ok[i] = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, name); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ULE, MIR_new_reg_op(c->ctx, c->param_num_ok[i]), MIR_new_reg_op(c->ctx, c->param_cache[i]), MIR_new_uint_op(c->ctx, NANBOX_PREFIX))); mir_i64_to_d(c->ctx, c->jit_func, c->param_num[i], c->param_cache[i], c->r_d_slot); } } if (c->writes_params && !c->cold_tier && !c->feat.needs_tco_args) { MIR_label_t bad_type = MIR_new_label(c->ctx); MIR_label_t not_integer = MIR_new_label(c->ctx); MIR_label_t not_integer_at[JIT_PARAM_HOIST_CAP] = {0}; MIR_label_t ready = MIR_new_label(c->ctx); bool any_numeric = false; uint8_t counters = jit_induction_params(c->func, c->param_count); for (int i = 0; i < c->param_count && i < JIT_PARAM_HOIST_CAP; i++) { if (!c->param_cache[i] || !(numeric_mask & (1u << i))) continue; char name[24]; snprintf(name, sizeof(name), "parg_num%d", i); c->param_d_cache[i] = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_D, name); mir_emit_is_num_guard(c->ctx, c->jit_func, c->r_bool, c->param_cache[i], bad_type); mir_i64_to_d(c->ctx, c->jit_func, c->param_d_cache[i], c->param_cache[i], c->r_d_slot); any_numeric = true; if (!(counters & (1u << i))) continue; c->induction_params |= (uint8_t)(1u << i); snprintf(name, sizeof(name), "parg_int%d", i); MIR_reg_t integer = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, name); snprintf(name, sizeof(name), "parg_back%d", i); MIR_reg_t back = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_D, name); snprintf(name, sizeof(name), "parg_top%d", i); MIR_reg_t top = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, name); not_integer_at[i] = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_D2I, MIR_new_reg_op(c->ctx, integer), MIR_new_reg_op(c->ctx, c->param_d_cache[i]))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_I2D, MIR_new_reg_op(c->ctx, back), MIR_new_reg_op(c->ctx, integer))); // D2I saturates, so ±2^63 round-trip as INT64_MAX/MIN; doubling without overflow bounds the counter to ±2^62 MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ADDO, MIR_new_reg_op(c->ctx, top), MIR_new_reg_op(c->ctx, integer), MIR_new_reg_op(c->ctx, integer))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BO, MIR_new_label_op(c->ctx, not_integer_at[i]))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_DBNE, MIR_new_label_op(c->ctx, not_integer_at[i]), MIR_new_reg_op(c->ctx, c->param_d_cache[i]), MIR_new_reg_op(c->ctx, back))); } if (any_numeric) { MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_JMP, MIR_new_label_op(c->ctx, ready))); if (c->induction_params) { MIR_reg_t failed = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "parg_not_integer"); for (int i = 0; i < JIT_PARAM_HOIST_CAP; i++) { if (!not_integer_at[i]) continue; MIR_append_insn(c->ctx, c->jit_func, not_integer_at[i]); mir_load_imm(c->ctx, c->jit_func, failed, 1u << i); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_JMP, MIR_new_label_op(c->ctx, not_integer))); } MIR_append_insn(c->ctx, c->jit_func, not_integer); MIR_append_insn(c->ctx, c->jit_func, MIR_new_call_insn(c->ctx, 4, MIR_new_ref_op(c->ctx, c->param_counters_off_proto), MIR_new_ref_op(c->ctx, c->imp_param_counters_off), MIR_new_uint_op(c->ctx, (uint64_t)(uintptr_t)c->func), MIR_new_reg_op(c->ctx, failed))); } MIR_append_insn(c->ctx, c->jit_func, bad_type); MIR_label_t call_entry = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_bool), MIR_new_mem_op(c->ctx, MIR_T_U8, offsetof(sv_vm_t, jit.osr) + offsetof(sv_jit_osr_t, active), c->r_vm, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, call_entry), MIR_new_reg_op(c->ctx, c->r_bool), MIR_new_int_op(c->ctx, 0))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_ret_insn(c->ctx, 1, MIR_new_uint_op(c->ctx, SV_JIT_BAILOUT))); MIR_append_insn(c->ctx, c->jit_func, call_entry); MIR_reg_t entry_result = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "param_entry_result"); c->call_tagging.resume = true; MIR_append_insn(c->ctx, c->jit_func, MIR_new_call_insn(c->ctx, 17, MIR_new_ref_op(c->ctx, c->resume_proto), MIR_new_ref_op(c->ctx, c->imp_resume), MIR_new_reg_op(c->ctx, entry_result), MIR_new_reg_op(c->ctx, c->r_vm), MIR_new_reg_op(c->ctx, c->r_closure), MIR_new_reg_op(c->ctx, c->r_this_curr), MIR_new_reg_op(c->ctx, c->r_new_target), MIR_new_reg_op(c->ctx, c->r_super_val), MIR_new_reg_op(c->ctx, c->r_args), MIR_new_reg_op(c->ctx, c->r_argc), MIR_new_uint_op(c->ctx, 0), MIR_new_int_op(c->ctx, 0), MIR_new_uint_op(c->ctx, 0), MIR_new_int_op(c->ctx, 0), MIR_new_uint_op(c->ctx, 0), MIR_new_int_op(c->ctx, 0), MIR_new_int_op(c->ctx, 0))); c->call_tagging.resume = false; MIR_append_insn(c->ctx, c->jit_func, MIR_new_ret_insn(c->ctx, 1, MIR_new_reg_op(c->ctx, entry_result))); MIR_append_insn(c->ctx, c->jit_func, ready); } } }
if (c->ctx == c->jc->ctx_hot && !c->feat.needs_tco_args) c->hoisted_upvalue = jit_hot_loop_upvalue(c->func); if (c->hoisted_upvalue >= 0) { MIR_reg_t table = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "hoisted_upvalue_table"); c->hoisted_upvalue_cell = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "hoisted_upvalue_cell"); MIR_reg_t root = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "hoisted_closure_root"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_ALLOCA, MIR_new_reg_op(c->ctx, root), MIR_new_int_op(c->ctx, sizeof(uint64_t)))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_I64, 0, root, 0, 1), MIR_new_reg_op(c->ctx, c->r_closure))); MIR_label_t done = MIR_new_label(c->ctx); mir_load_imm(c->ctx, c->jit_func, c->hoisted_upvalue_cell, 0); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, done), MIR_new_reg_op(c->ctx, c->r_closure), MIR_new_int_op(c->ctx, 0))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, table), MIR_new_mem_op(c->ctx, MIR_T_P, offsetof(sv_closure_t, upvalues), c->r_closure, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, done), MIR_new_reg_op(c->ctx, table), MIR_new_int_op(c->ctx, 0))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->hoisted_upvalue_cell), MIR_new_mem_op(c->ctx, MIR_T_P, c->hoisted_upvalue * sizeof(sv_upvalue_t *), table, 0, 1))); if (jit_upvalue_needs_tdz_guard(c, (uint16_t)c->hoisted_upvalue)) { c->hoisted_upvalue_tdz = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "hoisted_upvalue_tdz"); MIR_label_t loaded = MIR_new_label(c->ctx); mir_load_imm(c->ctx, c->jit_func, c->hoisted_upvalue_tdz, 0); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, loaded), MIR_new_reg_op(c->ctx, c->hoisted_upvalue_cell), MIR_new_int_op(c->ctx, 0))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, table), MIR_new_mem_op(c->ctx, MIR_T_P, offsetof(sv_upvalue_t, location), c->hoisted_upvalue_cell, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, table), MIR_new_mem_op(c->ctx, MIR_JSVAL, 0, table, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_EQ, MIR_new_reg_op(c->ctx, c->hoisted_upvalue_tdz), MIR_new_reg_op(c->ctx, table), MIR_new_uint_op(c->ctx, SV_TDZ))); MIR_append_insn(c->ctx, c->jit_func, loaded); } MIR_append_insn(c->ctx, c->jit_func, done); }
if (c->global_hoist_item) { MIR_reg_t addr = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "global_hoist_addr"); c->global_hoist.r_global = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "global_hoist_obj"); c->global_hoist.r_shape = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "global_hoist_shape"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, addr), MIR_new_ref_op(c->ctx, c->global_hoist_item))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->global_hoist.r_global), MIR_new_mem_op(c->ctx, MIR_T_U64, 0, addr, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->global_hoist.r_shape), MIR_new_mem_op(c->ctx, MIR_T_U64, 8, addr, 0, 1))); }
bool await_resume = false; for (int i = 0; c->await_park && i < sv_func_jit_await_map(c->func)->site_count && !await_resume; i++) await_resume = sv_func_jit_await_map(c->func)->sites[i].resumable;
if (c->osr_map.count > 0 || await_resume) { MIR_label_t normal_entry = MIR_new_label(c->ctx); MIR_label_t resume_entry = await_resume ? MIR_new_label(c->ctx) : NULL;
MIR_disp_t osr_base = (MIR_disp_t)offsetof(struct sv_vm, jit.osr);
MIR_reg_t r_osr_active = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "osr_active"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_osr_active), MIR_new_mem_op(c->ctx, MIR_T_U8, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, active), c->r_vm, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, normal_entry), MIR_new_reg_op(c->ctx, r_osr_active), MIR_new_int_op(c->ctx, 0)));
jit_emit_cold_entry_counter(c, "osr"); if (c->await_park) MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_frame_lp), MIR_new_mem_op(c->ctx, MIR_T_P, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, lp), c->r_vm, 0, 1))); if (resume_entry) MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, resume_entry), MIR_new_reg_op(c->ctx, r_osr_active), MIR_new_int_op(c->ctx, SV_JIT_OSR_AWAIT))); MIR_reg_t r_osr_locals = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "osr_locals"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_osr_locals), MIR_new_mem_op(c->ctx, MIR_T_P, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, locals), c->r_vm, 0, 1)));
if (c->feat.needs_iter_roots && c->vs.max > 0) { MIR_reg_t r_osr_vstack = MIR_new_func_reg( c->ctx, c->jit_func->u.func, MIR_T_I64, "osr_vstack"); MIR_reg_t r_osr_vstack_sp = MIR_new_func_reg( c->ctx, c->jit_func->u.func, MIR_T_I64, "osr_vstack_sp"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_osr_vstack), MIR_new_mem_op(c->ctx, MIR_T_P, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, vstack), c->r_vm, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_osr_vstack_sp), MIR_new_mem_op(c->ctx, MIR_T_I32, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, vstack_sp), c->r_vm, 0, 1))); for (int i = 0; i < c->vs.max; i++) { MIR_label_t slot_done = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_UBLE, MIR_new_label_op(c->ctx, slot_done), MIR_new_reg_op(c->ctx, r_osr_vstack_sp), MIR_new_int_op(c->ctx, i))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->vs.regs[i]), MIR_new_mem_op(c->ctx, MIR_T_I64, (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_osr_vstack, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_I64, (MIR_disp_t)(i * (int)sizeof(ant_value_t)), c->r_iter_roots, 0, 1), MIR_new_reg_op(c->ctx, c->vs.regs[i]))); MIR_append_insn(c->ctx, c->jit_func, slot_done); } }
for (int i = 0; i < c->n_locals; i++) { MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->local_regs[i]), MIR_new_mem_op(c->ctx, MIR_JSVAL, (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_osr_locals, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_JSVAL, (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_osr_locals, 0, 1), MIR_new_uint_op(c->ctx, 0))); }
jit_emit_entry_local_guards(c, osr_base, NULL);
if (c->has_captured_params && c->r_jit_open_upvalues) { MIR_append_insn(c->ctx, c->jit_func, MIR_new_call_insn(c->ctx, 7, MIR_new_ref_op(c->ctx, c->take_open_upvalues_rebase_proto), MIR_new_ref_op(c->ctx, c->imp_take_open_upvalues_rebase), MIR_new_reg_op(c->ctx, c->r_vm), MIR_new_reg_op(c->ctx, c->r_jit_open_upvalues), MIR_new_reg_op(c->ctx, c->r_args), MIR_new_reg_op(c->ctx, c->r_slotbuf), MIR_new_int_op(c->ctx, c->param_count))); }
if (c->has_captures) { MIR_reg_t r_osr_lp = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "osr_lp"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_osr_lp), MIR_new_mem_op(c->ctx, MIR_T_P, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, lp), c->r_vm, 0, 1)));
if (c->use_unified_slotbuf) { for (int i = 0; i < c->n_locals; i++) if (c->captured_locals && c->captured_locals[i]) MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_I64, (MIR_disp_t)(i * (int)sizeof(ant_value_t)), c->r_lbuf, 0, 1), MIR_new_reg_op(c->ctx, c->local_regs[i]))); } else { MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_lbuf), MIR_new_reg_op(c->ctx, r_osr_lp))); }
if (c->r_jit_open_upvalues) { if (c->use_unified_slotbuf) MIR_append_insn(c->ctx, c->jit_func, MIR_new_call_insn(c->ctx, 7, MIR_new_ref_op(c->ctx, c->take_open_upvalues_rebase_proto), MIR_new_ref_op(c->ctx, c->imp_take_open_upvalues_rebase), MIR_new_reg_op(c->ctx, c->r_vm), MIR_new_reg_op(c->ctx, c->r_jit_open_upvalues), MIR_new_reg_op(c->ctx, r_osr_lp), MIR_new_reg_op(c->ctx, c->r_lbuf), MIR_new_int_op(c->ctx, c->n_locals))); else MIR_append_insn(c->ctx, c->jit_func, MIR_new_call_insn(c->ctx, 6, MIR_new_ref_op(c->ctx, c->take_open_upvalues_proto), MIR_new_ref_op(c->ctx, c->imp_take_open_upvalues), MIR_new_reg_op(c->ctx, c->r_vm), MIR_new_reg_op(c->ctx, c->r_jit_open_upvalues), MIR_new_reg_op(c->ctx, c->r_lbuf), MIR_new_int_op(c->ctx, c->n_locals))); } }
MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_T_U8, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, active), c->r_vm, 0, 1), MIR_new_int_op(c->ctx, 0)));
MIR_reg_t r_osr_off = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_T_I64, "osr_off"); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, r_osr_off), MIR_new_mem_op(c->ctx, MIR_T_I32, osr_base + (MIR_disp_t)offsetof(sv_jit_osr_t, bc_offset), c->r_vm, 0, 1)));
for (int i = 0; i < c->osr_map.count; i++) { MIR_label_t target_lbl = label_for_offset(c->ctx, &c->lm, c->osr_map.offsets[i]); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, target_lbl), MIR_new_reg_op(c->ctx, r_osr_off), MIR_new_int_op(c->ctx, c->osr_map.offsets[i]))); } mir_load_imm(c->ctx, c->jit_func, c->r_bailout_val, (uint64_t)SV_JIT_RETRY_INTERP); MIR_append_insn(c->ctx, c->jit_func, MIR_new_ret_insn(c->ctx, 1, MIR_new_reg_op(c->ctx, c->r_bailout_val)));
if (resume_entry) jit_emit_await_resume_entry(c, resume_entry, osr_base);
MIR_append_insn(c->ctx, c->jit_func, normal_entry); } if (c->func->is_async) { for (int i = 0; i < c->n_locals; i++) mir_load_imm(c->ctx, c->jit_func, c->local_regs[i], mkval(kTypeUndefined, 0)); if (c->feat.needs_iter_roots && c->vs.max > 0) jit_emit_iter_roots_clear(c); } jit_emit_cold_entry_counter(c, "call"); c->call_entry = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, c->call_entry);
memset(c->jit_try_stack, 0, sizeof(c->jit_try_stack)); c->jit_try_depth = 0;
memset(c->catch_sp_map, 0, sizeof(c->catch_sp_map)); c->catch_sp_count = 0;
c->r_result = MIR_new_func_reg(c->ctx, c->jit_func->u.func, MIR_JSVAL, "result"); mir_load_imm(c->ctx, c->jit_func, c->r_result, mkval(kTypeUndefined, 0));
c->ip = c->func->code; c->end = c->func->code + c->func->code_len;
c->integer_locals = calloc((size_t)c->n_locals, sizeof(MIR_reg_t)); c->integer_local_ranges = calloc((size_t)c->n_locals, sizeof(jit_integer_range_t)); c->local_reg_limit = 0; for (int i = 0; i < c->n_locals; i++) { if (c->local_regs[i] > c->local_reg_limit) c->local_reg_limit = c->local_regs[i]; if (c->local_d_regs[i] > c->local_reg_limit) c->local_reg_limit = c->local_d_regs[i]; } c->local_by_reg = calloc((size_t)c->local_reg_limit + 1, sizeof(int)); if (c->local_by_reg) { for (int i = 0; i < c->n_locals; i++) { c->local_by_reg[c->local_regs[i]] = i + 1; c->local_by_reg[c->local_d_regs[i]] = i + 1; } } else { free(c->integer_locals); c->integer_locals = NULL; } c->integer_local_site = 0; c->element_available = false;
c->ok = true; c->call_n = 0; c->upval_n = 0; c->arith_n = 0; c->reg_site_n = 0;
if (c->normalize_sloppy_this) { MIR_label_t normalize_global = MIR_new_label(c->ctx); MIR_label_t normalize_box = MIR_new_label(c->ctx); MIR_label_t normalize_done = MIR_new_label(c->ctx); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_UBLE, MIR_new_label_op(c->ctx, normalize_box), MIR_new_reg_op(c->ctx, c->r_this_curr), MIR_new_uint_op(c->ctx, NANBOX_PREFIX))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_URSH, MIR_new_reg_op(c->ctx, c->r_bool), MIR_new_reg_op(c->ctx, c->r_this_curr), MIR_new_int_op(c->ctx, NANBOX_TYPE_SHIFT))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, normalize_global), MIR_new_reg_op(c->ctx, c->r_bool), MIR_new_uint_op(c->ctx, (NANBOX_PREFIX >> NANBOX_TYPE_SHIFT) | (uint64_t)kTypeUndefined))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, normalize_global), MIR_new_reg_op(c->ctx, c->r_bool), MIR_new_uint_op(c->ctx, (NANBOX_PREFIX >> NANBOX_TYPE_SHIFT) | (uint64_t)kTypeNull))); const uint8_t boxed_types[] = { kTypeString, kTypeBool, kTypeBigInt, kTypeSymbol}; for (size_t i = 0; i < sizeof(boxed_types); i++) { MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_BEQ, MIR_new_label_op(c->ctx, normalize_box), MIR_new_reg_op(c->ctx, c->r_bool), MIR_new_uint_op(c->ctx, (NANBOX_PREFIX >> NANBOX_TYPE_SHIFT) | (uint64_t)boxed_types[i]))); } MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_JMP, MIR_new_label_op(c->ctx, normalize_done)));
MIR_append_insn(c->ctx, c->jit_func, normalize_global); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_reg_op(c->ctx, c->r_this_curr), MIR_new_mem_op(c->ctx, MIR_JSVAL, (MIR_disp_t)offsetof(ant_t, global_this), c->r_js, 0, 1))); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_JMP, MIR_new_label_op(c->ctx, normalize_done)));
MIR_append_insn(c->ctx, c->jit_func, normalize_box); MIR_append_insn(c->ctx, c->jit_func, MIR_new_call_insn(c->ctx, 5, MIR_new_ref_op(c->ctx, c->normalize_this_proto), MIR_new_ref_op(c->ctx, c->imp_normalize_this), MIR_new_reg_op(c->ctx, c->r_this_curr), MIR_new_reg_op(c->ctx, c->r_js), MIR_new_reg_op(c->ctx, c->r_this_curr))); jit_emit_throw_if_error(c, c->r_this_curr); MIR_append_insn(c->ctx, c->jit_func, normalize_done); MIR_append_insn(c->ctx, c->jit_func, MIR_new_insn(c->ctx, MIR_MOV, MIR_new_mem_op(c->ctx, MIR_JSVAL, 0, c->r_this_root, 0, 1), MIR_new_reg_op(c->ctx, c->r_this_curr))); }
return true;}