MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

prevent arg closure buf being dropped on deop

+437 -159
+2 -10
include/silver/glue.h
··· 4 4 #ifdef ANT_JIT 5 5 #include "silver/engine.h" 6 6 7 - double jit_helper_tod(ant_value_t v); 8 - uint64_t jit_helper_vtype(ant_value_t v); 7 + bool jit_helper_stack_overflow(ant_t *js); 9 8 int64_t jit_helper_is_truthy(ant_t *js, ant_value_t v); 10 - 11 - ant_value_t jit_helper_tov(double d); 12 - ant_value_t jit_helper_mkbool(int b); 13 - 14 - bool jit_helper_stack_overflow(ant_t *js); 15 - sv_closure_t *jit_helper_get_closure(ant_value_t v); 16 9 17 10 ant_value_t jit_helper_add(sv_vm_t *vm, ant_t *js, ant_value_t l, ant_value_t r); 18 11 ant_value_t jit_helper_sub(sv_vm_t *vm, ant_t *js, ant_value_t l, ant_value_t r); ··· 94 87 ant_value_t jit_helper_closure( 95 88 sv_vm_t *vm, ant_t *js, 96 89 sv_closure_t *parent_closure, ant_value_t this_val, 97 - ant_value_t *args, int argc, 98 - uint32_t const_idx, ant_value_t *locals, int n_locals 90 + ant_value_t *slots, int slot_count, uint32_t const_idx 99 91 ); 100 92 101 93 ant_value_t jit_helper_bailout_resume(
+27 -4
src/modules/net.c
··· 17 17 #include "errors.h" 18 18 #include "internal.h" 19 19 20 + #include "gc/roots.h" 20 21 #include "gc/modules.h" 21 22 #include "net/listener.h" 22 23 #include "silver/engine.h" ··· 711 712 return js_false; 712 713 } 713 714 715 + GC_ROOT_SAVE(root_mark, js); 716 + GC_ROOT_PIN(js, parsed.callback); 714 717 net_socket_sync_state(socket); 718 + 715 719 if (is_callable(parsed.callback)) net_call_value(js, parsed.callback, js_mkundef(), NULL, 0); 720 + GC_ROOT_RESTORE(js, root_mark); 721 + 716 722 return js_true; 717 723 } 718 724 ··· 724 730 if (!socket) return js->thrown_value; 725 731 if (!socket->conn) return result; 726 732 if (!net_parse_write_args(js, args, nargs, &parsed)) return parsed.error; 733 + 734 + GC_ROOT_SAVE(root_mark, js); 735 + GC_ROOT_PIN(js, parsed.callback); 736 + 727 737 if (parsed.len > 0) { 728 - ant_value_t write_result = js_net_socket_write(js, args, nargs); 729 - if (is_err(write_result)) return write_result; 730 - } 738 + ant_value_t write_result = js_net_socket_write(js, args, nargs); 739 + if (is_err(write_result)) { 740 + GC_ROOT_RESTORE(js, root_mark); 741 + return write_result; 742 + }} 743 + 731 744 ant_conn_shutdown(socket->conn); 732 745 if (is_callable(parsed.callback)) net_call_value(js, parsed.callback, js_mkundef(), NULL, 0); 746 + GC_ROOT_RESTORE(js, root_mark); 747 + 733 748 return result; 734 749 } 735 750 ··· 819 834 callbacks.on_conn_close = net_server_on_conn_close; 820 835 callbacks.on_listener_close = net_server_on_listener_close; 821 836 837 + GC_ROOT_SAVE(root_mark, js); 838 + GC_ROOT_PIN(js, parsed.callback); 839 + 822 840 ant_value_t bind_result = net_server_bind_listener(js, server, &parsed, &callbacks); 823 - if (is_err(bind_result)) return bind_result; 841 + if (is_err(bind_result)) { 842 + GC_ROOT_RESTORE(js, root_mark); 843 + return bind_result; 844 + } 824 845 825 846 server->port = ant_listener_port(&server->listener); 826 847 server->listening = true; ··· 830 851 831 852 if (is_callable(parsed.callback)) net_call_value(js, parsed.callback, js_mkundef(), NULL, 0); 832 853 net_emit(js, server->obj, "listening", NULL, 0); 854 + GC_ROOT_RESTORE(js, root_mark); 855 + 833 856 return js_getthis(js); 834 857 } 835 858
+29 -41
src/silver/glue.c
··· 173 173 return (int64_t)js_truthy(js, v); 174 174 } 175 175 176 - sv_closure_t *jit_helper_get_closure(ant_value_t v) { 177 - if (vtype(v) != T_FUNC) return NULL; 178 - return js_func_closure(v); 179 - } 180 - 181 176 static inline void jit_set_error_site_from_func(ant_t *js, sv_func_t *func, int32_t bc_off) { 182 177 if (!func) return; 183 178 js_set_error_site_from_bc(js, func, (int)bc_off, func->filename); ··· 202 197 return coerce_to_str(js, v); 203 198 } 204 199 205 - uint64_t jit_helper_vtype(ant_value_t v) { return vtype(v); } 206 - double jit_helper_tod(ant_value_t v) { return tod(v); } 207 - ant_value_t jit_helper_tov(double d) { return tov(d); } 208 - ant_value_t jit_helper_mkbool(int b) { return js_bool(b); } 200 + static inline sv_upvalue_t *jit_make_undef_upvalue(void) { 201 + sv_upvalue_t *uv = js_upvalue_alloc(); 202 + uv->closed = js_mkundef(); 203 + uv->location = &uv->closed; 204 + return uv; 205 + } 209 206 210 207 ant_value_t jit_helper_closure( 211 208 sv_vm_t *vm, ant_t *js, 212 209 sv_closure_t *parent_closure, ant_value_t this_val, 213 - ant_value_t *args, int argc, 214 - uint32_t const_idx, ant_value_t *locals, int n_locals 210 + ant_value_t *slots, int slot_count, uint32_t const_idx 215 211 ) { 216 212 sv_func_t *parent_func = parent_closure->func; 217 213 sv_func_t *child = (sv_func_t *)(uintptr_t)vdata(parent_func->constants[const_idx]); ··· 225 221 closure->super_val = js_mkundef(); 226 222 closure->call_flags = child->is_arrow ? SV_CALL_IS_ARROW : 0; 227 223 228 - // TODO: reduce nesting 229 - if (child->upvalue_count > 0) { 224 + if (child->upvalue_count > 0) 230 225 closure->upvalues = calloc((size_t)child->upvalue_count, sizeof(sv_upvalue_t *)); 231 - for (int i = 0; i < child->upvalue_count; i++) { 232 - sv_upval_desc_t *desc = &child->upval_descs[i]; 233 - if (desc->is_local) { 234 - int idx = (int)desc->index; 235 - if (idx < parent_func->param_count) { 236 - sv_upvalue_t *uv = js_upvalue_alloc(); 237 - uv->closed = (idx < argc && args) ? args[idx] : js_mkundef(); 238 - uv->location = &uv->closed; 239 - closure->upvalues[i] = uv; 240 - } else { 241 - int li = idx - parent_func->param_count; 242 - if (li >= 0 && li < n_locals && locals) { 243 - closure->upvalues[i] = sv_capture_upvalue(vm, &locals[li]); 244 - } else { 245 - sv_upvalue_t *uv = js_upvalue_alloc(); 246 - uv->closed = js_mkundef(); 247 - uv->location = &uv->closed; 248 - closure->upvalues[i] = uv; 249 - } 250 - } 251 - } else closure->upvalues[i] = parent_closure->upvalues[desc->index]; 226 + 227 + for (int i = 0; i < child->upvalue_count; i++) { 228 + sv_upval_desc_t *desc = &child->upval_descs[i]; 229 + if (!desc->is_local) { 230 + closure->upvalues[i] = parent_closure->upvalues[desc->index]; 231 + continue; 232 + } 233 + 234 + int idx = (int)desc->index; 235 + if (!slots || idx < 0 || idx >= slot_count) { 236 + closure->upvalues[i] = jit_make_undef_upvalue(); 237 + continue; 252 238 } 239 + 240 + closure->upvalues[i] = sv_capture_upvalue(vm, &slots[idx]); 253 241 } 254 242 255 243 ant_value_t func_obj = mkobj(js, 0); ··· 282 270 return func_val; 283 271 } 284 272 285 - void jit_helper_close_upval(sv_vm_t *vm, uint16_t slot_idx, ant_value_t *locals, int n_locals) { 286 - (void)slot_idx; // TODO: use value 287 - if (!locals || n_locals <= 0) return; 273 + void jit_helper_close_upval(sv_vm_t *vm, uint16_t slot_idx, ant_value_t *slots, int slot_count) { 274 + if (!slots || slot_count <= 0) return; 275 + if ((int)slot_idx >= slot_count) return; 288 276 289 - ant_value_t *lo = locals; 290 - ant_value_t *hi = locals + n_locals; 277 + ant_value_t *lo = slots + slot_idx; 278 + ant_value_t *hi = slots + slot_count; 291 279 sv_upvalue_t **pp = &vm->open_upvalues; 292 280 293 281 while (*pp) { ··· 296 284 uv->closed = *uv->location; 297 285 uv->location = &uv->closed; 298 286 *pp = uv->next; 299 - } else pp = &uv->next; 287 + } 288 + else pp = &uv->next; 300 289 } 301 290 } 302 291 ··· 328 317 sv_vm_t *vm, ant_t *js, ant_value_t obj, 329 318 ant_value_t val, const char *str, uint32_t len 330 319 ) { 331 - (void)vm; 332 320 if (!sv_try_define_field_fast(js, obj, str, val)) 333 321 js_define_own_prop(js, obj, str, len, val); 334 322 }
+264 -104
src/silver/swarm.c
··· 58 58 LOAD_EXT(jit_helper_call); 59 59 LOAD_EXT(jit_helper_apply); 60 60 LOAD_EXT(jit_helper_rest); 61 - LOAD_EXT(jit_helper_tov); 62 61 LOAD_EXT(jit_helper_special_obj); 63 62 LOAD_EXT(jit_helper_get_global); 64 63 LOAD_EXT(jit_helper_get_field); ··· 325 324 MIR_reg_t r_tco_args, MIR_reg_t r_arg_arr, 326 325 MIR_reg_t r_args, MIR_reg_t r_argc, 327 326 MIR_reg_t *local_regs, int n_locals, 327 + bool has_captured_slots, MIR_reg_t r_slotbuf, 328 328 bool has_captures, bool *captured_locals, 329 329 MIR_reg_t r_lbuf, MIR_label_t entry 330 330 ) { ··· 343 343 MIR_new_insn(ctx, MIR_MOV, 344 344 MIR_new_reg_op(ctx, r_argc), 345 345 MIR_new_int_op(ctx, (int64_t)call_argc))); 346 + if (has_captured_slots) { 347 + for (int i = 0; i < param_count; i++) { 348 + MIR_label_t arg_present = MIR_new_label(ctx); 349 + MIR_label_t arg_done = MIR_new_label(ctx); 350 + MIR_append_insn(ctx, fn, 351 + MIR_new_insn(ctx, MIR_UBGT, 352 + MIR_new_label_op(ctx, arg_present), 353 + MIR_new_reg_op(ctx, r_argc), 354 + MIR_new_int_op(ctx, (int64_t)i))); 355 + MIR_append_insn(ctx, fn, 356 + MIR_new_insn(ctx, MIR_MOV, 357 + MIR_new_mem_op(ctx, MIR_T_I64, 358 + (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_slotbuf, 0, 1), 359 + MIR_new_uint_op(ctx, mkval(T_UNDEF, 0)))); 360 + MIR_append_insn(ctx, fn, 361 + MIR_new_insn(ctx, MIR_JMP, 362 + MIR_new_label_op(ctx, arg_done))); 363 + MIR_append_insn(ctx, fn, arg_present); 364 + MIR_append_insn(ctx, fn, 365 + MIR_new_insn(ctx, MIR_MOV, 366 + MIR_new_mem_op(ctx, MIR_T_I64, 367 + (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_slotbuf, 0, 1), 368 + MIR_new_mem_op(ctx, MIR_T_I64, 369 + (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_tco_args, 0, 1))); 370 + MIR_append_insn(ctx, fn, arg_done); 371 + } 372 + } 346 373 for (int i = 0; i < n_locals; i++) 347 374 mir_load_imm(ctx, fn, local_regs[i], mkval(T_UNDEF, 0)); 348 375 if (has_captures) { ··· 772 799 } 773 800 } 774 801 802 + static sv_func_t *scan_closure_child(sv_func_t *func, uint8_t *ip) { 803 + if ((sv_op_t)*ip != OP_CLOSURE) return NULL; 804 + 805 + uint32_t idx = sv_get_u32(ip + 1); 806 + if (idx >= (uint32_t)func->const_count) return NULL; 807 + 808 + ant_value_t cv = func->constants[idx]; 809 + if (vtype(cv) != T_FUNC) return NULL; 810 + 811 + return (sv_func_t *)(uintptr_t)vdata(cv); 812 + } 813 + 775 814 static bool *scan_captured_locals(sv_func_t *func, int n_locals) { 776 815 if (n_locals <= 0) return NULL; 777 816 bool *captured = calloc((size_t)n_locals, sizeof(bool)); ··· 782 821 sv_op_t op = (sv_op_t)*ip; 783 822 int sz = sv_op_size[op]; 784 823 if (sz == 0) break; 785 - if (op == OP_CLOSURE) { 786 - uint32_t idx = sv_get_u32(ip + 1); 787 - if (idx < (uint32_t)func->const_count) { 788 - sv_func_t *child = (sv_func_t *)(uintptr_t)vdata(func->constants[idx]); 789 - for (int i = 0; i < child->upvalue_count; i++) { 790 - sv_upval_desc_t *desc = &child->upval_descs[i]; 791 - if (desc->is_local) { 792 - int li = (int)desc->index - func->param_count; 793 - if (li >= 0 && li < n_locals) 794 - captured[li] = true; 795 - } 796 - } 797 - } 824 + sv_func_t *child = scan_closure_child(func, ip); 825 + if (!child) { 826 + ip += sz; 827 + continue; 828 + } 829 + 830 + for (int i = 0; i < child->upvalue_count; i++) { 831 + sv_upval_desc_t *desc = &child->upval_descs[i]; 832 + if (!desc->is_local) continue; 833 + 834 + int li = (int)desc->index - func->param_count; 835 + if (li < 0 || li >= n_locals) continue; 836 + captured[li] = true; 798 837 } 799 838 ip += sz; 800 839 } 801 840 return captured; 802 841 } 803 842 843 + static bool *scan_captured_params(sv_func_t *func) { 844 + int param_count = func ? func->param_count : 0; 845 + if (param_count <= 0) return NULL; 846 + bool *captured = calloc((size_t)param_count, sizeof(bool)); 847 + if (!captured) return NULL; 848 + 849 + uint8_t *ip = func->code; 850 + uint8_t *end = func->code + func->code_len; 851 + while (ip < end) { 852 + sv_op_t op = (sv_op_t)*ip; 853 + int sz = sv_op_size[op]; 854 + if (sz == 0) break; 855 + sv_func_t *child = scan_closure_child(func, ip); 856 + if (!child) { 857 + ip += sz; 858 + continue; 859 + } 860 + 861 + for (int i = 0; i < child->upvalue_count; i++) { 862 + sv_upval_desc_t *desc = &child->upval_descs[i]; 863 + if (!desc->is_local) continue; 864 + if (desc->index >= (uint16_t)param_count) continue; 865 + captured[desc->index] = true; 866 + } 867 + ip += sz; 868 + } 869 + 870 + return captured; 871 + } 872 + 804 873 805 874 #define JIT_INLINE_MAX_BYTECODE 128 806 875 ··· 1645 1714 bool needs_inc_local; 1646 1715 bool needs_args_buf; 1647 1716 bool needs_close_upval; 1648 - bool needs_args_norm; 1649 1717 bool needs_tco_args; 1650 1718 bool needs_ic_epoch; 1651 1719 } jit_features_t; ··· 1684 1752 case OP_CLOSE_UPVAL: case OP_CLOSURE: 1685 1753 f.needs_close_upval = true; 1686 1754 break; 1687 - case OP_GET_ARG: 1688 1755 case OP_SET_ARG: 1689 - f.needs_args_norm = true; 1756 + f.needs_bailout = true; 1690 1757 break; 1691 1758 case OP_GET_FIELD: case OP_GET_FIELD2: case OP_PUT_FIELD: 1692 1759 case OP_INSTANCEOF: case OP_CALL_IS_PROTO: ··· 1754 1821 case OP_INC_LOCAL: case OP_DEC_LOCAL: case OP_ADD_LOCAL: 1755 1822 case OP_TO_PROPKEY: 1756 1823 case OP_RETURN: case OP_RETURN_UNDEF: 1757 - case OP_CLOSURE: case OP_SET_NAME: 1824 + case OP_SET_NAME: 1758 1825 case OP_TRY_PUSH: case OP_TRY_POP: 1759 1826 case OP_THROW: case OP_THROW_ERROR: 1760 1827 case OP_CATCH: case OP_NIP_CATCH: 1761 1828 case OP_NOP: case OP_HALT: 1762 1829 case OP_LINE_NUM: case OP_COL_NUM: case OP_LABEL: 1763 1830 break; 1831 + case OP_CLOSURE: { 1832 + uint32_t idx = sv_get_u32(ip + 1); 1833 + if (idx >= (uint32_t)func->const_count) return false; 1834 + ant_value_t cv = func->constants[idx]; 1835 + if (vtype(cv) != T_FUNC) return false; 1836 + break; 1837 + } 1764 1838 case OP_SPECIAL_OBJ: 1765 1839 if (sv_get_u8(ip + 1) != 1 && sv_get_u8(ip + 1) != 3) { 1766 1840 if (sv_jit_warn_unlikely) ··· 1924 1998 1925 1999 MIR_type_t cl_ret = MIR_JSVAL; 1926 2000 MIR_item_t closure_proto = MIR_new_proto(ctx, "closure_proto", 1927 - 1, &cl_ret, 9, 2001 + 1, &cl_ret, 7, 1928 2002 MIR_T_I64, "vm", 1929 2003 MIR_T_I64, "js", 1930 2004 MIR_T_P, "parent", 1931 2005 MIR_JSVAL, "this_val", 1932 - MIR_T_P, "args", 1933 - MIR_T_I32, "argc", 1934 - MIR_T_I32, "const_idx", 1935 - MIR_T_P, "locals", 1936 - MIR_T_I32, "n_locals"); 2006 + MIR_T_P, "slots", 2007 + MIR_T_I32, "slot_count", 2008 + MIR_T_I32, "const_idx"); 1937 2009 1938 2010 MIR_item_t close_upval_proto = MIR_new_proto(ctx, "close_upval_proto", 1939 2011 0, NULL, 4, 1940 2012 MIR_T_I64, "vm", 1941 2013 MIR_T_I32, "slot_idx", 1942 - MIR_T_P, "locals", 1943 - MIR_T_I32, "n_locals"); 2014 + MIR_T_P, "slots", 2015 + MIR_T_I32, "slot_count"); 1944 2016 1945 2017 MIR_item_t set_name_proto = MIR_new_proto(ctx, "sn_proto", 1946 2018 0, NULL, 5, ··· 2050 2122 MIR_item_t imp_call = MIR_new_import(ctx, "jit_helper_call"); 2051 2123 MIR_item_t imp_apply = MIR_new_import(ctx, "jit_helper_apply"); 2052 2124 MIR_item_t imp_rest = MIR_new_import(ctx, "jit_helper_rest"); 2053 - MIR_item_t imp_tov = MIR_new_import(ctx, "jit_helper_tov"); 2054 2125 MIR_item_t imp_special_obj = MIR_new_import(ctx, "jit_helper_special_obj"); 2055 2126 MIR_item_t imp_gg = MIR_new_import(ctx, "jit_helper_get_global"); 2056 2127 MIR_item_t imp_get_field = MIR_new_import(ctx, "jit_helper_get_field"); ··· 2093 2164 MIR_item_t imp_set_name = MIR_new_import(ctx, "jit_helper_set_name"); 2094 2165 MIR_item_t imp_stack_ovf = MIR_new_import(ctx, "jit_helper_stack_overflow"); 2095 2166 MIR_item_t imp_stack_ovf_err = MIR_new_import(ctx, "jit_helper_stack_overflow_error"); 2096 - (void)imp_tov; 2097 2167 2098 2168 MIR_item_t jit_func = MIR_new_func(ctx, fname, 2099 2169 1, &ret_type, ··· 2260 2330 MIR_reg_t r_bailout_sp = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "bail_sp"); 2261 2331 MIR_label_t bailout_tramp = needs_bailout ? MIR_new_label(ctx) : NULL; 2262 2332 2263 - bool needs_lbuf = needs_bailout || feat.needs_close_upval; 2264 - MIR_reg_t r_lbuf = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "lbuf"); 2265 - if (needs_lbuf && n_locals > 0) { 2266 - MIR_append_insn(ctx, jit_func, 2267 - MIR_new_insn(ctx, MIR_ALLOCA, 2268 - MIR_new_reg_op(ctx, r_lbuf), 2269 - MIR_new_uint_op(ctx, (uint64_t)n_locals * sizeof(ant_value_t)))); 2270 - } else { 2271 - mir_load_imm(ctx, jit_func, r_lbuf, 0); 2272 - } 2273 - 2333 + int param_count = func->param_count; 2334 + bool *captured_params = scan_captured_params(func); 2274 2335 bool *captured_locals = scan_captured_locals(func, n_locals); 2336 + bool has_captured_params = false; 2275 2337 bool has_captures = false; 2338 + if (captured_params) { 2339 + for (int i = 0; i < param_count; i++) 2340 + if (captured_params[i]) { has_captured_params = true; break; } 2341 + } 2276 2342 if (captured_locals) { 2277 2343 for (int i = 0; i < n_locals; i++) 2278 2344 if (captured_locals[i]) { has_captures = true; break; } 2279 2345 } 2280 - if (has_captures) { 2281 - for (int i = 0; i < n_locals; i++) { 2282 - if (captured_locals[i]) 2283 - MIR_append_insn(ctx, jit_func, 2284 - MIR_new_insn(ctx, MIR_MOV, 2285 - MIR_new_mem_op(ctx, MIR_T_I64, 2286 - (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1), 2287 - MIR_new_uint_op(ctx, mkval(T_UNDEF, 0)))); 2288 - } 2346 + bool has_captured_slots = has_captured_params || has_captures; 2347 + int captured_slot_count = param_count + n_locals; 2348 + 2349 + if (has_captured_params && needs_bailout) { 2350 + free(vs.regs); free(vs.known_func); free(vs.d_regs); free(vs.slot_type); 2351 + free(vs.known_const); free(vs.has_const); 2352 + free(local_regs); free(local_d_regs); free(known_func_locals); free(known_type_locals); 2353 + free(captured_params); free(captured_locals); 2354 + MIR_finish_func(ctx); MIR_finish_module(ctx); func->jit_compiling = false; return NULL; 2289 2355 } 2290 2356 2291 - int param_count = func->param_count; 2292 - if (feat.needs_tco_args && param_count > 0) { 2357 + MIR_reg_t r_slotbuf = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "slotbuf"); 2358 + if (has_captured_slots && captured_slot_count > 0) { 2293 2359 MIR_append_insn(ctx, jit_func, 2294 2360 MIR_new_insn(ctx, MIR_ALLOCA, 2295 - MIR_new_reg_op(ctx, r_tco_args), 2296 - MIR_new_uint_op(ctx, (uint64_t)param_count * sizeof(ant_value_t)))); 2297 - } else mir_load_imm(ctx, jit_func, r_tco_args, 0); 2298 - if (param_count > 0 && feat.needs_args_norm) { 2299 - MIR_label_t args_ok = MIR_new_label(ctx); 2300 - MIR_append_insn(ctx, jit_func, 2301 - MIR_new_insn(ctx, MIR_UBGE, 2302 - MIR_new_label_op(ctx, args_ok), 2303 - MIR_new_reg_op(ctx, r_argc), 2304 - MIR_new_int_op(ctx, (int64_t)param_count))); 2305 - MIR_reg_t r_arg_local = MIR_new_func_reg(ctx, jit_func->u.func, 2306 - MIR_T_I64, "arg_local"); 2307 - MIR_append_insn(ctx, jit_func, 2308 - MIR_new_insn(ctx, MIR_ALLOCA, 2309 - MIR_new_reg_op(ctx, r_arg_local), 2310 - MIR_new_uint_op(ctx, (uint64_t)param_count * sizeof(ant_value_t)))); 2311 - for (int i = 0; i < param_count; i++) 2361 + MIR_new_reg_op(ctx, r_slotbuf), 2362 + MIR_new_uint_op(ctx, (uint64_t)captured_slot_count * sizeof(ant_value_t)))); 2363 + for (int i = 0; i < param_count; i++) { 2364 + MIR_label_t arg_present = MIR_new_label(ctx); 2365 + MIR_label_t arg_done = MIR_new_label(ctx); 2366 + MIR_append_insn(ctx, jit_func, 2367 + MIR_new_insn(ctx, MIR_UBGT, 2368 + MIR_new_label_op(ctx, arg_present), 2369 + MIR_new_reg_op(ctx, r_argc), 2370 + MIR_new_int_op(ctx, (int64_t)i))); 2312 2371 MIR_append_insn(ctx, jit_func, 2313 2372 MIR_new_insn(ctx, MIR_MOV, 2314 2373 MIR_new_mem_op(ctx, MIR_T_I64, 2315 - (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_arg_local, 0, 1), 2374 + (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_slotbuf, 0, 1), 2316 2375 MIR_new_uint_op(ctx, mkval(T_UNDEF, 0)))); 2317 - for (int i = 0; i < param_count; i++) { 2318 - MIR_label_t copy_skip = MIR_new_label(ctx); 2319 2376 MIR_append_insn(ctx, jit_func, 2320 - MIR_new_insn(ctx, MIR_UBLE, 2321 - MIR_new_label_op(ctx, copy_skip), 2322 - MIR_new_reg_op(ctx, r_argc), 2323 - MIR_new_int_op(ctx, (int64_t)i))); 2377 + MIR_new_insn(ctx, MIR_JMP, 2378 + MIR_new_label_op(ctx, arg_done))); 2379 + MIR_append_insn(ctx, jit_func, arg_present); 2324 2380 MIR_append_insn(ctx, jit_func, 2325 2381 MIR_new_insn(ctx, MIR_MOV, 2326 2382 MIR_new_mem_op(ctx, MIR_T_I64, 2327 - (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_arg_local, 0, 1), 2383 + (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_slotbuf, 0, 1), 2328 2384 MIR_new_mem_op(ctx, MIR_T_I64, 2329 2385 (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args, 0, 1))); 2330 - MIR_append_insn(ctx, jit_func, copy_skip); 2386 + MIR_append_insn(ctx, jit_func, arg_done); 2331 2387 } 2388 + for (int i = 0; i < n_locals; i++) 2389 + MIR_append_insn(ctx, jit_func, 2390 + MIR_new_insn(ctx, MIR_MOV, 2391 + MIR_new_mem_op(ctx, MIR_T_I64, 2392 + (MIR_disp_t)((param_count + i) * (int)sizeof(ant_value_t)), r_slotbuf, 0, 1), 2393 + MIR_new_uint_op(ctx, mkval(T_UNDEF, 0)))); 2394 + } else mir_load_imm(ctx, jit_func, r_slotbuf, 0); 2395 + 2396 + bool needs_lbuf = needs_bailout || feat.needs_close_upval || has_captured_slots; 2397 + MIR_reg_t r_lbuf = MIR_new_func_reg(ctx, jit_func->u.func, MIR_T_I64, "lbuf"); 2398 + if (has_captured_slots && n_locals > 0) { 2332 2399 MIR_append_insn(ctx, jit_func, 2333 - MIR_new_insn(ctx, MIR_MOV, 2334 - MIR_new_reg_op(ctx, r_args), 2335 - MIR_new_reg_op(ctx, r_arg_local))); 2336 - MIR_append_insn(ctx, jit_func, args_ok); 2400 + MIR_new_insn(ctx, MIR_ADD, 2401 + MIR_new_reg_op(ctx, r_lbuf), 2402 + MIR_new_reg_op(ctx, r_slotbuf), 2403 + MIR_new_int_op(ctx, (int64_t)param_count * (int64_t)sizeof(ant_value_t)))); 2404 + } else if (needs_lbuf && n_locals > 0) { 2405 + MIR_append_insn(ctx, jit_func, 2406 + MIR_new_insn(ctx, MIR_ALLOCA, 2407 + MIR_new_reg_op(ctx, r_lbuf), 2408 + MIR_new_uint_op(ctx, (uint64_t)n_locals * sizeof(ant_value_t)))); 2409 + } else { 2410 + mir_load_imm(ctx, jit_func, r_lbuf, 0); 2337 2411 } 2338 2412 2413 + if (feat.needs_tco_args && param_count > 0) { 2414 + MIR_append_insn(ctx, jit_func, 2415 + MIR_new_insn(ctx, MIR_ALLOCA, 2416 + MIR_new_reg_op(ctx, r_tco_args), 2417 + MIR_new_uint_op(ctx, (uint64_t)param_count * sizeof(ant_value_t)))); 2418 + } else mir_load_imm(ctx, jit_func, r_tco_args, 0); 2339 2419 jit_label_map_t lm = {0}; 2340 2420 scan_branch_targets(func, &lm, ctx); 2341 2421 ··· 2549 2629 case OP_GET_ARG: { 2550 2630 uint16_t idx = sv_get_u16(ip + 1); 2551 2631 MIR_reg_t dst = vstack_push(&vs); 2552 - MIR_append_insn(ctx, jit_func, 2553 - MIR_new_insn(ctx, MIR_MOV, 2554 - MIR_new_reg_op(ctx, dst), 2555 - MIR_new_mem_op(ctx, MIR_JSVAL, 2556 - (MIR_disp_t)(idx * (int)sizeof(ant_value_t)), 2557 - r_args, 0, 1))); 2632 + if (has_captured_slots && idx < (uint16_t)param_count) { 2633 + MIR_append_insn(ctx, jit_func, 2634 + MIR_new_insn(ctx, MIR_MOV, 2635 + MIR_new_reg_op(ctx, dst), 2636 + MIR_new_mem_op(ctx, MIR_JSVAL, 2637 + (MIR_disp_t)(idx * (int)sizeof(ant_value_t)), 2638 + r_slotbuf, 0, 1))); 2639 + } else { 2640 + MIR_label_t arg_in_range = MIR_new_label(ctx); 2641 + MIR_label_t arg_done = MIR_new_label(ctx); 2642 + MIR_append_insn(ctx, jit_func, 2643 + MIR_new_insn(ctx, MIR_UBGT, 2644 + MIR_new_label_op(ctx, arg_in_range), 2645 + MIR_new_reg_op(ctx, r_argc), 2646 + MIR_new_int_op(ctx, (int64_t)idx))); 2647 + mir_load_imm(ctx, jit_func, dst, mkval(T_UNDEF, 0)); 2648 + MIR_append_insn(ctx, jit_func, 2649 + MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, arg_done))); 2650 + MIR_append_insn(ctx, jit_func, arg_in_range); 2651 + MIR_append_insn(ctx, jit_func, 2652 + MIR_new_insn(ctx, MIR_MOV, 2653 + MIR_new_reg_op(ctx, dst), 2654 + MIR_new_mem_op(ctx, MIR_JSVAL, 2655 + (MIR_disp_t)(idx * (int)sizeof(ant_value_t)), 2656 + r_args, 0, 1))); 2657 + MIR_append_insn(ctx, jit_func, arg_done); 2658 + } 2558 2659 break; 2559 2660 } 2560 2661 ··· 2562 2663 uint16_t idx = sv_get_u16(ip + 1); 2563 2664 vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot); 2564 2665 MIR_reg_t val = vstack_top(&vs); 2565 - MIR_append_insn(ctx, jit_func, 2566 - MIR_new_insn(ctx, MIR_MOV, 2567 - MIR_new_mem_op(ctx, MIR_JSVAL, 2568 - (MIR_disp_t)(idx * (int)sizeof(ant_value_t)), 2569 - r_args, 0, 1), 2570 - MIR_new_reg_op(ctx, val))); 2666 + if (has_captured_slots && idx < (uint16_t)param_count) { 2667 + MIR_append_insn(ctx, jit_func, 2668 + MIR_new_insn(ctx, MIR_MOV, 2669 + MIR_new_mem_op(ctx, MIR_JSVAL, 2670 + (MIR_disp_t)(idx * (int)sizeof(ant_value_t)), 2671 + r_slotbuf, 0, 1), 2672 + MIR_new_reg_op(ctx, val))); 2673 + if (idx < (uint16_t)param_count) { 2674 + MIR_label_t arg_in_range = MIR_new_label(ctx); 2675 + MIR_label_t arg_done = MIR_new_label(ctx); 2676 + MIR_append_insn(ctx, jit_func, 2677 + MIR_new_insn(ctx, MIR_UBGT, 2678 + MIR_new_label_op(ctx, arg_in_range), 2679 + MIR_new_reg_op(ctx, r_argc), 2680 + MIR_new_int_op(ctx, (int64_t)idx))); 2681 + MIR_append_insn(ctx, jit_func, 2682 + MIR_new_insn(ctx, MIR_JMP, MIR_new_label_op(ctx, arg_done))); 2683 + MIR_append_insn(ctx, jit_func, arg_in_range); 2684 + MIR_append_insn(ctx, jit_func, 2685 + MIR_new_insn(ctx, MIR_MOV, 2686 + MIR_new_mem_op(ctx, MIR_JSVAL, 2687 + (MIR_disp_t)(idx * (int)sizeof(ant_value_t)), 2688 + r_args, 0, 1), 2689 + MIR_new_reg_op(ctx, val))); 2690 + MIR_append_insn(ctx, jit_func, arg_done); 2691 + } 2692 + } else { 2693 + MIR_label_t arg_in_range = MIR_new_label(ctx); 2694 + MIR_append_insn(ctx, jit_func, 2695 + MIR_new_insn(ctx, MIR_UBGT, 2696 + MIR_new_label_op(ctx, arg_in_range), 2697 + MIR_new_reg_op(ctx, r_argc), 2698 + MIR_new_int_op(ctx, (int64_t)idx))); 2699 + mir_load_imm(ctx, jit_func, r_bailout_val, (uint64_t)SV_JIT_BAILOUT); 2700 + mir_emit_bailout_check(ctx, jit_func, r_bailout_val, 2701 + 0, r_bailout_off, bc_off, 2702 + r_bailout_sp, vs.sp, bailout_tramp, 2703 + r_args_buf, &vs, local_regs, n_locals, r_lbuf, r_d_slot); 2704 + MIR_append_insn(ctx, jit_func, arg_in_range); 2705 + MIR_append_insn(ctx, jit_func, 2706 + MIR_new_insn(ctx, MIR_MOV, 2707 + MIR_new_mem_op(ctx, MIR_JSVAL, 2708 + (MIR_disp_t)(idx * (int)sizeof(ant_value_t)), 2709 + r_args, 0, 1), 2710 + MIR_new_reg_op(ctx, val))); 2711 + } 2571 2712 break; 2572 2713 } 2573 2714 ··· 4360 4501 if (is_tail && jit_try_depth == 0) { 4361 4502 mir_emit_self_tail(ctx, jit_func, (int)call_argc, param_count, 4362 4503 r_tco_args, r_arg_arr, r_args, r_argc, 4363 - local_regs, n_locals, has_captures, 4504 + local_regs, n_locals, has_captured_slots, r_slotbuf, 4505 + has_captures, 4364 4506 captured_locals, r_lbuf, self_tail_entry); 4365 4507 break; 4366 4508 } ··· 4482 4624 if (is_tail && jit_try_depth == 0) { 4483 4625 mir_emit_self_tail(ctx, jit_func, (int)call_argc, param_count, 4484 4626 r_tco_args, r_arg_arr, r_args, r_argc, 4485 - local_regs, n_locals, has_captures, 4627 + local_regs, n_locals, has_captured_slots, r_slotbuf, 4628 + has_captures, 4486 4629 captured_locals, r_lbuf, self_tail_entry); 4487 4630 } else { 4488 4631 MIR_append_insn(ctx, jit_func, ··· 4730 4873 4731 4874 case OP_CLOSE_UPVAL: { 4732 4875 uint16_t idx = sv_get_u16(ip + 1); 4733 - if (n_locals > 0) { 4876 + if (n_locals > 0 && r_lbuf) { 4734 4877 for (int i = 0; i < n_locals; i++) 4735 4878 MIR_append_insn(ctx, jit_func, 4736 4879 MIR_new_insn(ctx, MIR_MOV, ··· 4743 4886 MIR_new_ref_op(ctx, close_upval_proto), 4744 4887 MIR_new_ref_op(ctx, imp_close_upval), 4745 4888 MIR_new_reg_op(ctx, r_vm), 4746 - MIR_new_uint_op(ctx, (uint64_t)idx), 4747 - MIR_new_reg_op(ctx, r_lbuf), 4748 - MIR_new_int_op(ctx, n_locals))); 4889 + MIR_new_uint_op(ctx, has_captured_slots ? (uint64_t)idx : (uint64_t)(idx >= (uint16_t)param_count ? idx - (uint16_t)param_count : 0)), 4890 + MIR_new_reg_op(ctx, has_captured_slots ? r_slotbuf : r_lbuf), 4891 + MIR_new_int_op(ctx, has_captured_slots ? captured_slot_count : n_locals))); 4749 4892 break; 4750 4893 } 4751 4894 ··· 4790 4933 case OP_RETURN: { 4791 4934 vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot); 4792 4935 MIR_reg_t ret_val = vstack_pop(&vs); 4936 + if (has_captured_slots && captured_slot_count > 0) 4937 + MIR_append_insn(ctx, jit_func, 4938 + MIR_new_call_insn(ctx, 6, 4939 + MIR_new_ref_op(ctx, close_upval_proto), 4940 + MIR_new_ref_op(ctx, imp_close_upval), 4941 + MIR_new_reg_op(ctx, r_vm), 4942 + MIR_new_uint_op(ctx, 0), 4943 + MIR_new_reg_op(ctx, r_slotbuf), 4944 + MIR_new_int_op(ctx, captured_slot_count))); 4793 4945 MIR_append_insn(ctx, jit_func, 4794 4946 MIR_new_ret_insn(ctx, 1, MIR_new_reg_op(ctx, ret_val))); 4795 4947 break; 4796 4948 } 4797 4949 4798 4950 case OP_RETURN_UNDEF: { 4951 + if (has_captured_slots && captured_slot_count > 0) 4952 + MIR_append_insn(ctx, jit_func, 4953 + MIR_new_call_insn(ctx, 6, 4954 + MIR_new_ref_op(ctx, close_upval_proto), 4955 + MIR_new_ref_op(ctx, imp_close_upval), 4956 + MIR_new_reg_op(ctx, r_vm), 4957 + MIR_new_uint_op(ctx, 0), 4958 + MIR_new_reg_op(ctx, r_slotbuf), 4959 + MIR_new_int_op(ctx, captured_slot_count))); 4799 4960 MIR_append_insn(ctx, jit_func, 4800 4961 MIR_new_ret_insn(ctx, 1, 4801 4962 MIR_new_uint_op(ctx, mkval(T_UNDEF, 0)))); ··· 6932 7093 MIR_new_reg_op(ctx, local_regs[i]))); 6933 7094 } 6934 7095 MIR_append_insn(ctx, jit_func, 6935 - MIR_new_call_insn(ctx, 12, 7096 + MIR_new_call_insn(ctx, 10, 6936 7097 MIR_new_ref_op(ctx, closure_proto), 6937 7098 MIR_new_ref_op(ctx, imp_closure), 6938 7099 MIR_new_reg_op(ctx, dst), ··· 6940 7101 MIR_new_reg_op(ctx, r_js), 6941 7102 MIR_new_reg_op(ctx, r_closure), 6942 7103 MIR_new_reg_op(ctx, r_this), 6943 - MIR_new_reg_op(ctx, r_args), 6944 - MIR_new_reg_op(ctx, r_argc), 6945 - MIR_new_uint_op(ctx, (uint64_t)idx), 6946 - MIR_new_reg_op(ctx, r_lbuf), 6947 - MIR_new_int_op(ctx, n_locals))); 7104 + MIR_new_reg_op(ctx, r_slotbuf), 7105 + MIR_new_int_op(ctx, captured_slot_count), 7106 + MIR_new_uint_op(ctx, (uint64_t)idx))); 6948 7107 break; 6949 7108 } 6950 7109 ··· 7001 7160 free(local_d_regs); 7002 7161 free(known_func_locals); 7003 7162 free(known_type_locals); 7163 + free(captured_params); 7004 7164 free(captured_locals); 7005 7165 7006 7166 if (!ok) return NULL;
+90
tests/bench_jit_missing_params.cjs
··· 1 + const now = () => (typeof performance !== 'undefined' && performance.now ? performance.now() : Date.now()); 2 + 3 + function readScale() { 4 + if (typeof process === 'undefined' || !process || !process.argv) return 1; 5 + const raw = Number(process.argv[2]); 6 + return Number.isFinite(raw) && raw > 0 ? raw : 1; 7 + } 8 + 9 + const SCALE = readScale(); 10 + const REPEATS = 5; 11 + 12 + function bench(name, rounds, fn) { 13 + fn(Math.max(1, (rounds / 8) | 0)); 14 + 15 + const samples = []; 16 + let out = 0; 17 + for (let i = 0; i < REPEATS; i++) { 18 + const t0 = now(); 19 + out = fn(rounds); 20 + samples.push(now() - t0); 21 + } 22 + 23 + let best = samples[0]; 24 + let sum = 0; 25 + for (let i = 0; i < samples.length; i++) { 26 + if (samples[i] < best) best = samples[i]; 27 + sum += samples[i]; 28 + } 29 + 30 + const avg = sum / samples.length; 31 + console.log(`${name}: best ${best.toFixed(2)} ms, avg ${avg.toFixed(2)} ms, out ${out}`); 32 + return out; 33 + } 34 + 35 + function hotMissingParamWrite(rounds) { 36 + function f(val, options) { 37 + options = options || {}; 38 + if (typeof val === 'number') return options.long ? 2 : 3; 39 + return 0; 40 + } 41 + 42 + let sum = 0; 43 + for (let i = 0; i < rounds; i++) sum += f(i); 44 + return sum; 45 + } 46 + 47 + function hotPresentParamWrite(rounds) { 48 + function f(val, options) { 49 + options = options || {}; 50 + if (typeof val === 'number') return options.long ? 2 : 3; 51 + return 0; 52 + } 53 + 54 + const shared = {}; 55 + let sum = 0; 56 + for (let i = 0; i < rounds; i++) sum += f(i, shared); 57 + return sum; 58 + } 59 + 60 + function hotNoParamWrite(rounds) { 61 + function f(val, options) { 62 + if (!options) options = {}; 63 + if (typeof val === 'number') return options.long ? 2 : 3; 64 + return 0; 65 + } 66 + 67 + const shared = {}; 68 + let sum = 0; 69 + for (let i = 0; i < rounds; i++) sum += f(i, shared); 70 + return sum; 71 + } 72 + 73 + function hotLocalWrite(rounds) { 74 + function f(val, options) { 75 + let opts = options || {}; 76 + if (typeof val === 'number') return opts.long ? 2 : 3; 77 + return 0; 78 + } 79 + 80 + let sum = 0; 81 + for (let i = 0; i < rounds; i++) sum += f(i); 82 + return sum; 83 + } 84 + 85 + const rounds = 8_000_000 * SCALE; 86 + console.log(`jit missing-parameter benchmark (${rounds} rounds)`); 87 + bench('missing param write', rounds, hotMissingParamWrite); 88 + bench('present param write', rounds, hotPresentParamWrite); 89 + bench('no param write', rounds, hotNoParamWrite); 90 + bench('local alias write', rounds, hotLocalWrite);
+25
tests/test_jit_typeof_bailout_arg_resume.cjs
··· 1 + let failed = 0; 2 + 3 + function f(val, options) { 4 + options = options || {}; 5 + const type = typeof val; 6 + if (type === 'string' && val.length > 0) { 7 + return 1; 8 + } 9 + if (type === 'number' && isFinite(val)) { 10 + return options.long ? 2 : 3; 11 + } 12 + return 0; 13 + } 14 + 15 + try { 16 + for (let i = 0; i < 300; i++) { 17 + const got = f(42); 18 + if (got !== 3) throw new Error('unexpected result at iteration ' + i + ': ' + got); 19 + } 20 + } catch (e) { 21 + failed++; 22 + console.log('fail:', e && e.message ? e.message : e); 23 + } 24 + 25 + if (failed > 0) throw new Error('test_jit_typeof_bailout_arg_resume failed');