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 super lookup for extracted static methods and constructors

+158 -15
+1
include/silver/engine.h
··· 154 154 bool has_await; 155 155 bool is_generator; 156 156 bool is_method; 157 + bool is_static; 157 158 bool is_tla; 158 159 uint64_t gc_epoch; 159 160
+3
src/silver/compiler.c
··· 3962 3962 bool is_fn = is_class_method_def(m); 3963 3963 3964 3964 if (is_fn) { 3965 + if (is_static) m->right->flags |= FN_STATIC; 3965 3966 compile_func_expr(c, m->right); 3966 3967 emit_get_local(c, home_local); 3967 3968 emit_op(c, OP_SET_HOME_OBJ); ··· 4594 4595 func->has_await = false; 4595 4596 func->is_generator = !!(node->flags & FN_GENERATOR); 4596 4597 func->is_method = !!(node->flags & FN_METHOD); 4598 + func->is_static = !!(node->flags & FN_STATIC); 4597 4599 func->is_tla = comp.is_tla; 4598 4600 func->filename = enclosing->filename ? enclosing->filename : enclosing->js->filename; 4599 4601 func->source_line = (int)node->line; 4602 + 4600 4603 if (node->str && node->len > 0) { 4601 4604 char *name = code_arena_bump(node->len + 1); 4602 4605 memcpy(name, node->str, node->len);
+3 -3
src/silver/engine.c
··· 1020 1020 L_PUT_PRIVATE: { sv_op_put_private(vm, js); NEXT(1); } 1021 1021 L_DEF_PRIVATE: { sv_op_def_private(vm, js); NEXT(1); } 1022 1022 1023 - L_GET_SUPER: { sv_op_get_super(vm, js); NEXT(1); } 1024 - L_GET_SUPER_VAL: { sv_op_get_super_val(vm, js); NEXT(1); } 1025 - L_PUT_SUPER_VAL: { sv_op_put_super_val(vm, js); NEXT(1); } 1023 + L_GET_SUPER: { sv_op_get_super(vm, js); NEXT(1); } 1024 + L_GET_SUPER_VAL: { sv_op_get_super_val(vm, js, frame); NEXT(1); } 1025 + L_PUT_SUPER_VAL: { sv_op_put_super_val(vm, js); NEXT(1); } 1026 1026 1027 1027 L_ADD: { 1028 1028 ant_value_t r = vm->stack[vm->sp - 1], l = vm->stack[vm->sp - 2];
+11 -5
src/silver/ops/super.h
··· 8 8 vm->stack[vm->sp - 1] = js_get_proto(js, obj); 9 9 } 10 10 11 - static inline void sv_op_get_super_val(sv_vm_t *vm, ant_t *js) { 11 + static inline void sv_op_get_super_val(sv_vm_t *vm, ant_t *js, sv_frame_t *frame) { 12 12 ant_value_t prop = vm->stack[--vm->sp]; 13 13 ant_value_t obj = vm->stack[--vm->sp]; 14 14 ant_value_t receiver = vm->stack[--vm->sp]; 15 - ant_value_t proto; 16 15 17 - if (vtype(obj) == T_FUNC && vtype(receiver) != T_FUNC) { 18 - proto = js_getprop_fallback(js, obj, "prototype"); 19 - } else proto = js_get_proto(js, obj); 16 + sv_func_t *current_func = frame ? frame->func : NULL; 17 + bool use_ctor_prototype = 18 + vtype(obj) == T_FUNC && 19 + vtype(receiver) != T_FUNC && 20 + current_func && 21 + !current_func->is_static; 22 + 23 + ant_value_t proto; 24 + if (use_ctor_prototype) proto = js_getprop_fallback(js, obj, "prototype"); 25 + else proto = js_get_proto(js, obj); 20 26 21 27 if (vtype(prop) == T_SYMBOL) { 22 28 vm->stack[vm->sp++] = js_get_sym_with_receiver(js, proto, prop, receiver);
+27 -7
src/silver/swarm.c
··· 1053 1053 case OP_JMP_TRUE_PEEK: case OP_JMP_FALSE_PEEK: 1054 1054 case OP_RETURN: case OP_RETURN_UNDEF: 1055 1055 case OP_GET_FIELD: case OP_GET_FIELD2: case OP_GET_GLOBAL: 1056 + case OP_NOP: case OP_LINE_NUM: case OP_COL_NUM: case OP_LABEL: 1057 + break; 1056 1058 case OP_SPECIAL_OBJ: 1057 1059 // OP_SPECIAL_OBJ(0) materializes `arguments`. keep these functions on 1058 1060 // the interpreter until JIT routes a real per-call activation/object 1059 1061 // with matching lifetime and semantics. 1060 1062 if (sv_get_u8(ip + 1) == 0) return false; 1061 - break; 1062 - case OP_NOP: case OP_LINE_NUM: case OP_COL_NUM: case OP_LABEL: 1063 1063 break; 1064 1064 default: 1065 1065 return false; ··· 1130 1130 MIR_reg_t result, MIR_label_t slow, MIR_label_t join, 1131 1131 MIR_reg_t r_bool, MIR_reg_t *p_d_slot, int id, 1132 1132 MIR_reg_t r_inl_closure, MIR_reg_t r_inl_this, 1133 + MIR_reg_t r_inl_new_target, MIR_reg_t r_inl_super, 1133 1134 MIR_reg_t r_vm, MIR_reg_t r_js, 1134 1135 MIR_item_t helper2_proto, MIR_item_t imp_seq, 1135 1136 MIR_item_t imp_sne, MIR_item_t imp_eq, MIR_item_t imp_ne, ··· 1811 1812 uint8_t which = sv_get_u8(ip + 1); 1812 1813 MIR_reg_t dst = inl_vs[isp++]; 1813 1814 if (which == 1) { 1814 - mir_load_imm(ctx, jit_func, dst, mkval(T_UNDEF, 0)); 1815 + MIR_append_insn(ctx, jit_func, 1816 + MIR_new_insn(ctx, MIR_MOV, 1817 + MIR_new_reg_op(ctx, dst), 1818 + MIR_new_reg_op(ctx, r_inl_new_target))); 1815 1819 } else if (which == 2) { 1816 1820 MIR_append_insn(ctx, jit_func, 1817 1821 MIR_new_insn(ctx, MIR_MOV, 1818 1822 MIR_new_reg_op(ctx, dst), 1819 - MIR_new_mem_op(ctx, MIR_T_I64, 1820 - (MIR_disp_t)offsetof(sv_closure_t, super_val), 1821 - r_inl_closure, 0, 1))); 1823 + MIR_new_reg_op(ctx, r_inl_super))); 1822 1824 } else if (which == 3) { 1823 1825 MIR_append_insn(ctx, jit_func, 1824 1826 MIR_new_call_insn(ctx, 6, ··· 4724 4726 MIR_label_t inl_join = MIR_new_label(ctx); 4725 4727 4726 4728 MIR_reg_t r_inl_cl = 0; 4729 + MIR_reg_t r_inl_new_target = 0; 4730 + MIR_reg_t r_inl_super = 0; 4727 4731 char inl_this_rn[32], inl_flags_rn[32], inl_bound_rn[32]; 4728 4732 snprintf(inl_this_rn, sizeof(inl_this_rn), "inl%d_this", cn); 4729 4733 snprintf(inl_flags_rn, sizeof(inl_flags_rn), "inl%d_flags", cn); ··· 4742 4746 MIR_new_reg_op(ctx, r_inl_cl), 4743 4747 MIR_new_reg_op(ctx, r_inl_callee), 4744 4748 MIR_new_uint_op(ctx, NANBOX_DATA_MASK))); 4749 + } 4750 + { 4751 + char nt_rn[32], sup_rn[32]; 4752 + snprintf(nt_rn, sizeof(nt_rn), "inl%d_nt", cn); 4753 + snprintf(sup_rn, sizeof(sup_rn), "inl%d_sup", cn); 4754 + r_inl_new_target = MIR_new_func_reg(ctx, jit_func->u.func, 4755 + MIR_JSVAL, nt_rn); 4756 + r_inl_super = MIR_new_func_reg(ctx, jit_func->u.func, 4757 + MIR_JSVAL, sup_rn); 4758 + mir_load_imm(ctx, jit_func, r_inl_new_target, mkval(T_UNDEF, 0)); 4759 + MIR_append_insn(ctx, jit_func, 4760 + MIR_new_insn(ctx, MIR_MOV, 4761 + MIR_new_reg_op(ctx, r_inl_super), 4762 + MIR_new_mem_op(ctx, MIR_T_I64, 4763 + (MIR_disp_t)offsetof(sv_closure_t, super_val), 4764 + r_inl_cl, 0, 1))); 4745 4765 } 4746 4766 4747 4767 if (speculative) { ··· 4783 4803 inl_arg_regs, (int)call_argc, 4784 4804 r_call_res, inl_slow, inl_join, 4785 4805 r_bool, &r_d_slot, cn, 4786 - r_inl_cl, r_inl_this, 4806 + r_inl_cl, r_inl_this, r_inl_new_target, r_inl_super, 4787 4807 r_vm, r_js, 4788 4808 helper2_proto, imp_seq, imp_sne, imp_eq, imp_ne, 4789 4809 gf_proto, imp_get_field,
+97
tests/test_jit_inline_special_obj.mjs
··· 1 + function assert(condition, message) { 2 + if (!condition) throw new Error(message); 3 + } 4 + 5 + function assertEq(actual, expected, message) { 6 + if (actual !== expected) { 7 + throw new Error(`${message}: expected ${expected}, got ${actual}`); 8 + } 9 + } 10 + 11 + function runNewTargetHot() { 12 + function readNewTarget() { 13 + return new.target; 14 + } 15 + 16 + let last = null; 17 + for (let i = 0; i < 600; i++) { 18 + last = readNewTarget(); 19 + } 20 + return last; 21 + } 22 + 23 + class BaseBox { 24 + static value = 7; 25 + } 26 + 27 + class DerivedBox extends BaseBox { 28 + static readSuperValue() { 29 + return super.value; 30 + } 31 + } 32 + 33 + const superReader = DerivedBox.readSuperValue; 34 + 35 + const staticValueSymbol = Symbol("static-value"); 36 + 37 + class SymbolBaseBox { 38 + static [staticValueSymbol] = 11; 39 + } 40 + 41 + class SymbolDerivedBox extends SymbolBaseBox { 42 + static readSuperSymbol() { 43 + return super[staticValueSymbol]; 44 + } 45 + } 46 + 47 + const superSymbolReader = SymbolDerivedBox.readSuperSymbol; 48 + 49 + class ConstructorBase { 50 + get value() { 51 + return this.tag; 52 + } 53 + } 54 + 55 + class ConstructorDerived extends ConstructorBase { 56 + constructor() { 57 + super(); 58 + this.tag = "ctor-super"; 59 + this.fromCtor = super.value; 60 + } 61 + } 62 + 63 + function runSuperHot() { 64 + let last = 0; 65 + for (let i = 0; i < 600; i++) { 66 + last = superReader(); 67 + } 68 + return last; 69 + } 70 + 71 + function runSuperSymbolHot() { 72 + let last = 0; 73 + for (let i = 0; i < 600; i++) { 74 + last = superSymbolReader(); 75 + } 76 + return last; 77 + } 78 + 79 + const isAnt = typeof process === "object" 80 + && process !== null 81 + && typeof process.versions === "object" 82 + && process.versions !== null 83 + && typeof process.versions.ant === "string"; 84 + 85 + assertEq(runNewTargetHot(), undefined, "hot inline helper preserves new.target"); 86 + assertEq(superReader(), 7, "extracted static super value lookup"); 87 + assertEq(runSuperHot(), 7, "hot direct call preserves super value lookup"); 88 + assertEq(superSymbolReader(), 11, "extracted static super symbol lookup"); 89 + assertEq(runSuperSymbolHot(), 11, "hot direct call preserves super symbol lookup"); 90 + assertEq(new ConstructorDerived().fromCtor, "ctor-super", "constructor super getter lookup"); 91 + 92 + if (isAnt) { 93 + const antOnly = await import("./test_jit_inline_special_obj_import.mjs"); 94 + await antOnly.verifyImportBinding(assert, assertEq); 95 + } 96 + 97 + console.log("OK: test_jit_inline_special_obj");
+1
tests/test_jit_inline_special_obj_dep.mjs
··· 1 + export const marker = "inline-special-obj";
+15
tests/test_jit_inline_special_obj_import.mjs
··· 1 + function getImportBinding() { 2 + return import; 3 + } 4 + 5 + export async function verifyImportBinding(assert, assertEq) { 6 + let importBinding = null; 7 + for (let i = 0; i < 600; i++) { 8 + importBinding = getImportBinding(); 9 + } 10 + 11 + assert(typeof importBinding === "function", "hot inline helper returns import binding"); 12 + 13 + const imported = await importBinding("./test_jit_inline_special_obj_dep.mjs"); 14 + assertEq(imported.marker, "inline-special-obj", "returned import binding loads sibling module"); 15 + }