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.

fix: mir leak when unloading on bailout

+128 -48
+55 -2
include/silver/engine.h
··· 5 5 #include "internal.h" 6 6 #include "runtime.h" 7 7 #include "errors.h" 8 + #include "debug.h" 8 9 #include "gc/objects.h" 9 10 #include "modules/timer.h" 10 11 ··· 178 179 179 180 bool jit_compile_failed; 180 181 bool jit_compiling; 182 + 183 + uint8_t jit_bailout_count; 184 + uint32_t jit_bailout_tfb_ver; 181 185 uint32_t tfb_version; 182 186 uint32_t jit_compiled_tfb_ver; 183 187 uint8_t *type_feedback; ··· 842 846 #define SV_TFB_STR (1 << 1) 843 847 #define SV_TFB_BOOL (1 << 2) 844 848 #define SV_TFB_OTHER (1 << 3) 849 + 845 850 #define SV_TFB_CTOR_PROP_BINS 17 846 851 #define SV_TFB_CTOR_PROP_OVERFLOW_FROM (SV_TFB_CTOR_PROP_BINS - 1) 847 852 #define SV_TFB_INOBJ_SLACK_ALLOCATIONS 32 ··· 852 857 #define SV_JIT_RECOMPILE_DELAY 50 853 858 #define SV_TFB_ALLOC_THRESHOLD 2 854 859 855 - #define SV_CALL_FB_MAX_SLOTS 32 860 + #define SV_CALL_FB_MAX_SLOTS 32 861 + #define SV_JIT_BAILOUT_LIMIT 5 856 862 #define SV_CALL_FB_MISS_DISABLE 4 857 863 858 864 #define SV_JIT_RETRY_INTERP mkval(T_ERR, 1) ··· 863 869 | ((ant_value_t)T_SENTINEL << NANBOX_TYPE_SHIFT) \ 864 870 | SV_JIT_MAGIC) 865 871 872 + extern const char *const sv_op_names[OP__COUNT]; 873 + 866 874 static inline bool sv_is_jit_bailout(ant_value_t v) { 867 875 return v == SV_JIT_BAILOUT; 868 876 } ··· 875 883 if (js && js->jit_active_depth > 0) js->jit_active_depth--; 876 884 } 877 885 878 - static inline void sv_jit_on_bailout(sv_func_t *fn) { 886 + static inline void sv_jit_on_bailout_at(sv_func_t *fn, const char *reason, int bc_off) { 887 + if (!fn) return; 888 + 889 + if (fn->jit_bailout_tfb_ver != fn->tfb_version) { 890 + fn->jit_bailout_tfb_ver = fn->tfb_version; 891 + fn->jit_bailout_count = 0; 892 + } 893 + 894 + if (fn->jit_bailout_count < UINT8_MAX) 895 + fn->jit_bailout_count++; 896 + 879 897 fn->jit_code = NULL; 880 898 fn->back_edge_count = 0; 899 + 900 + if (sv_jit_warn_unlikely) { 901 + const char *op_name = "entry"; 902 + if (bc_off >= 0 && bc_off < fn->code_len) { 903 + uint8_t op = fn->code[bc_off]; 904 + if (op < OP__COUNT && sv_op_names[op]) op_name = sv_op_names[op]; 905 + } 906 + 907 + uint32_t line = 0, col = 0; 908 + (void)sv_lookup_srcpos(fn, bc_off, &line, &col); 909 + 910 + fprintf(stderr, 911 + "jit: bailout %u/%u tfb=%u func=%s op=%s bc=%d at %s:%u:%u reason=%s\n", 912 + (unsigned)fn->jit_bailout_count, (unsigned)SV_JIT_BAILOUT_LIMIT, 913 + fn->tfb_version, fn->name ? fn->name : "<anonymous>", 914 + op_name, bc_off, fn->filename ? fn->filename : "<unknown>", 915 + line, col, reason ? reason : "unknown" 916 + ); 917 + } 918 + 919 + if (fn->jit_bailout_count >= SV_JIT_BAILOUT_LIMIT) { 920 + fn->jit_compile_failed = true; 921 + fn->call_count = 0; 922 + if (sv_jit_warn_unlikely) fprintf( 923 + stderr, "jit: disabling %s after %u bailouts at tfb=%u\n", 924 + fn->name ? fn->name : "<anonymous>", 925 + (unsigned)fn->jit_bailout_count, fn->tfb_version 926 + ); 927 + return; 928 + } 929 + 881 930 fn->call_count = SV_JIT_THRESHOLD - SV_JIT_RECOMPILE_DELAY; 931 + } 932 + 933 + static inline void sv_jit_on_bailout(sv_func_t *fn) { 934 + sv_jit_on_bailout_at(fn, "direct", -1); 882 935 } 883 936 884 937 typedef ant_value_t (*sv_jit_func_t)(
+1 -1
src/silver/compiler.c
··· 5326 5326 return func; 5327 5327 } 5328 5328 5329 - static const char *sv_op_names[OP__COUNT] = { 5329 + const char *const sv_op_names[OP__COUNT] = { 5330 5330 #define OP_DEF(name, size, n_pop, n_push, f) [OP_##name] = #name, 5331 5331 #include "silver/opcode.h" 5332 5332 };
+3 -3
src/silver/glue.c
··· 546 546 return sv_vm_call(vm, js, call_func, call_this, args, argc, NULL, false); 547 547 } 548 548 549 - // TODO: dont bail out 550 549 ant_value_t jit_helper_typeof(sv_vm_t *vm, ant_t *js, ant_value_t v) { 551 - return SV_JIT_BAILOUT; 550 + const char *ts = typestr(vtype(v)); 551 + return js_mkstr(js, ts, strlen(ts)); 552 552 } 553 553 554 554 int64_t jit_helper_is_truthy(ant_t *js, ant_value_t v) { ··· 695 695 ) { 696 696 if (!closure || !closure->func) return mkval(T_ERR, 0); 697 697 sv_func_t *fn = closure->func; 698 - sv_jit_on_bailout(fn); 698 + sv_jit_on_bailout_at(fn, "resume", (int)bc_offset); 699 699 700 700 vm->jit_resume.active = true; 701 701 vm->jit_resume.ip_offset = (int)bc_offset;
+69 -42
src/silver/swarm.c
··· 20 20 #include <stdint.h> 21 21 #include <stddef.h> 22 22 23 - static const char *sv_op_name[] = { 24 - #define OP_DEF(name, size, n_pop, n_push, f) [OP_##name] = #name, 25 - #include "silver/opcode.h" 26 - }; 27 - 28 23 typedef struct { 29 24 MIR_context_t ctx; 30 25 bool externals_loaded; ··· 2039 2034 default: 2040 2035 if (sv_jit_warn_unlikely) 2041 2036 fprintf(stderr, "jit: ineligible op %s in %s\n", 2042 - (op < OP__COUNT && sv_op_name[op]) ? sv_op_name[op] : "???", 2037 + (op < OP__COUNT && sv_op_names[op]) ? sv_op_names[op] : "???", 2043 2038 func->name ? func->name : "<anonymous>"); 2044 2039 eligible = false; 2045 2040 break; ··· 2518 2513 vs.slot_type = calloc((size_t)vs.max, sizeof(uint8_t)); 2519 2514 vs.known_const = calloc((size_t)vs.max, sizeof(uint64_t)); 2520 2515 vs.has_const = calloc((size_t)vs.max, sizeof(bool)); 2516 + 2521 2517 if (!vs.regs || !vs.known_func || !vs.d_regs || !vs.slot_type || !vs.known_const || !vs.has_const) { 2522 - free(vs.regs); free(vs.known_func); free(vs.d_regs); free(vs.slot_type); 2523 - free(vs.known_const); free(vs.has_const); 2524 - MIR_finish_func(ctx); MIR_finish_module(ctx); func->jit_compiling = false; return NULL; 2518 + free(vs.regs); 2519 + free(vs.known_func); 2520 + free(vs.d_regs); 2521 + free(vs.slot_type); 2522 + free(vs.known_const); 2523 + free(vs.has_const); 2524 + 2525 + MIR_finish_func(ctx); 2526 + MIR_finish_module(ctx); 2527 + MIR_remove_module(ctx, mod); 2528 + 2529 + func->jit_compiling = false; 2530 + return NULL; 2525 2531 } 2526 2532 2527 2533 for (int i = 0; i < vs.max; i++) { ··· 2545 2551 local_d_regs = calloc((size_t)n_locals, sizeof(MIR_reg_t)); 2546 2552 known_func_locals = calloc((size_t)n_locals, sizeof(sv_func_t *)); 2547 2553 known_type_locals = calloc((size_t)n_locals, sizeof(uint8_t)); 2554 + 2548 2555 if (!local_regs || !local_d_regs || !known_func_locals || !known_type_locals) { 2549 - free(vs.regs); free(vs.known_func); free(vs.d_regs); free(vs.slot_type); 2550 - free(vs.known_const); free(vs.has_const); 2551 - free(local_regs); free(local_d_regs); free(known_func_locals); free(known_type_locals); 2552 - MIR_finish_func(ctx); MIR_finish_module(ctx); return NULL; 2556 + free(vs.regs); 2557 + free(vs.known_func); 2558 + free(vs.d_regs); 2559 + free(vs.slot_type); 2560 + free(vs.known_const); 2561 + free(vs.has_const); 2562 + free(local_regs); 2563 + free(local_d_regs); 2564 + free(known_func_locals); 2565 + free(known_type_locals); 2566 + 2567 + MIR_finish_func(ctx); 2568 + MIR_finish_module(ctx); 2569 + MIR_remove_module(ctx, mod); 2570 + 2571 + func->jit_compiling = false; 2572 + return NULL; 2553 2573 } 2574 + 2554 2575 if (func->local_types && func->local_type_count > 0) { 2555 2576 int ncopy = func->local_type_count < n_locals ? func->local_type_count : n_locals; 2556 2577 for (int i = 0; i < ncopy; i++) ··· 2668 2689 int slotbuf_count = use_unified_slotbuf ? (param_count + n_locals) : param_count; 2669 2690 2670 2691 if (has_captured_params && needs_bailout) { 2671 - free(vs.regs); free(vs.known_func); free(vs.d_regs); free(vs.slot_type); 2672 - free(vs.known_const); free(vs.has_const); 2673 - free(local_regs); free(local_d_regs); free(known_func_locals); free(known_type_locals); 2674 - free(captured_params); free(captured_locals); 2675 - MIR_finish_func(ctx); MIR_finish_module(ctx); func->jit_compiling = false; return NULL; 2692 + free(vs.regs); 2693 + free(vs.known_func); 2694 + free(vs.d_regs); 2695 + free(vs.slot_type); 2696 + free(vs.known_const); 2697 + free(vs.has_const); 2698 + free(local_regs); 2699 + free(local_d_regs); 2700 + free(known_func_locals); 2701 + free(known_type_locals); 2702 + free(captured_params); 2703 + free(captured_locals); 2704 + 2705 + MIR_finish_func(ctx); 2706 + MIR_finish_module(ctx); 2707 + MIR_remove_module(ctx, mod); 2708 + 2709 + func->jit_compile_failed = true; 2710 + func->jit_compiling = false; 2711 + 2712 + return NULL; 2676 2713 } 2677 2714 2678 2715 MIR_reg_t r_slotbuf = r_tmp2; ··· 7383 7420 } 7384 7421 7385 7422 case OP_TYPEOF: { 7423 + vstack_ensure_boxed(&vs, vs.sp - 1, ctx, jit_func, r_d_slot); 7386 7424 MIR_reg_t rs = vstack_top(&vs); 7387 - for (int i = 0; i < vs.sp; i++) 7388 - MIR_append_insn(ctx, jit_func, 7389 - MIR_new_insn(ctx, MIR_MOV, 7390 - MIR_new_mem_op(ctx, MIR_T_I64, 7391 - (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_args_buf, 0, 1), 7392 - MIR_new_reg_op(ctx, vs.regs[i]))); 7393 - for (int i = 0; i < n_locals; i++) 7394 - MIR_append_insn(ctx, jit_func, 7395 - MIR_new_insn(ctx, MIR_MOV, 7396 - MIR_new_mem_op(ctx, MIR_T_I64, 7397 - (MIR_disp_t)(i * (int)sizeof(ant_value_t)), r_lbuf, 0, 1), 7398 - MIR_new_reg_op(ctx, local_regs[i]))); 7399 7425 MIR_append_insn(ctx, jit_func, 7400 - MIR_new_insn(ctx, MIR_MOV, 7401 - MIR_new_reg_op(ctx, r_bailout_off), 7402 - MIR_new_int_op(ctx, bc_off))); 7403 - MIR_append_insn(ctx, jit_func, 7404 - MIR_new_insn(ctx, MIR_MOV, 7405 - MIR_new_reg_op(ctx, r_bailout_sp), 7406 - MIR_new_int_op(ctx, vs.sp))); 7407 - MIR_append_insn(ctx, jit_func, 7408 - MIR_new_insn(ctx, MIR_JMP, 7409 - MIR_new_label_op(ctx, bailout_tramp))); 7410 - (void)rs; (void)imp_typeof; 7426 + MIR_new_call_insn(ctx, 6, 7427 + MIR_new_ref_op(ctx, helper1_proto), 7428 + MIR_new_ref_op(ctx, imp_typeof), 7429 + MIR_new_reg_op(ctx, rs), 7430 + MIR_new_reg_op(ctx, r_vm), 7431 + MIR_new_reg_op(ctx, r_js), 7432 + MIR_new_reg_op(ctx, rs))); 7411 7433 break; 7412 7434 } 7413 7435 ··· 8214 8236 free(captured_params); 8215 8237 free(captured_locals); 8216 8238 8217 - if (!ok) return NULL; 8239 + if (!ok) { 8240 + MIR_remove_module(ctx, mod); 8241 + func->jit_compile_failed = true; 8242 + func->jit_compiling = false; 8243 + return NULL; 8244 + } 8218 8245 8219 8246 MIR_load_module(ctx, mod); 8220 8247 MIR_link(ctx, MIR_set_gen_interface, NULL);