From 501b438428006d1bd5ec21d937d88accb1ec5420 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 6 Oct 2025 10:09:57 -0400 Subject: [PATCH 01/91] Add FAST_CALL instruction --- fast_call.wasm | Bin 0 -> 51 bytes fast_call.wat | 10 ++++++++++ src/engine/BytecodeIterator.v3 | 2 +- src/engine/CodeValidator.v3 | 2 +- src/engine/Opcodes.v3 | 2 ++ src/engine/v3/V3Interpreter.v3 | 4 ++-- src/engine/x86-64/X86_64Interpreter.v3 | 1 + 7 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 fast_call.wasm create mode 100644 fast_call.wat diff --git a/fast_call.wasm b/fast_call.wasm new file mode 100644 index 0000000000000000000000000000000000000000..671de0268347c954bd8763413398f56d6c56e687 GIT binary patch literal 51 zcmZQbEY4+QU|?WmWlUgTtY>CsVqjqBU}VWn%* v.visit_BR_IF(read_LABEL()); BR_TABLE => v.visit_BR_TABLE(cp.read_labels()); RETURN => v.visit_RETURN(); - CALL => v.visit_CALL(read_FUNC()); + CALL, FAST_CALL => v.visit_CALL(read_FUNC()); CALL_INDIRECT => v.visit_CALL_INDIRECT(read_SIG(), read_TABLE()); RETURN_CALL => v.visit_RETURN_CALL(read_FUNC()); RETURN_CALL_INDIRECT => v.visit_RETURN_CALL_INDIRECT(read_SIG(), read_TABLE()); diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index bf3511288..2372ca1a7 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -416,7 +416,7 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e checkAndPopArgs(sig.results); setUnreachable(); } - CALL => { + CALL, FAST_CALL => { var func = parser.readFuncRef(); if (func == null) return; checkSignature(func.sig); diff --git a/src/engine/Opcodes.v3 b/src/engine/Opcodes.v3 index b0a78d735..f3beb943c 100644 --- a/src/engine/Opcodes.v3 +++ b/src/engine/Opcodes.v3 @@ -7,6 +7,8 @@ def imm: ImmSigs; // An enumeration of the WebAssembly opcodes, including their mnenomic names, // the kind of immediate expected, and the (monomorphic) operator signature. enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: SigDecl) { + // Fast handler + FAST_CALL (0x00, 0xF0, "fast_call", imm.FUNC, null), // Default, invalid opcode. INVALID (0x00, 0xFF, "", imm.NONE, null), // Control and calls. diff --git a/src/engine/v3/V3Interpreter.v3 b/src/engine/v3/V3Interpreter.v3 index 95c72b94f..2af335ae5 100644 --- a/src/engine/v3/V3Interpreter.v3 +++ b/src/engine/v3/V3Interpreter.v3 @@ -371,7 +371,7 @@ class V3Interpreter extends WasmStack { RETURN => { doReturn(frame.fp, frame.func.sig); } - CALL => { + CALL, FAST_CALL => { var func_index = codeptr.read_uleb32(); var f = frame.func.instance.functions[func_index]; return doCallFunction(f); @@ -1640,7 +1640,7 @@ class V3Interpreter extends WasmStack { // XXX: use read_opcode_and_skip() var opcode = codeptr.read_opcode_but_skip_probe(frame.func.decl); match (opcode) { - CALL, CALL_REF => { + CALL, CALL_REF, FAST_CALL => { codeptr.skip_leb(); frame.pc = codeptr.pos; } diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index aeed06343..7d97ae371 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -1320,6 +1320,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { genPopFrameAndRet(); bindHandler(Opcode.CALL); + bindHandler(Opcode.FAST_CALL); computeCurIpForTrap(-1); genReadUleb32(r_tmp1); From 9385870baf7d401e766ee3e923bf9b8c63269599 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 6 Oct 2025 13:41:00 -0400 Subject: [PATCH 02/91] Update tag for fast_call --- fast_call.wasm | Bin 51 -> 51 bytes src/engine/Opcodes.v3 | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fast_call.wasm b/fast_call.wasm index 671de0268347c954bd8763413398f56d6c56e687..f6dc1a5e098fa11b854805bf9bb3dad3057cd83e 100644 GIT binary patch delta 16 UcmXpuo}j@k&fxeDgtD@@0VH??o&W#< delta 16 VcmXpuo}j_~fx+<~2xVn)0{|_{1$O`d diff --git a/src/engine/Opcodes.v3 b/src/engine/Opcodes.v3 index f3beb943c..2b44e01ae 100644 --- a/src/engine/Opcodes.v3 +++ b/src/engine/Opcodes.v3 @@ -7,8 +7,6 @@ def imm: ImmSigs; // An enumeration of the WebAssembly opcodes, including their mnenomic names, // the kind of immediate expected, and the (monomorphic) operator signature. enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: SigDecl) { - // Fast handler - FAST_CALL (0x00, 0xF0, "fast_call", imm.FUNC, null), // Default, invalid opcode. INVALID (0x00, 0xFF, "", imm.NONE, null), // Control and calls. @@ -34,6 +32,8 @@ enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: RETURN_CALL_INDIRECT (0x00, 0x13, "return_call_indirect", imm.SIG_TABLE, null), CALL_REF (0x00, 0x14, "call_ref", imm.SIG, null), RETURN_CALL_REF (0x00, 0x15, "return_call_ref", imm.SIG, null), + // Fast handler custom instruction + FAST_CALL (0x00, 0x17, "fast_call", imm.FUNC, null), DELEGATE (0x00, 0x18, "delegate", imm.LABEL, null), CATCH_ALL (0x00, 0x19, "catch_all", imm.NONE, null), DROP (0x00, 0x1A, "drop", imm.NONE, null), @@ -811,6 +811,7 @@ component Opcodes { attributes[InternalOpcode.PROBE.code] = OpcodeAttribute.INTERNAL | OpcodeAttribute.PROBE; attributes[InternalOpcode.WHAMM_PROBE.code] = OpcodeAttribute.INTERNAL | OpcodeAttribute.PROBE; attributes[InternalOpcode.BREAK_PROBE.code] = OpcodeAttribute.INTERNAL | OpcodeAttribute.PROBE; + attributes[Opcode.FAST_CALL.tag] = OpcodeAttribute.INTERNAL; for (op in [Opcode.END, Opcode.I32_CONST, Opcode.I64_CONST, Opcode.F32_CONST, Opcode.F64_CONST, Opcode.GLOBAL_GET, Opcode.REF_NULL, Opcode.REF_FUNC, Opcode.STRUCT_NEW, Opcode.STRUCT_NEW_DEFAULT, From ca553b95da013457ca30f9314bebd33438859def Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 8 Oct 2025 13:02:45 -0400 Subject: [PATCH 03/91] Separate more fast call behavior --- fast_call.wasm | Bin 51 -> 68 bytes fast_call.wat | 12 ++++++------ src/engine/BytecodeIterator.v3 | 3 ++- src/engine/compiler/SinglePassCompiler.v3 | 1 + src/util/BytecodeVisitor.v3 | 1 + 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/fast_call.wasm b/fast_call.wasm index f6dc1a5e098fa11b854805bf9bb3dad3057cd83e..36f858295824074b732c768e522caf4cc349e47b 100644 GIT binary patch literal 68 zcmV~$F%Ezr5Cp*8CsVqjqBU}VWn%* v.visit_BR_IF(read_LABEL()); BR_TABLE => v.visit_BR_TABLE(cp.read_labels()); RETURN => v.visit_RETURN(); - CALL, FAST_CALL => v.visit_CALL(read_FUNC()); + CALL => v.visit_CALL(read_FUNC()); + FAST_CALL => v.visit_FAST_CALL(read_FUNC()); CALL_INDIRECT => v.visit_CALL_INDIRECT(read_SIG(), read_TABLE()); RETURN_CALL => v.visit_RETURN_CALL(read_FUNC()); RETURN_CALL_INDIRECT => v.visit_RETURN_CALL_INDIRECT(read_SIG(), read_TABLE()); diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 8c80f86d6..ec5233f31 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -827,6 +827,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_br(ret_label); setUnreachable(); } + // for CALL, FAST_CALL, and RETURN_CALL def visitCallDirect(op: Opcode, index: u31, tailCall: bool) { if (op == Opcode.CALL) { Metrics.spc_static_calls.val++; diff --git a/src/util/BytecodeVisitor.v3 b/src/util/BytecodeVisitor.v3 index fbef4b056..da03cc410 100644 --- a/src/util/BytecodeVisitor.v3 +++ b/src/util/BytecodeVisitor.v3 @@ -70,6 +70,7 @@ class BytecodeVisitor { def visit_BR_TABLE (labels: Range) { visitControl(Opcode.BR_TABLE); } def visit_RETURN () { visitControl(Opcode.RETURN); } def visit_CALL (func_index: u31) { visitCallDirect(Opcode.CALL, func_index, false); } + def visit_FAST_CALL (func_index: u31) { visitCallDirect(Opcode.FAST_CALL, func_index, false); } def visit_CALL_INDIRECT (sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.CALL_INDIRECT, sig_index, table_index, false); } def visit_RETURN_CALL (func_index: u31) { visitCallDirect(Opcode.RETURN_CALL, func_index, true); } def visit_RETURN_CALL_INDIRECT(sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.RETURN_CALL_INDIRECT, sig_index, table_index, true); } From 93347ff316eae360f96021e5c54975eb671ef8db Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 14 Oct 2025 14:56:21 -0400 Subject: [PATCH 04/91] Add CallProperty to distinguish between tail call and fast call --- src/engine/compiler/SinglePassCompiler.v3 | 59 +++++++++++++++++------ src/util/BytecodeVisitor.v3 | 28 +++++++---- 2 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index ec5233f31..2d8a80f58 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -828,7 +828,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl setUnreachable(); } // for CALL, FAST_CALL, and RETURN_CALL - def visitCallDirect(op: Opcode, index: u31, tailCall: bool) { + def visitCallDirect(op: Opcode, index: u31, prop: CallProperty) { if (op == Opcode.CALL) { Metrics.spc_static_calls.val++; masm.emit_inc_metric(Metrics.spc_dynamic_calls); @@ -836,7 +836,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var func = module.functions[index]; // Try inlining for intra-module, non-tail calls - if (!tailCall && shouldInline(func)) { + if (prop != CallProperty.TAIL && shouldInline(func)) { if (Trace.compiler) Trace.OUT.put2("Inlining call to func #%d (%d bytes)", index, func.orig_bytecode.length).ln(); if (op == Opcode.CALL) { Metrics.spc_static_inlined_calls.val++; @@ -854,11 +854,12 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var tmp = allocTmp(ValueKind.REF); emit_load_instance(tmp); + // Load the function, XXX: skip and compute function from instance + code on stack? masm.emit_v3_Instance_functions_r_r(func_reg, tmp); masm.emit_v3_Array_elem_r_ri(ValueKind.REF, func_reg, func_reg, func.func_index); - emitCallToReg(func.sig, func_reg, vsp_reg, tmp, func.imp != null, tailCall); + emitCallToReg(func.sig, func_reg, vsp_reg, tmp, func.imp != null, prop); }); } def emitInlinedCall(callee_func: FuncDecl, whamm: WhammProbe) { @@ -867,6 +868,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var results_count = u32.view(sig.results.length); var orig_sp = state.sp; + // Arguments are already on stack + // Stack: [..., arg0, arg1, ..., argN] <- sp + // We want callee's local 0 = arg0, so: var new_local_base_sp: u31 = u31.view(orig_sp - params_count); var new_ctl_base_sp = u31.view(state.ctl_stack.top); @@ -887,7 +891,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl m = whamm_instance.module; new_local_base_sp = u31.view(state.sp) - u31.view(whamm_sig.length); // XXX - func_body_ctl.val_stack_top = new_local_base_sp; // correct val_stack_top for whamm arg count + func_body_ctl.val_stack_top = new_local_base_sp; // correct val_stack_top for whamm arg count } // create merge state based on outer function's base sp given inlined function's results @@ -901,6 +905,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl pushSpcFrame(callee_frame); // Emit function entry probe, if any. + // XXX expensive because frame materialization required if (whamm == null && !FeatureDisable.entryProbes && func.entry_probed) { var probe = Instrumentation.getLocalProbe(module, callee_func.func_index, 0); withReconstructedInlinedFrames(fun => @@ -931,24 +936,48 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } if (Trace.compiler) Trace.OUT.puts(" End inlined function body").ln(); - // Restore caller spc context - popSpcFrame(); + // Check if the inlined function is unreachable (e.g., ended with UNREACHABLE, RETURN, THROW) + var inlined_reachable = state.ctl_stack.peek().reachable; + + // Restore caller context by popping frame + popSpcFrame(); // Automatically restores cached fields + + // Note: Control stack cleanup (popping implicit BLOCK) is handled by visit_END + + // If inlined function is unreachable, no results to clean up + if (!inlined_reachable) { + if (Trace.compiler) { + Trace.OUT.puts(" Inlined function unreachable, skipping result cleanup").ln(); + Trace.OUT.put3(" state.sp=%d, new_local_base_sp=%d, callee_slots=%d", + state.sp, new_local_base_sp, state.sp - new_local_base_sp).ln(); + } + // Drop all callee state (params + locals, no results) + var callee_slots = state.sp - new_local_base_sp; + if (callee_slots > 0) dropN(u32.view(callee_slots)); + if (Trace.compiler) Trace.OUT.put1(" After dropN: state.sp=%d", state.sp).ln(); + setUnreachable(); + return; + } + + if (Trace.compiler) { + Trace.OUT.put1(" Inlined call complete, sp=%d", state.sp).ln(); + } } - def emitCallToReg(sig: SigDecl, func_reg: Reg, vsp_reg: Reg, tmp: Reg, checkHostCall: bool, tailCall: bool) { + def emitCallToReg(sig: SigDecl, func_reg: Reg, vsp_reg: Reg, tmp: Reg, checkHostCall: bool, prop: CallProperty) { var retpt = masm.newLabel(it.pc), wasmcall_label = masm.newLabel(it.pc); // Handle the current stack state. - if (tailCall) emitMoveTailCallArgs(sig); // transfer tail call args + if (prop == CallProperty.TAIL) emitMoveTailCallArgs(sig); // transfer tail call args else state.emitSaveAll(resolver, SpillMode.SAVE_AND_FREE_REGS); // spill entire value stack // Compute VSP below the args passed into callee function and spill it emit_compute_vsp(vsp_reg, state.sp - u32.!(sig.params.length)); - if (!tailCall) emit_spill_vsp(vsp_reg); + if (prop != CallProperty.TAIL) emit_spill_vsp(vsp_reg); // Add params to VSP if (sig.params.length > 0) masm.emit_addw_r_i(vsp_reg, sig.params.length * masm.valuerep.slot_size); if (checkHostCall) { // A call to imported function must first check for WasmFunction. masm.emit_br_r(func_reg, MasmBrCond.IS_WASM_FUNC, wasmcall_label); - if (tailCall) { + if (prop == CallProperty.TAIL) { masm.emit_jump_HostCallStub(); // XXX: stub relies on func_arg and VSP } else { masm.emit_call_HostCallStub(); // XXX: stub relies on func_arg and VSP @@ -961,7 +990,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_v3_FuncDecl_target_code_r_r(tmp, tmp); // Call or jump to the entrypoint. - if (tailCall) { + if (prop == CallProperty.TAIL) { masm.emit_jump_r(tmp); setUnreachable(); } else { @@ -985,7 +1014,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // adjust frame masm.emit_addw_r_i(regs.sp, frame.frameSize); } - def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, tailCall: bool) { + def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, prop: CallProperty) { var sig = SigDecl.!(module.heaptypes[sig_index]); withReconstructedInlinedFrames(fun { var vsp_reg = allocTmpFixed(ValueKind.REF, regs.vsp); @@ -1042,10 +1071,10 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.bindLabel(end); } - emitCallToReg(sig, func_reg, vsp_reg, tmp_reg, true, tailCall); + emitCallToReg(sig, func_reg, vsp_reg, tmp_reg, true, prop); }); } - def visitCallRef(op: Opcode, index: u31, tailCall: bool) { + def visitCallRef(op: Opcode, index: u31, prop: CallProperty) { var sig = SigDecl.!(module.heaptypes[index]); var sv = state.peek(); if (sv.isConst() && sv.const == 0) { @@ -1058,7 +1087,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var tmp = allocTmp(ValueKind.REF); var func_reg = sv.reg; - emitCallToReg(sig, func_reg, vsp_reg, tmp, true, tailCall); + emitCallToReg(sig, func_reg, vsp_reg, tmp, true, prop); } def visit_DROP() { dropN(1); diff --git a/src/util/BytecodeVisitor.v3 b/src/util/BytecodeVisitor.v3 index da03cc410..adc822bfe 100644 --- a/src/util/BytecodeVisitor.v3 +++ b/src/util/BytecodeVisitor.v3 @@ -20,9 +20,9 @@ class BytecodeVisitor { def visitMisc(op: Opcode) { visitOp(op); } def visitControl(op: Opcode) { visitOp(op); } def visitCall(op: Opcode) { visitOp(op); } - def visitCallDirect(op: Opcode, func_index: u31, tailCall: bool) { visitCall(op); } - def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, tailCall: bool) { visitCall(op); } - def visitCallRef(op: Opcode, sig_index: u31, tailCall: bool) { visitCall(op); } + def visitCallDirect(op: Opcode, func_index: u31, prop: CallProperty) { visitCall(op); } + def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, prop: CallProperty) { visitCall(op); } + def visitCallRef(op: Opcode, sig_index: u31, prop: CallProperty) { visitCall(op); } def visitLocal(op: Opcode, local_index: u31) { visitOp(op); } def visitGlobal(op: Opcode, local_index: u31) { visitOp(op); } def visitTable(op: Opcode, table_index: u31) { visitOp(op); } @@ -69,13 +69,13 @@ class BytecodeVisitor { def visit_BR_IF (depth: u31) { visitControl(Opcode.BR_IF); } def visit_BR_TABLE (labels: Range) { visitControl(Opcode.BR_TABLE); } def visit_RETURN () { visitControl(Opcode.RETURN); } - def visit_CALL (func_index: u31) { visitCallDirect(Opcode.CALL, func_index, false); } - def visit_FAST_CALL (func_index: u31) { visitCallDirect(Opcode.FAST_CALL, func_index, false); } - def visit_CALL_INDIRECT (sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.CALL_INDIRECT, sig_index, table_index, false); } - def visit_RETURN_CALL (func_index: u31) { visitCallDirect(Opcode.RETURN_CALL, func_index, true); } - def visit_RETURN_CALL_INDIRECT(sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.RETURN_CALL_INDIRECT, sig_index, table_index, true); } - def visit_CALL_REF (sig_index: u31) { visitCallRef(Opcode.CALL_REF, sig_index, false); } - def visit_RETURN_CALL_REF(sig_index: u31) { visitCallRef(Opcode.RETURN_CALL_REF, sig_index, true); } + def visit_CALL (func_index: u31) { visitCallDirect(Opcode.CALL, func_index, SLOW); } + def visit_FAST_CALL (func_index: u31) { visitCallDirect(Opcode.FAST_CALL, func_index, FAST); } + def visit_CALL_INDIRECT (sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.CALL_INDIRECT, sig_index, table_index, SLOW); } + def visit_RETURN_CALL (func_index: u31) { visitCallDirect(Opcode.RETURN_CALL, func_index, TAIL); } + def visit_RETURN_CALL_INDIRECT(sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.RETURN_CALL_INDIRECT, sig_index, table_index, TAIL); } + def visit_CALL_REF (sig_index: u31) { visitCallRef(Opcode.CALL_REF, sig_index, SLOW); } + def visit_RETURN_CALL_REF(sig_index: u31) { visitCallRef(Opcode.RETURN_CALL_REF, sig_index, TAIL); } def visit_DELEGATE (depth: u31) { visitControl(Opcode.DELEGATE); } def visit_CATCH_ALL () { visitControl(Opcode.CATCH_ALL); } def visit_DROP () { visitMisc(Opcode.DROP); } @@ -654,3 +654,11 @@ class BytecodeVisitor { def visit_SUSPEND (tag: u31) { visitOp(Opcode.SUSPEND); } def visit_SWITCH (cont: u31, tag: u31) { visitOp(Opcode.SWITCH); } } + +enum CallProperty { + SLOW, TAIL, FAST +} + +def SLOW = CallProperty.SLOW; +def TAIL = CallProperty.TAIL; +def FAST = CallProperty.FAST; From 9a7d2effa87f43a1e9c0d3c344502d29468b7c45 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 5 Jan 2026 15:56:01 -0500 Subject: [PATCH 05/91] Add stubs/initialization for fast call entries and no-op FAST_CALL in interpreter --- src/engine/Module.v3 | 3 + src/engine/compiler/SinglePassCompiler.v3 | 69 ++++++++------- src/engine/x86-64/V3Offsets.v3 | 1 + src/engine/x86-64/X86_64Interpreter.v3 | 23 ++++- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 84 +++++++++++++++++++ src/engine/x86-64/X86_64Target.v3 | 70 +++++++++++++--- 6 files changed, 204 insertions(+), 46 deletions(-) diff --git a/src/engine/Module.v3 b/src/engine/Module.v3 index 90d85a4ae..f1598f07c 100644 --- a/src/engine/Module.v3 +++ b/src/engine/Module.v3 @@ -141,6 +141,7 @@ class FuncDecl(sig_index: int) extends Decl { var cbd_sidetable: Array; // CBD u8 sidetable var frame_var_tags: Array; // value tags for frame variables var target_code: TargetCode; + var fast_target_code: TargetCode; var tierup_trigger: int = int.max; var handlers = FuncHandlerInfo.new(); @@ -154,6 +155,7 @@ class FuncDecl(sig_index: int) extends Decl { var tc: TargetCode; var tr: TargetCode; target_code = tc; // reset target code as well + fast_target_code = tc; sidetable = Sidetables.NO_SIDETABLE; cbd_sidetable = null; } @@ -183,6 +185,7 @@ class FuncDecl(sig_index: int) extends Decl { n.sidetable = this.sidetable; n.num_locals = this.num_locals; n.target_code = this.target_code; + n.fast_target_code = this.fast_target_code; return n; } def findExHandler(instance: Instance, tag: Tag, throw_pc: int) -> ExHandler { diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 2d8a80f58..f2bd316e9 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -133,15 +133,15 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def gen(module: Module, func: FuncDecl, err: ErrorGen) -> bool { this.osr_pc = -1; this.err = err; - return Metrics.spc_time_us.run(gen0, (module, func)); + return Metrics.spc_time_us.run(gen0(_, _, false), (module, func)); } def genOsr(module: Module, func: FuncDecl, pc: int, err: ErrorGen) -> MasmLabel { this.osr_pc = pc; this.err = err; - var ok = Metrics.spc_time_us.run(gen0, (module, func)); + var ok = Metrics.spc_time_us.run(gen0(_, _, false), (module, func)); return if(ok, osr_entry_label); } - private def gen0(module: Module, func: FuncDecl) -> bool { + private def gen0(module: Module, func: FuncDecl, fast: bool) -> bool { if (Trace.compiler) OUT.put1("==== begin compile: %q ========================", func.render(module.names, _)).ln(); var before_code_bytes = masm.curCodeBytes(); var before_data_bytes = masm.curDataBytes(); @@ -172,7 +172,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl pushSpcFrame(initial_frame); // Emit prologue, which allocates the frame and initializes various registers. - emitPrologue(); + if (!fast) emitPrologue(); // Visit all local declarations. it.dispatchLocalDecls(this); @@ -764,34 +764,37 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl setUnreachable(); } def visit_END() { - var ctl_top = state.ctl_stack.peek(); - if (ctl_top.opcode == Opcode.LOOP.code) { - state.ctl_stack.pop(); - if (!ctl_top.reachable) setUnreachable(); - } else if (ctl_top.opcode == Opcode.IF.code) { - // simulate empty if-true block - state.emitFallthru(resolver); - masm.emit_br(ctl_top.label); - masm.bindLabel(ctl_top.else_label); - state.doElse(); - ctl_top.opcode = Opcode.ELSE.code; - state.emitFallthru(resolver); - masm.bindLabel(ctl_top.label); - state.resetToMerge(ctl_top); - state.ctl_stack.pop(); - } else if (ctl_top.opcode == Opcode.BLOCK.code || ctl_top.opcode == Opcode.ELSE.code) { - state.emitFallthru(resolver); - masm.bindLabel(ctl_top.label); - state.resetToMerge(ctl_top); - state.ctl_stack.pop(); - } else if (ctl_top.opcode == Opcode.RETURN.code) { - state.emitFallthru(resolver); - masm.bindLabel(ctl_top.label); - state.resetToMerge(ctl_top); - emitProbe(); - if (ctl_top.merge_count > 1) emitReturn(ctl_top); - state.ctl_stack.pop(); - return; + if (!isInlined()) { + var ctl_top = state.ctl_stack.peek(); + if (ctl_top.opcode == Opcode.LOOP.code) { + state.ctl_stack.pop(); + if (!ctl_top.reachable) setUnreachable(); + } else if (ctl_top.opcode == Opcode.IF.code) { + // simulate empty if-true block + state.emitFallthru(resolver); + masm.emit_br(ctl_top.label); + masm.bindLabel(ctl_top.else_label); + state.doElse(); + ctl_top.opcode = Opcode.ELSE.code; + state.emitFallthru(resolver); + masm.bindLabel(ctl_top.label); + state.resetToMerge(ctl_top); + state.ctl_stack.pop(); + } else if (ctl_top.opcode == Opcode.BLOCK.code || ctl_top.opcode == Opcode.ELSE.code) { + state.emitFallthru(resolver); + masm.bindLabel(ctl_top.label); + state.resetToMerge(ctl_top); + state.ctl_stack.pop(); + // case for END for fallthrough at end of function? + } else if (ctl_top.opcode == Opcode.RETURN.code) { + state.emitFallthru(resolver); + masm.bindLabel(ctl_top.label); + state.resetToMerge(ctl_top); + emitProbe(); + if (ctl_top.merge_count > 1) emitReturn(ctl_top); + state.ctl_stack.pop(); + } + } emitProbe(); } @@ -2147,11 +2150,13 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_br(target.label); } } + // Return includes epilogue? def emitReturn(ctl: SpcControl) { // All explicit RETURN instructions branch here. masm.bindLabel(ret_label); var results = sig.results; + // fix values? if (masm.valuerep.tagged) { // update mismatched value tags var params = sig.params; diff --git a/src/engine/x86-64/V3Offsets.v3 b/src/engine/x86-64/V3Offsets.v3 index dc3507f58..8321beb17 100644 --- a/src/engine/x86-64/V3Offsets.v3 +++ b/src/engine/x86-64/V3Offsets.v3 @@ -31,6 +31,7 @@ class V3Offsets { def FuncDecl_orig_bytecode = int.view(Pointer.atField(decl.orig_bytecode) - Pointer.atObject(decl)); def FuncDecl_sidetable = int.view(Pointer.atField(decl.sidetable.entries) - Pointer.atObject(decl)); def FuncDecl_target_code = int.view(Pointer.atField(decl.target_code.spc_entry) - Pointer.atObject(decl)); + def FuncDecl_fast_target_code = int.view(Pointer.atField(decl.fast_target_code.spc_entry) - Pointer.atObject(decl)); def FuncDecl_tierup_trigger = int.view(Pointer.atField(decl.tierup_trigger) - Pointer.atObject(decl)); def FuncDecl_entry_probed = int.view(Pointer.atField(decl.entry_probed) - Pointer.atObject(decl)); def FuncDecl_frame_var_tags = int.view(Pointer.atField(decl.frame_var_tags) - Pointer.atObject(decl)); diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index 7d97ae371..5a48e95d3 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -1319,8 +1319,27 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { asm.movd_r_i(G(Target.V3_RET_GPRS[0]), 0); genPopFrameAndRet(); - bindHandler(Opcode.CALL); + // FAST_CALL bindHandler(Opcode.FAST_CALL); + var dispatchLabel = X86_64Label.new(); + // genTagPush(BpTypeCode.I32.code); + // asm.movq_m_i(vsph[0].value, 770); + // incrementVsp(); + + genReadUleb32(r_tmp1); + asm.movq_r_m(r_tmp0, r_instance.plus(offsets.Instance_functions)); + asm.movq_r_m(func_arg, r_tmp0.plusR(r_tmp1, offsets.REF_SIZE, offsets.Array_contents)); + + var tmp = r_tmp2; + asm.movq_r_m(tmp, func_arg.plus(offsets.WasmFunction_decl)); + asm.ijmp_m(tmp.plus(offsets.FuncDecl_fast_target_code)); + asm.invalid(); + + // don't go here + asm.bind(dispatchLabel); + endHandler(); + + bindHandler(Opcode.CALL); computeCurIpForTrap(-1); genReadUleb32(r_tmp1); @@ -1339,6 +1358,8 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { var tmp = r_tmp2; asm.movq_r_m(tmp, func_arg.plus(offsets.WasmFunction_decl)); asm.icall_m(tmp.plus(offsets.FuncDecl_target_code)); + // assembly call to target function + // if not compiled, interpreter's entry point } else { asm.call_rel_far(callReentryLabel); } diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index ee1edfea6..e63d282b5 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -34,6 +34,50 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.trap_stubs = TRAPS_STUB; } + var dispatchJmpOffset: int = -1; + // Generate a load of the next bytecode and a dispatch through the dispatch table. + def genDispatch0(ic: X86_64InterpreterCode, ptr: X86_64Addr, table: IcCodeRef, increment: bool) { + def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; + def r_ip = G(xenv.ip); + def r_dispatch = G(xenv.dispatch); + def r_tmp0 = G(xenv.tmp0); // RCX + def r_tmp1 = G(xenv.tmp1); // RDX + + var opcode = r_tmp0; + var base = r_tmp1; + if (ptr != null) asm.movbzx_r_m(opcode, ptr); + if (increment) asm.inc_r(r_ip); + match (FastIntTuning.dispatchEntrySize) { + 2 => { + if (table == null) asm.movq_r_r(base, r_dispatch); + else asm.lea(base, table); // RIP-relative LEA + asm.movwsx_r_m(opcode, base.plusR(opcode, 2, 0)); // load 16-bit offset + asm.add_r_r(base, opcode); + if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; + asm.ijmp_r(base); + } + 4 => { + if (table == null) { + asm.movd_r_m(base, r_dispatch.plusR(opcode, 4, 0)); + } else { + var addr = ic.start + table.offset; + asm.movd_r_m(base, X86_64Addr.new(null, opcode, 4, int.!(addr - Pointer.NULL))); + } + if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; + asm.ijmp_r(base); + } + 8 => { + if (table == null) { + if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; + asm.ijmp_m(r_dispatch.plusR(opcode, 8, 0)); + } else { + var addr = ic.start + table.offset; + if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; + asm.ijmp_m(X86_64Addr.new(null, opcode, 8, int.!(addr - Pointer.NULL))); + } + } + } + } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { var b = pop(), a = popReg(); if (b.isConst()) asm.cmp_r_i(G(a.reg), b.const); @@ -1414,6 +1458,7 @@ class X86_64SpcCompileStub extends RiUserCode { def V3_SPC_ENTRY_FUNC = X86_64PreGenFunc<(WasmFunction, Pointer, Pointer), Throwable>.new("v3-spc-entry", null, genSpcEntryFunc); def LAZY_COMPILE_STUB = X86_64PreGenStub.new("spc-lazy-compile", X86_64SpcCompileStub.new("lazy"), genLazyCompileStub); +def FAST_COMPILE_STUB = X86_64PreGenStub.new("spc-fast-compile", X86_64SpcCompileStub.new("fast"), genFastCompileStub); def TIERUP_COMPILE_STUB = X86_64PreGenStub.new("spc-tierup-compile", X86_64SpcCompileStub.new("tierup"), genTierUpCompileStub); def TRAPS_STUB = X86_64SpcTrapsStub.new(); def TRAPS_PREGEN = X86_64PreGenStub.new("spc-trap", TRAPS_STUB, genTrapsStub); @@ -1469,6 +1514,36 @@ def genLazyCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { asm.movq_r_r(G(Target.V3_RET_GPRS[0]), G(Target.V3_RET_GPRS[2])); asm.ret(); } +// XXX the stub must also respect the register usage of the fast interpreter +def genFastCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { + if (SpcTuning.disable) return; + var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); + var asm = X86_64Assembler.!(masm.asm); + var regs = X86_64MasmRegs.SPC_EXEC_ENV; + var func_arg = G(regs.func_arg); + + def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; + def r_ip = G(xenv.ip); + def r_dispatch = G(xenv.dispatch); + def r_tmp0 = G(xenv.tmp0); // RCX + def r_tmp1 = G(xenv.tmp1); // RDX + def ip_ptr = r_ip.plus(0); + + // simplified dispatch sequence + + var opcode = r_tmp0; + var base = r_tmp1; + + asm.movbzx_r_m(opcode, ip_ptr); + asm.inc_r(r_ip); + + // flattened 4 case + var addr = ic.start + ic.header.fastDispatchTableOffset; + asm.movd_r_m(base, X86_64Addr.new(null, opcode, 4, int.!(addr - Pointer.NULL))); + asm.ijmp_r(base); + + asm.invalid(); +} def genTierUpCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { if (SpcTuning.disable) return; var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); @@ -1537,6 +1612,10 @@ component X86_64Spc { def invoke(wf: WasmFunction, sp: Pointer) -> Throwable { return V3_SPC_ENTRY_FUNC.get()(wf, sp, wf.decl.target_code.spc_entry); } + def setFastCompileFor(module: Module, decl: FuncDecl) { + if (Debug.runtime) Trace.OUT.put1("setFastCompile %q", decl.render(module.names, _)).ln(); + decl.fast_target_code = TargetCode(FAST_COMPILE_STUB.getEntry()); + } def setLazyCompileFor(module: Module, decl: FuncDecl) { if (Debug.runtime) Trace.OUT.put1("setLazyCompile %q", decl.render(module.names, _)).ln(); decl.target_code = TargetCode(LAZY_COMPILE_STUB.getEntry()); @@ -1561,6 +1640,11 @@ component X86_64Spc { var result = X86_64SpcStrategy.!(Execute.tiering).lazyCompile(wf); return (result.wf, result.entrypoint, result.thrown); } + private def fastCompile(wf: WasmFunction) -> (WasmFunction, Pointer, Throwable) { + // The global stub simply consults the execution strategy. + var result = X86_64ExecutionStrategy.!(Execute.tiering).fastCompile(wf); // no condition that tiering uses SPC (int => fast SPC) + return (result.wf, result.entrypoint, result.thrown); + } private def tierupCompile(wf: WasmFunction) -> (WasmFunction, Pointer, Throwable) { // The global stub simply consults the execution strategy. var result = X86_64SpcStrategy.!(Execute.tiering).tierupCompile(wf); diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 2f36db8b7..c9d003d33 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -199,6 +199,7 @@ class X86_64ExecutionStrategy extends ExecutionStrategy { } // Compilation methods called directly by stubs. def lazyCompile(wf: WasmFunction) -> SpcResultForStub; + def fastCompile(wf: WasmFunction) -> SpcResultForStub; def tierupCompile(wf: WasmFunction) -> SpcResultForStub; // Tiering may require setting up the whole module. def onTestModule(module: Module) { @@ -207,6 +208,20 @@ class X86_64ExecutionStrategy extends ExecutionStrategy { def disableLazyNameDecodingDuringGC(module: Module) { if (module.names != null) module.names.lazyDecodeDisabled = RiGc.inGC; } + + def installStubForModule(module: Module, set: (Module, FuncDecl) -> void) { + // ensure entrypoint and lazy compile stubs are generated + X86_64PreGenStubs.gen(); + // Set all functions to refer to the tier-up compile stub. + var codeSize = MINIMUM_CODE_SIZE; + for (i < module.functions.length) { + var f = module.functions[i]; + if (f.imported()) continue; + set(module, f); + codeSize += X86_64Spc.estimateCodeSizeFor(f); + } + allocateCodeForModule(module, codeSize); + } } // One tier: fast-int, modules require no pre-processing. @@ -230,6 +245,48 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { if (FastIntTuning.enableWhammProbeTrampoline && WhammProbe.?(p)) X86_64WhammTrampoline.makeTrampoline(WhammProbe.!(p), X86_64PreGenStubs.getInterpreterCode()); } + + // TODO avoid duplicated function here + def fastCompile(wf: WasmFunction) -> SpcResultForStub { + // Check the JIT filter, if there is one + if (!applyJitFilter(wf.instance.module, wf.decl, "fast")) return SpcResultForStub(wf, X86_64Spc.setInterpreterFallback(wf.decl), null); + + var module = wf.instance.module; + var code = module.target_module.spc_code; + var compiler = newCompiler(module.filename); // XXX: cache per-thread + var masm = X86_64MacroAssembler.!(compiler.masm), w = masm.asm.w; + + // generate code for the function + var success = compiler.gen(module, wf.decl, null); + + // Check for remaining code space + var regionSize = code.mapping.range.size(); + var remaining = regionSize - u64.!(code.codeEnd); + var codeSize = w.atEnd().pos; + if (codeSize > remaining) { + if (Trace.compiler) Trace.OUT.put3("exhausted code space for module (%d of %d bytes remaining, need %d)", + remaining, regionSize, codeSize).ln(); + success = false; + } + + var entrypoint: Pointer; + if (success) { + // Copy code into end of region + entrypoint = code.appendCode(masm); + Target.setTargetCode(wf.decl, entrypoint, entrypoint + codeSize); + } else { + // Failed, enter interpreter + var f = wf.decl; + if (Trace.compiler) Trace.OUT.put1("func[%d] FAST compile failed", f.func_index).ln(); + entrypoint = X86_64Spc.setInterpreterFallback(f); + } + return SpcResultForStub(wf, entrypoint, null); + } + + // XXX not an exhaustive way to add stubs. but what is? + def onModuleFinish(module: Module, size: u32, err: ErrorGen) { + installStubForModule(module, X86_64Spc.setFastCompileFor); + } } // Base class of all strategies that use SPC. @@ -282,19 +339,6 @@ class X86_64SpcStrategy extends X86_64ExecutionStrategy { } return SpcResultForStub(wf, entrypoint, null); } - def installStubForModule(module: Module, set: (Module, FuncDecl) -> void) { - // ensure entrypoint and lazy compile stubs are generated - X86_64PreGenStubs.gen(); - // Set all functions to refer to the tier-up compile stub. - var codeSize = MINIMUM_CODE_SIZE; - for (i < module.functions.length) { - var f = module.functions[i]; - if (f.imported()) continue; - set(module, f); - codeSize += X86_64Spc.estimateCodeSizeFor(f); - } - allocateCodeForModule(module, codeSize); - } } // One tier: SPC, modules are eagerly compiled. From a3e2ab68021e6d9114721c14fce1e7564c64c5b0 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 5 Jan 2026 16:01:03 -0500 Subject: [PATCH 06/91] Clean up unused dispatch function and specify goals --- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 52 +++---------------- 1 file changed, 7 insertions(+), 45 deletions(-) diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index e63d282b5..5c99db15b 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -34,50 +34,6 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.trap_stubs = TRAPS_STUB; } - var dispatchJmpOffset: int = -1; - // Generate a load of the next bytecode and a dispatch through the dispatch table. - def genDispatch0(ic: X86_64InterpreterCode, ptr: X86_64Addr, table: IcCodeRef, increment: bool) { - def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; - def r_ip = G(xenv.ip); - def r_dispatch = G(xenv.dispatch); - def r_tmp0 = G(xenv.tmp0); // RCX - def r_tmp1 = G(xenv.tmp1); // RDX - - var opcode = r_tmp0; - var base = r_tmp1; - if (ptr != null) asm.movbzx_r_m(opcode, ptr); - if (increment) asm.inc_r(r_ip); - match (FastIntTuning.dispatchEntrySize) { - 2 => { - if (table == null) asm.movq_r_r(base, r_dispatch); - else asm.lea(base, table); // RIP-relative LEA - asm.movwsx_r_m(opcode, base.plusR(opcode, 2, 0)); // load 16-bit offset - asm.add_r_r(base, opcode); - if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; - asm.ijmp_r(base); - } - 4 => { - if (table == null) { - asm.movd_r_m(base, r_dispatch.plusR(opcode, 4, 0)); - } else { - var addr = ic.start + table.offset; - asm.movd_r_m(base, X86_64Addr.new(null, opcode, 4, int.!(addr - Pointer.NULL))); - } - if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; - asm.ijmp_r(base); - } - 8 => { - if (table == null) { - if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; - asm.ijmp_m(r_dispatch.plusR(opcode, 8, 0)); - } else { - var addr = ic.start + table.offset; - if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; - asm.ijmp_m(X86_64Addr.new(null, opcode, 8, int.!(addr - Pointer.NULL))); - } - } - } - } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { var b = pop(), a = popReg(); if (b.isConst()) asm.cmp_r_i(G(a.reg), b.const); @@ -1514,7 +1470,13 @@ def genLazyCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { asm.movq_r_r(G(Target.V3_RET_GPRS[0]), G(Target.V3_RET_GPRS[2])); asm.ret(); } -// XXX the stub must also respect the register usage of the fast interpreter +/* This stub should: + * - save program state (i.e. an epilogue as if it was a call/new frame) + * - compile the function (given register constraints imposed by fast int) + * - rewrite the `fast_target_code` field with this new function + * - restore program state + * - jump into the new `fast_target_code` (or re-dispatch on itself) + */ def genFastCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { if (SpcTuning.disable) return; var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); From f922f4f625fb1a3ead7327c1a2effd84f073f68a Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 5 Jan 2026 17:35:50 -0500 Subject: [PATCH 07/91] Work on SPC accepting fast mode and emitting dispatch sequence --- src/engine/compiler/SinglePassCompiler.v3 | 27 +++--- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 87 ++++++++++++++++++- src/engine/x86-64/X86_64Target.v3 | 16 ++-- 3 files changed, 108 insertions(+), 22 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index f2bd316e9..3aa828a5e 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -79,7 +79,7 @@ def KIND_REF_U64 = SpcConsts.KIND_REF_U64; def KIND_CONT = SpcConsts.KIND_CONT; // Compiles Wasm bytecode to machine code in a single pass via a MacroAssembler. -class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAlloc, extensions: Extension.set, limits: Limits) extends BytecodeVisitor { +class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAlloc, extensions: Extension.set, limits: Limits, fast: bool) extends BytecodeVisitor { def instrTracer = if(Trace.compiler, InstrTracer.new()); def config = masm.regConfig; def regs = xenv; @@ -133,15 +133,15 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def gen(module: Module, func: FuncDecl, err: ErrorGen) -> bool { this.osr_pc = -1; this.err = err; - return Metrics.spc_time_us.run(gen0(_, _, false), (module, func)); + return Metrics.spc_time_us.run(gen0(_, _), (module, func)); } def genOsr(module: Module, func: FuncDecl, pc: int, err: ErrorGen) -> MasmLabel { this.osr_pc = pc; this.err = err; - var ok = Metrics.spc_time_us.run(gen0(_, _, false), (module, func)); + var ok = Metrics.spc_time_us.run(gen0(_, _), (module, func)); return if(ok, osr_entry_label); } - private def gen0(module: Module, func: FuncDecl, fast: bool) -> bool { + private def gen0(module: Module, func: FuncDecl) -> bool { if (Trace.compiler) OUT.put1("==== begin compile: %q ========================", func.render(module.names, _)).ln(); var before_code_bytes = masm.curCodeBytes(); var before_data_bytes = masm.curDataBytes(); @@ -2169,14 +2169,19 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (isInlined()) return; - // Compute VSP = VFP + state.sp - emit_compute_vsp(regs.vsp, state.sp); - // Return to caller - masm.emit_mov_r_i(regs.ret_throw, 0); - // Deallocate stack frame - masm.emit_addw_r_i(regs.sp, frame.frameSize); - masm.emit_ret(); + if (!fast) { + // Compute VSP = VFP + state.sp // \ + emit_compute_vsp(regs.vsp, state.sp); // | + // Return to caller // | fast context: do not emit these instructions + masm.emit_mov_r_i(regs.ret_throw, 0); // | instead, emit the dispatch sequence from the interpreter + // Deallocate stack frame // | + masm.emit_addw_r_i(regs.sp, frame.frameSize); // | + masm.emit_ret(); // / + } else { + emitFastDispatch(); + } } + def emitFastDispatch() -> void; def emitOsrEntry(osr_entry_label: MasmLabel, state: Array) { if (Trace.compiler) Trace.OUT.put1(" OSR (+%d)", osr_entry_label.create_pos).ln(); masm.bindLabel(osr_entry_label); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 5c99db15b..dd305151f 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -28,12 +28,37 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { def w = DataWriter.new(); def mmasm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); def asm = mmasm.asm; + var ic: X86_64InterpreterCode; - new(extensions: Extension.set, limits: Limits, config: RegConfig) - super(X86_64MasmRegs.SPC_EXEC_ENV, mmasm, X86_64MasmRegs.SPC_ALLOC.copy(), extensions, limits) { + new(ic, extensions: Extension.set, limits: Limits, config: RegConfig, fast: bool) + super(X86_64MasmRegs.SPC_EXEC_ENV, mmasm, + if(fast, X86_64MasmRegs.INT_ALLOC.copy(), X86_64MasmRegs.SPC_ALLOC.copy()), + extensions, limits, fast) { mmasm.trap_stubs = TRAPS_STUB; } + def emitFastDispatch() { + ic = X86_64Spc.ic; + + def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; + def r_ip = G(xenv.ip); + def r_dispatch = G(xenv.dispatch); + def r_tmp0 = G(xenv.tmp0); // RCX + def r_tmp1 = G(xenv.tmp1); // RDX + def ip_ptr = r_ip.plus(0); + + // simplified dispatch sequence + var opcode = r_tmp0; + var base = r_tmp1; + asm.movbzx_r_m(opcode, ip_ptr); + asm.inc_r(r_ip); + var addr = ic.start + ic.header.fastDispatchTableOffset; + asm.movd_r_m(base, X86_64Addr.new(null, opcode, 4, int.!(addr - Pointer.NULL))); + asm.ijmp_r(base); + + asm.invalid(); + } + private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { var b = pop(), a = popReg(); if (b.isConst()) asm.cmp_r_i(G(a.reg), b.const); @@ -1441,6 +1466,8 @@ def genSpcEntryFunc(ic: X86_64InterpreterCode, w: DataWriter) { asm.invalid(); } def genLazyCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { + + if (SpcTuning.disable) return; var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); var asm = X86_64Assembler.!(masm.asm); @@ -1478,6 +1505,59 @@ def genLazyCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { * - jump into the new `fast_target_code` (or re-dispatch on itself) */ def genFastCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { + X86_64Spc.ic = ic; + // TODO: figure out this ic thing, because this sucks (and doesn't even work) + + if (SpcTuning.disable) return; + var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); + var asm = X86_64Assembler.!(masm.asm); + var regs = X86_64MasmRegs.SPC_EXEC_ENV; + var func_arg = G(regs.func_arg); + // TODO ensure that register use is compatible with fast-int usage + asm.pushq_r(G(regs.func_arg)); // push function onto stack + masm.emit_store_curstack_vsp(regs.vsp); + asm.movq_r_r(Target.V3_PARAM_GPRS[1], G(regs.func_arg)); // function + // Load {null} for the receiver. + asm.movq_r_i(Target.V3_PARAM_GPRS[0], 0); + // Call {X86_64Spc.fastCompile} directly. + masm.emit_call_abs(codePointer(X86_64Spc.fastCompile)); + asm.q.add_r_i(R.RSP, Pointer.SIZE); // pop function off stack + // Check for non-null abrupt return. + var unwind = X86_64Label.new(); + asm.q.cmp_r_i(Target.V3_RET_GPRS[2], 0); + asm.jc_rel_near(C.NZ, unwind); + // Tail-call the result of the compile. + var scratch = X86_64Regs.R15; +// asm.movq_r_r(scratch, Target.V3_RET_GPRS[1]); // entrypoint +// asm.movq_r_r(G(regs.func_arg), Target.V3_RET_GPRS[0]); // function +// masm.emit_load_curstack_vsp(regs.vsp); +// asm.ijmp_r(scratch); // jump to entrypoint + asm.invalid(); + // Simply return the {Throwable} object. + asm.bind(unwind); + asm.movq_r_r(Target.V3_RET_GPRS[0], Target.V3_RET_GPRS[2]); + + // DISPATCH + + def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; + def r_ip = G(xenv.ip); + def r_dispatch = G(xenv.dispatch); + def r_tmp0 = G(xenv.tmp0); // RCX + def r_tmp1 = G(xenv.tmp1); // RDX + def ip_ptr = r_ip.plus(0); + + // simplified dispatch sequence + var opcode = r_tmp0; + var base = r_tmp1; + asm.movbzx_r_m(opcode, ip_ptr); + asm.inc_r(r_ip); + var addr = ic.start + ic.header.fastDispatchTableOffset; + asm.movd_r_m(base, X86_64Addr.new(null, opcode, 4, int.!(addr - Pointer.NULL))); + asm.ijmp_r(base); + + asm.invalid(); +} +def genFastNopStub(ic: X86_64InterpreterCode, w: DataWriter) { if (SpcTuning.disable) return; var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); var asm = X86_64Assembler.!(masm.asm); @@ -1570,6 +1650,7 @@ def codePointer(f: P -> R) -> Pointer { // Global functionality associated with the single-pass compiler for X86-64. component X86_64Spc { + var ic: X86_64InterpreterCode; // A handy chokepoint for entering JIT code from V3. def invoke(wf: WasmFunction, sp: Pointer) -> Throwable { return V3_SPC_ENTRY_FUNC.get()(wf, sp, wf.decl.target_code.spc_entry); @@ -1604,7 +1685,7 @@ component X86_64Spc { } private def fastCompile(wf: WasmFunction) -> (WasmFunction, Pointer, Throwable) { // The global stub simply consults the execution strategy. - var result = X86_64ExecutionStrategy.!(Execute.tiering).fastCompile(wf); // no condition that tiering uses SPC (int => fast SPC) + var result = X86_64ExecutionStrategy.!(Execute.tiering).fastCompile(wf, ic); // no condition that tiering uses SPC (int => fast SPC) return (result.wf, result.entrypoint, result.thrown); } private def tierupCompile(wf: WasmFunction) -> (WasmFunction, Pointer, Throwable) { diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index c9d003d33..ae0402e0c 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -199,7 +199,7 @@ class X86_64ExecutionStrategy extends ExecutionStrategy { } // Compilation methods called directly by stubs. def lazyCompile(wf: WasmFunction) -> SpcResultForStub; - def fastCompile(wf: WasmFunction) -> SpcResultForStub; + def fastCompile(wf: WasmFunction, ic: X86_64InterpreterCode) -> SpcResultForStub; def tierupCompile(wf: WasmFunction) -> SpcResultForStub; // Tiering may require setting up the whole module. def onTestModule(module: Module) { @@ -247,13 +247,13 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { } // TODO avoid duplicated function here - def fastCompile(wf: WasmFunction) -> SpcResultForStub { + def fastCompile(wf: WasmFunction, ic: X86_64InterpreterCode) -> SpcResultForStub { // Check the JIT filter, if there is one if (!applyJitFilter(wf.instance.module, wf.decl, "fast")) return SpcResultForStub(wf, X86_64Spc.setInterpreterFallback(wf.decl), null); var module = wf.instance.module; var code = module.target_module.spc_code; - var compiler = newCompiler(module.filename); // XXX: cache per-thread + var compiler = newCompiler(module.filename, true, ic); var masm = X86_64MacroAssembler.!(compiler.masm), w = masm.asm.w; // generate code for the function @@ -310,7 +310,7 @@ class X86_64SpcStrategy extends X86_64ExecutionStrategy { var module = wf.instance.module; var code = module.target_module.spc_code; - var compiler = newCompiler(module.filename); // XXX: cache per-thread + var compiler = newCompiler(module.filename, false, null); // XXX: cache per-thread var masm = X86_64MacroAssembler.!(compiler.masm), w = masm.asm.w; // generate code for the function @@ -374,7 +374,7 @@ class X86_64SpcAotStrategy(interpreter_fallback: bool) extends X86_64SpcStrategy // ensure entrypoint and lazy compile stubs are generated X86_64PreGenStubs.gen(); - var compiler = newCompiler(module.filename); + var compiler = newCompiler(module.filename, false, null); var w = compiler.w; // generate code for all functions @@ -467,7 +467,7 @@ class X86_64DynamicStrategy extends X86_64SpcStrategy { } def onTierUp(wf: WasmFunction, pc: int) -> TargetOsrInfo { var module = wf.instance.module; - var compiler = newCompiler(module.filename); + var compiler = newCompiler(module.filename, false, null); if (!applyJitFilter(wf.instance.module, wf.decl, "osr")) { // OSR compile suppressed wf.decl.tierup_trigger = int.max; // no point in trying for a while @@ -496,10 +496,10 @@ class X86_64DynamicStrategy extends X86_64SpcStrategy { } } -def newCompiler(filename: string) -> X86_64SinglePassCompiler { +def newCompiler(filename: string, fast: bool, ic: X86_64InterpreterCode) -> X86_64SinglePassCompiler { var extensions = Extension.set.all; // TODO: all extensions enabled for compilation var limits = Limits.new(); - var compiler = X86_64SinglePassCompiler.new(extensions, limits, X86_64MasmRegs.CONFIG); + var compiler = X86_64SinglePassCompiler.new(ic, extensions, limits, X86_64MasmRegs.CONFIG, fast); return compiler; } def MINIMUM_CODE_SIZE = PAGE_SIZE_i; From f736bd26615fcfce409d2e172f8a886ec4be6d1a Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 14 Jan 2026 17:39:15 -0500 Subject: [PATCH 08/91] macro dispatch, add fast_target_code correctly, better stub caller discipline --- src/engine/Debug.v3 | 6 +- src/engine/Opcodes.v3 | 51 ++++++- src/engine/Trace.v3 | 2 +- src/engine/compiler/MacroAssembler.v3 | 2 + src/engine/x86-64/X86_64Interpreter.v3 | 18 ++- src/engine/x86-64/X86_64MacroAssembler.v3 | 71 ++++++++++ src/engine/x86-64/X86_64PreGenStubs.v3 | 2 +- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 127 +++++++++++------- src/engine/x86-64/X86_64Target.v3 | 23 +++- 9 files changed, 243 insertions(+), 59 deletions(-) diff --git a/src/engine/Debug.v3 b/src/engine/Debug.v3 index 29b91af78..55a445978 100644 --- a/src/engine/Debug.v3 +++ b/src/engine/Debug.v3 @@ -6,9 +6,9 @@ component Debug { // Debug tracing options. def paranoid = false; def verbose = false; - def interpreter = false; - def runtime = false; - def compiler = false; + def interpreter = true; + def runtime = true; + def compiler = true; def pregen = false; def stack = false; def memory = false; diff --git a/src/engine/Opcodes.v3 b/src/engine/Opcodes.v3 index 2b44e01ae..4204e3bf1 100644 --- a/src/engine/Opcodes.v3 +++ b/src/engine/Opcodes.v3 @@ -33,7 +33,6 @@ enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: CALL_REF (0x00, 0x14, "call_ref", imm.SIG, null), RETURN_CALL_REF (0x00, 0x15, "return_call_ref", imm.SIG, null), // Fast handler custom instruction - FAST_CALL (0x00, 0x17, "fast_call", imm.FUNC, null), DELEGATE (0x00, 0x18, "delegate", imm.LABEL, null), CATCH_ALL (0x00, 0x19, "catch_all", imm.NONE, null), DROP (0x00, 0x1A, "drop", imm.NONE, null), @@ -611,6 +610,56 @@ enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: RESUME_THROW (0x00, 0xE4, "resume_throw", imm.CONT_TAG_HANDLE, null), RESUME_THROW_REF (0x00, 0xE5, "resume_throw_ref", imm.CONT_HANDLE, null), SWITCH (0x00, 0xE6, "switch", imm.CONT_TAG, null) + + // fast call instructions + FAST_CALL (0x00, 0x17, "fast_call", imm.FUNC, null) + //FAST_CALL0 (0x00, 0x27, "fast_call0", imm.NONE, null), + //FAST_CALL1 (0x00, 0xC5, "fast_call1", imm.NONE, null), + //FAST_CALL2 (0x00, 0xC6, "fast_call2", imm.NONE, null), + //FAST_CALL3 (0x00, 0xC7, "fast_call3", imm.NONE, null), + //FAST_CALL4 (0x00, 0xC8, "fast_call4", imm.NONE, null), + //FAST_CALL5 (0x00, 0xC9, "fast_call5", imm.NONE, null), + //FAST_CALL6 (0x00, 0xCA, "fast_call6", imm.NONE, null), + //FAST_CALL7 (0x00, 0xCB, "fast_call7", imm.NONE, null), + //FAST_CALL8 (0x00, 0xCC, "fast_call8", imm.NONE, null), + //FAST_CALL9 (0x00, 0xCD, "fast_call9", imm.NONE, null), + //FAST_CALL10 (0x00, 0xCE, "fast_call10", imm.NONE, null), + //FAST_CALL11 (0x00, 0xCF, "fast_call11", imm.NONE, null), + //FAST_CALL12 (0x00, 0xD7, "fast_call12", imm.NONE, null), + //FAST_CALL13 (0x00, 0xD8, "fast_call13", imm.NONE, null), + //FAST_CALL14 (0x00, 0xD9, "fast_call14", imm.NONE, null), + //FAST_CALL15 (0x00, 0xDA, "fast_call15", imm.NONE, null), + //FAST_CALL16 (0x00, 0xDB, "fast_call16", imm.NONE, null), + //FAST_CALL17 (0x00, 0xDC, "fast_call17", imm.NONE, null), + //FAST_CALL18 (0x00, 0xDD, "fast_call18", imm.NONE, null), + //FAST_CALL19 (0x00, 0xDE, "fast_call19", imm.NONE, null), + //FAST_CALL20 (0x00, 0xDF, "fast_call20", imm.NONE, null), + //FAST_CALL21 (0x00, 0xE0, "fast_call21", imm.NONE, null), + //FAST_CALL22 (0x00, 0xE1, "fast_call22", imm.NONE, null), + //FAST_CALL23 (0x00, 0xE2, "fast_call23", imm.NONE, null), + //FAST_CALL24 (0x00, 0xE3, "fast_call24", imm.NONE, null), + //FAST_CALL25 (0x00, 0xE4, "fast_call25", imm.NONE, null), + //FAST_CALL26 (0x00, 0xE5, "fast_call26", imm.NONE, null), + //FAST_CALL27 (0x00, 0xE6, "fast_call27", imm.NONE, null), + //FAST_CALL28 (0x00, 0xE7, "fast_call28", imm.NONE, null), + //FAST_CALL29 (0x00, 0xE8, "fast_call29", imm.NONE, null), + //FAST_CALL30 (0x00, 0xE9, "fast_call30", imm.NONE, null), + //FAST_CALL31 (0x00, 0xEA, "fast_call31", imm.NONE, null), + //FAST_CALL32 (0x00, 0xEB, "fast_call32", imm.NONE, null), + //FAST_CALL33 (0x00, 0xEC, "fast_call33", imm.NONE, null), + //FAST_CALL34 (0x00, 0xED, "fast_call34", imm.NONE, null), + //FAST_CALL35 (0x00, 0xEE, "fast_call35", imm.NONE, null), + //FAST_CALL36 (0x00, 0xEF, "fast_call36", imm.NONE, null), + //FAST_CALL37 (0x00, 0xF2, "fast_call37", imm.NONE, null), + //FAST_CALL38 (0x00, 0xF3, "fast_call38", imm.NONE, null), + //FAST_CALL39 (0x00, 0xF4, "fast_call39", imm.NONE, null), + //FAST_CALL40 (0x00, 0xF5, "fast_call40", imm.NONE, null), + //FAST_CALL41 (0x00, 0xF6, "fast_call41", imm.NONE, null), + //FAST_CALL42 (0x00, 0xF7, "fast_call42", imm.NONE, null), + //FAST_CALL43 (0x00, 0xF8, "fast_call43", imm.NONE, null), + //FAST_CALL44 (0x00, 0xF9, "fast_call44", imm.NONE, null), + //FAST_CALL45 (0x00, 0xFA, "fast_call45", imm.NONE, null), + //FAST_CALL46 (0x00, 0xFF, "fast_call46", imm.NONE, null) } // Enumeration of the different kinds of immediates to opcodes. diff --git a/src/engine/Trace.v3 b/src/engine/Trace.v3 index 22624e980..9ccc5a514 100644 --- a/src/engine/Trace.v3 +++ b/src/engine/Trace.v3 @@ -8,7 +8,7 @@ component Trace { var binparse = false; var canon = false; - var compiler = false; + var compiler = true; var asm = false; var exception = false; var fatal = false; diff --git a/src/engine/compiler/MacroAssembler.v3 b/src/engine/compiler/MacroAssembler.v3 index 47b9feb05..6721973b0 100644 --- a/src/engine/compiler/MacroAssembler.v3 +++ b/src/engine/compiler/MacroAssembler.v3 @@ -367,6 +367,8 @@ class MacroAssembler(valuerep: Tagging, regConfig: RegConfig) { // Destructive on {parent}. def emit_cont_mv(from_vsp: Reg, contStack: Reg, n_vals: Reg, tmp1: Reg, tmp2: Reg, xmm0: Reg); + def emit_dispatchSequence(); + // Validates {cont} and: // - Mark {cont} as used // - Move {cont.stack} to {destContStack} diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index 5a48e95d3..0698a35f5 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -537,6 +537,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { var tmp = r_scratch; { // Entrypoint for calls coming from V3 ic.header.intV3EntryOffset = w.pos; + //masm.emit_debugger_breakpoint(); // Allocate and initialize interpreter stack frame from incoming V3 args. asm.q.sub_r_i(r_sp, k_frame_size); @@ -1256,7 +1257,9 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { } def genLocals() { bindHandler(Opcode.DROP); + //masm.emit_debugger_breakpoint(); decrementVsp(); + //masm.emit_debugger_breakpoint(); endHandler(); bindHandler(Opcode.LOCAL_GET); @@ -1321,6 +1324,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { // FAST_CALL bindHandler(Opcode.FAST_CALL); + //masm.emit_debugger_breakpoint(); var dispatchLabel = X86_64Label.new(); // genTagPush(BpTypeCode.I32.code); // asm.movq_m_i(vsph[0].value, 770); @@ -1332,11 +1336,20 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { var tmp = r_tmp2; asm.movq_r_m(tmp, func_arg.plus(offsets.WasmFunction_decl)); + + //masm.emit_debugger_breakpoint(); asm.ijmp_m(tmp.plus(offsets.FuncDecl_fast_target_code)); - asm.invalid(); + //asm.icall_m(tmp.plus(offsets.FuncDecl_fast_target_code)); + //asm.invalid(); // don't go here asm.bind(dispatchLabel); + masm.emit_nop(); + masm.emit_nop(); + masm.emit_nop(); + masm.emit_nop(); + masm.emit_nop(); + masm.emit_nop(); endHandler(); bindHandler(Opcode.CALL); @@ -2759,7 +2772,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { if (FastIntTuning.enableWhammProbeTrampoline) { var pos = w.atEnd().pos; writeDispatchEntry(dispatchTables[0].1, InternalOpcode.BREAK_PROBE.code, pos); - masm.emit_debugger_breakpoint(); + //masm.emit_debugger_breakpoint(); // Compute a pointer to the original code at this pc offset var pc = r_tmp1; // = IP - CODE asm.movq_r_r(pc, r_ip); @@ -4060,6 +4073,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { // Generate a dispatch from the main dispatch table. def genDispatch() { genDispatch0(ip_ptr, if (FeatureDisable.globalProbes, dispatchTables[0].1), true); + //masm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, dispatchTables[0].1, true, ic); } // Generate a load of the next bytecode and a dispatch through the dispatch table. def genDispatch0(ptr: X86_64Addr, table: IcCodeRef, increment: bool) { diff --git a/src/engine/x86-64/X86_64MacroAssembler.v3 b/src/engine/x86-64/X86_64MacroAssembler.v3 index 4321748f3..ad7b1d891 100644 --- a/src/engine/x86-64/X86_64MacroAssembler.v3 +++ b/src/engine/x86-64/X86_64MacroAssembler.v3 @@ -47,6 +47,34 @@ class X86_64MacroAssembler extends MacroAssembler { } } + def saveIVar(r: X86_64Gpr, ivars: Array<(X86_64Gpr, X86_64Addr)>) { + for (t in ivars) { + if (t.0 == r) asm.movq_m_r(t.1, r); + } + } + def saveCallerIVars(r_ip: X86_64Gpr, r_stp: X86_64Gpr, r_curpc: X86_64Gpr, + ivars: Array<(X86_64Gpr, X86_64Addr)>) { + saveIVar(r_ip, ivars); + saveIVar(r_stp, ivars); + if (!FeatureDisable.stacktraces) saveIVar(r_curpc, ivars); + } + def restoreReg(r: X86_64Gpr, ivars: Array<(X86_64Gpr, X86_64Addr)>) { + for (t in ivars) { + if (t.0 == r) asm.movq_r_m(r, t.1); + } + } + def restoreCallerIVars(r_ip: X86_64Gpr, r_stp: X86_64Gpr, r_eip: X86_64Gpr, + r_instance: X86_64Gpr, r_func_decl: X86_64Gpr, r_mem0_base: X86_64Gpr, r_vfp: X86_64Gpr, + ivars: Array<(X86_64Gpr, X86_64Addr)>) { + restoreReg(r_ip, ivars); + restoreReg(r_stp, ivars); + restoreReg(r_eip, ivars); + restoreReg(r_instance, ivars); + restoreReg(r_func_decl, ivars); + restoreReg(r_mem0_base, ivars); + restoreReg(r_vfp, ivars); + } + // Label operations def newLabel(create_pos: int) -> X86_64MasmLabel { return X86_64MasmLabel.new(create_pos, asm.newLabel()); @@ -1593,6 +1621,49 @@ class X86_64MacroAssembler extends MacroAssembler { asm.pextrq_r_s_i(G(to), X(from), 1); } + // xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; + // r_ip rax + // ip_ptr + // r_dispatch r14 + // r_tmp0 rcx + // r_tmp1 rdx + def emit_int_dispatch(opcode: X86_64Gpr, base: X86_64Gpr, r_ip: X86_64Gpr, r_dispatch: X86_64Gpr, + ptr: X86_64Addr, table: IcCodeRef, increment: bool, ic: X86_64InterpreterCode) { + if (ptr != null) asm.movbzx_r_m(opcode, ptr); + if (increment) asm.inc_r(r_ip); + match (FastIntTuning.dispatchEntrySize) { + 2 => { + if (table == null) asm.movq_r_r(base, r_dispatch); + else asm.lea(base, table); // RIP-relative LEA + asm.movwsx_r_m(opcode, base.plusR(opcode, 2, 0)); // load 16-bit offset + asm.add_r_r(base, opcode); + //if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; + asm.ijmp_r(base); + } + 4 => { + if (table == null) { + asm.movd_r_m(base, r_dispatch.plusR(opcode, 4, 0)); + } else { + var addr = ic.start + table.offset; + asm.movd_r_m(base, X86_64Addr.new(null, opcode, 4, int.!(addr - Pointer.NULL))); + } + //if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; + asm.ijmp_r(base); + } + 8 => { + if (table == null) { + //if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; + asm.ijmp_m(r_dispatch.plusR(opcode, 8, 0)); + } else { + var addr = ic.start + table.offset; + //if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; + asm.ijmp_m(X86_64Addr.new(null, opcode, 8, int.!(addr - Pointer.NULL))); + } + } + } + + } + // Reads a 32- or 64-bit unsigned LEB from {rw_ptr} into {w_dest}. def emit_read_uleb(w_dest: X86_64Gpr, rw_ptr: X86_64Gpr, w_scratch1: X86_64Gpr, w_scratch2: X86_64Gpr) -> this { // TODO: handle w_dest = rcx diff --git a/src/engine/x86-64/X86_64PreGenStubs.v3 b/src/engine/x86-64/X86_64PreGenStubs.v3 index afe80d79f..74985e55f 100644 --- a/src/engine/x86-64/X86_64PreGenStubs.v3 +++ b/src/engine/x86-64/X86_64PreGenStubs.v3 @@ -25,7 +25,7 @@ layout X86_64PreGenHeader { +24 intV3EntryOffset: i32; // entry into interpreter from V3 caller +28 intSpcEntryOffset: i32; // entry into interpreter from SPC caller +32 intIntEntryOffset: i32; // entry into interpreter from interpreter caller - +36 intSuspendEntryOffset: i32; // entry into interpreter from a suspended child stack + +36 intSuspendEntryOffset: i32; // entry into interpreter from a suspended child stack +40 deoptReentryOffset: i32; // re-enter interpreter from optimized code +44 oobMemoryHandlerOffset: i32; // handler for signals caused by OOB memory access +48 divZeroHandlerOffset: i32; // handler for signals caused by divide by zero diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index dd305151f..8f0a54d2e 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -36,27 +36,16 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { extensions, limits, fast) { mmasm.trap_stubs = TRAPS_STUB; } - def emitFastDispatch() { - ic = X86_64Spc.ic; - + // DISPATCH def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; def r_ip = G(xenv.ip); + def ip_ptr = r_ip.plus(0); def r_dispatch = G(xenv.dispatch); def r_tmp0 = G(xenv.tmp0); // RCX def r_tmp1 = G(xenv.tmp1); // RDX - def ip_ptr = r_ip.plus(0); - - // simplified dispatch sequence - var opcode = r_tmp0; - var base = r_tmp1; - asm.movbzx_r_m(opcode, ip_ptr); - asm.inc_r(r_ip); - var addr = ic.start + ic.header.fastDispatchTableOffset; - asm.movd_r_m(base, X86_64Addr.new(null, opcode, 4, int.!(addr - Pointer.NULL))); - asm.ijmp_r(base); - - asm.invalid(); + mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, + IcCodeRef.new(ic.header.fastDispatchTableOffset), true, ic); } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { @@ -1440,6 +1429,7 @@ class X86_64SpcCompileStub extends RiUserCode { def V3_SPC_ENTRY_FUNC = X86_64PreGenFunc<(WasmFunction, Pointer, Pointer), Throwable>.new("v3-spc-entry", null, genSpcEntryFunc); def LAZY_COMPILE_STUB = X86_64PreGenStub.new("spc-lazy-compile", X86_64SpcCompileStub.new("lazy"), genLazyCompileStub); def FAST_COMPILE_STUB = X86_64PreGenStub.new("spc-fast-compile", X86_64SpcCompileStub.new("fast"), genFastCompileStub); +def FAST_CALL_NOP = X86_64PreGenStub.new("spc-fast-nop", X86_64SpcCompileStub.new("fast"), genFastNopStub); def TIERUP_COMPILE_STUB = X86_64PreGenStub.new("spc-tierup-compile", X86_64SpcCompileStub.new("tierup"), genTierUpCompileStub); def TRAPS_STUB = X86_64SpcTrapsStub.new(); def TRAPS_PREGEN = X86_64PreGenStub.new("spc-trap", TRAPS_STUB, genTrapsStub); @@ -1466,8 +1456,6 @@ def genSpcEntryFunc(ic: X86_64InterpreterCode, w: DataWriter) { asm.invalid(); } def genLazyCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { - - if (SpcTuning.disable) return; var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); var asm = X86_64Assembler.!(masm.asm); @@ -1505,57 +1493,102 @@ def genLazyCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { * - jump into the new `fast_target_code` (or re-dispatch on itself) */ def genFastCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { - X86_64Spc.ic = ic; - // TODO: figure out this ic thing, because this sucks (and doesn't even work) - if (SpcTuning.disable) return; var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); var asm = X86_64Assembler.!(masm.asm); var regs = X86_64MasmRegs.SPC_EXEC_ENV; var func_arg = G(regs.func_arg); + + var xenv = X86_64MasmRegs.INT_EXEC_ENV; + // TODO ensure that register use is compatible with fast-int usage + def r_mem0_base = G(xenv.mem0_base); + def r_vfp = G(xenv.vfp); + def r_vsp = G(xenv.vsp); + def r_stp = G(xenv.stp); + def r_ip = G(xenv.ip); + def r_eip = G(xenv.eip); + def r_func_decl = G(xenv.func_decl); + def r_instance = G(xenv.instance); + def r_curpc = G(xenv.curpc); + + def m_mem0_base = R.RSP.plus(X86_64InterpreterFrame.mem0_base.offset); + def m_vfp = R.RSP.plus(X86_64InterpreterFrame.vfp.offset); + def m_vsp = R.RSP.plus(X86_64InterpreterFrame.vsp.offset); + def m_stp = R.RSP.plus(X86_64InterpreterFrame.stp.offset); + def m_ip = R.RSP.plus(X86_64InterpreterFrame.ip.offset); + def m_eip = R.RSP.plus(X86_64InterpreterFrame.eip.offset); + def m_func_decl = R.RSP.plus(X86_64InterpreterFrame.func_decl.offset); + def m_instance = R.RSP.plus(X86_64InterpreterFrame.instance.offset); + def m_curpc = R.RSP.plus(X86_64InterpreterFrame.curpc.offset); + + def ivar_MEM0_BASE = (r_mem0_base, m_mem0_base); + def ivar_VFP = (r_vfp, m_vfp); + def ivar_VSP = (r_vsp, m_vsp); + def ivar_STP = (r_stp, m_stp); + def ivar_IP = (r_ip, m_ip); + def ivar_EIP = (r_eip, m_eip); + def ivar_FUNC_DECL = (r_func_decl, m_func_decl); + def ivar_INSTANCE = (r_instance, m_instance); + def ivar_CURPC = (r_curpc, m_curpc); + + def all_ivars = [ + ivar_MEM0_BASE, + ivar_VFP, + ivar_VSP, + ivar_STP, + ivar_IP, + ivar_EIP, + ivar_FUNC_DECL, + ivar_INSTANCE, + ivar_CURPC + ]; + + //masm.emit_debugger_breakpoint(); + for (i < all_ivars.length) { + asm.pushq_r(all_ivars[i].0); + } asm.pushq_r(G(regs.func_arg)); // push function onto stack + //masm.saveCallerIVars(r_ip, r_stp, r_curpc, all_ivars); + // saveCallerIVars (move to macro assembler) + // look at runtime calls in int, and int->spc calls masm.emit_store_curstack_vsp(regs.vsp); - asm.movq_r_r(Target.V3_PARAM_GPRS[1], G(regs.func_arg)); // function + //masm.emit_debugger_breakpoint(); + + asm.movq_r_r(Target.V3_PARAM_GPRS[1], G(regs.func_arg)); // function (rdx) + asm.movq_r_i(Target.V3_PARAM_GPRS[2], int.!(Pointer.atObject(ic) - Pointer.NULL)); // load into rdx // Load {null} for the receiver. asm.movq_r_i(Target.V3_PARAM_GPRS[0], 0); // Call {X86_64Spc.fastCompile} directly. + //masm.emit_debugger_breakpoint(); masm.emit_call_abs(codePointer(X86_64Spc.fastCompile)); + //masm.emit_debugger_breakpoint(); asm.q.add_r_i(R.RSP, Pointer.SIZE); // pop function off stack // Check for non-null abrupt return. var unwind = X86_64Label.new(); asm.q.cmp_r_i(Target.V3_RET_GPRS[2], 0); asm.jc_rel_near(C.NZ, unwind); // Tail-call the result of the compile. - var scratch = X86_64Regs.R15; -// asm.movq_r_r(scratch, Target.V3_RET_GPRS[1]); // entrypoint -// asm.movq_r_r(G(regs.func_arg), Target.V3_RET_GPRS[0]); // function -// masm.emit_load_curstack_vsp(regs.vsp); -// asm.ijmp_r(scratch); // jump to entrypoint - asm.invalid(); - // Simply return the {Throwable} object. - asm.bind(unwind); - asm.movq_r_r(Target.V3_RET_GPRS[0], Target.V3_RET_GPRS[2]); + var scratch = X86_64Regs.R9; + asm.movq_r_r(scratch, Target.V3_RET_GPRS[1]); // entrypoint + asm.movq_r_r(G(regs.func_arg), Target.V3_RET_GPRS[0]); // function - // DISPATCH - - def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; - def r_ip = G(xenv.ip); - def r_dispatch = G(xenv.dispatch); - def r_tmp0 = G(xenv.tmp0); // RCX - def r_tmp1 = G(xenv.tmp1); // RDX - def ip_ptr = r_ip.plus(0); + for (i < all_ivars.length) { + asm.popq_r(all_ivars[all_ivars.length - i - 1].0); + } + //masm.restoreCallerIVars(r_ip, r_stp, r_eip, r_instance, r_func_decl, r_mem0_base, r_vfp, all_ivars); + masm.emit_load_curstack_vsp(regs.vsp); - // simplified dispatch sequence - var opcode = r_tmp0; - var base = r_tmp1; - asm.movbzx_r_m(opcode, ip_ptr); - asm.inc_r(r_ip); - var addr = ic.start + ic.header.fastDispatchTableOffset; - asm.movd_r_m(base, X86_64Addr.new(null, opcode, 4, int.!(addr - Pointer.NULL))); - asm.ijmp_r(base); + //masm.emit_debugger_breakpoint(); + asm.ijmp_r(scratch); // jump to entrypoint asm.invalid(); + asm.ret(); + + // Simply return the {Throwable} object. ?? + asm.bind(unwind); + asm.movq_r_r(Target.V3_RET_GPRS[0], Target.V3_RET_GPRS[2]); + asm.ret(); } def genFastNopStub(ic: X86_64InterpreterCode, w: DataWriter) { if (SpcTuning.disable) return; @@ -1683,7 +1716,7 @@ component X86_64Spc { var result = X86_64SpcStrategy.!(Execute.tiering).lazyCompile(wf); return (result.wf, result.entrypoint, result.thrown); } - private def fastCompile(wf: WasmFunction) -> (WasmFunction, Pointer, Throwable) { + private def fastCompile(wf: WasmFunction, ic: X86_64InterpreterCode) -> (WasmFunction, Pointer, Throwable) { // The global stub simply consults the execution strategy. var result = X86_64ExecutionStrategy.!(Execute.tiering).fastCompile(wf, ic); // no condition that tiering uses SPC (int => fast SPC) return (result.wf, result.entrypoint, result.thrown); diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index ae0402e0c..754186088 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -65,6 +65,23 @@ component Target { f.target_code = TargetCode(addr); Debug.afterCompile(f, u64.view(addr - Pointer.NULL)); } + def setFastTargetCode(f: FuncDecl, addr: Pointer, end: Pointer) { + if (Trace.compiler) { + Trace.OUT.put2("func[%d].fast_target_code: break *0x%x", f.func_index, addr - Pointer.NULL) + .put2(" disass 0x%x, 0x%x", addr - Pointer.NULL, end - Pointer.NULL).ln(); + if (Trace.asm) { + var cur_byte = addr; + Trace.OUT.puts("JIT code: "); + while (cur_byte < end) { + Trace.OUT.put1("%x ", cur_byte.load()); + cur_byte++; + } + Trace.OUT.ln(); + } + } + f.fast_target_code = TargetCode(addr); + Debug.afterCompile(f, u64.view(addr - Pointer.NULL)); + } def pregenIntoFile(filename: string) -> ErrorBuilder { var data = System.fileLoad(filename); var err = ErrorBuilder.new().puts("interpreter generator: "); @@ -239,6 +256,7 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { } def onNewFunction(wf: WasmFunction, err: ErrorGen) { Target.setUnconditionalInterpreterEntryIfMultiTier(wf.decl); + X86_64Spc.setFastCompileFor(wf.instance.module, wf.decl); } def onFuncProbeInsert1(module: Module, func: FuncDecl, offset: int, p: Probe) { @@ -248,9 +266,6 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { // TODO avoid duplicated function here def fastCompile(wf: WasmFunction, ic: X86_64InterpreterCode) -> SpcResultForStub { - // Check the JIT filter, if there is one - if (!applyJitFilter(wf.instance.module, wf.decl, "fast")) return SpcResultForStub(wf, X86_64Spc.setInterpreterFallback(wf.decl), null); - var module = wf.instance.module; var code = module.target_module.spc_code; var compiler = newCompiler(module.filename, true, ic); @@ -273,7 +288,7 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { if (success) { // Copy code into end of region entrypoint = code.appendCode(masm); - Target.setTargetCode(wf.decl, entrypoint, entrypoint + codeSize); + Target.setFastTargetCode(wf.decl, entrypoint, entrypoint + codeSize); } else { // Failed, enter interpreter var f = wf.decl; From 6056e476bd9f2dc255af2b89b4e2666ae57d4276 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 15 Jan 2026 11:13:20 -0500 Subject: [PATCH 09/91] Fix vsp in fast spc --- src/engine/Trace.v3 | 2 +- src/engine/compiler/SinglePassCompiler.v3 | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/Trace.v3 b/src/engine/Trace.v3 index 9ccc5a514..22624e980 100644 --- a/src/engine/Trace.v3 +++ b/src/engine/Trace.v3 @@ -8,7 +8,7 @@ component Trace { var binparse = false; var canon = false; - var compiler = true; + var compiler = false; var asm = false; var exception = false; var fatal = false; diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 3aa828a5e..0c420fd6c 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -2150,7 +2150,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_br(target.label); } } - // Return includes epilogue? + // Return includes epilogue def emitReturn(ctl: SpcControl) { // All explicit RETURN instructions branch here. masm.bindLabel(ret_label); @@ -2169,10 +2169,10 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (isInlined()) return; + // Compute VSP = VFP + state.sp + emit_compute_vsp(regs.vsp, state.sp); if (!fast) { - // Compute VSP = VFP + state.sp // \ - emit_compute_vsp(regs.vsp, state.sp); // | - // Return to caller // | fast context: do not emit these instructions + // Return to caller // \ fast context: do not emit these instructions masm.emit_mov_r_i(regs.ret_throw, 0); // | instead, emit the dispatch sequence from the interpreter // Deallocate stack frame // | masm.emit_addw_r_i(regs.sp, frame.frameSize); // | From 4e7ea0ec00c6a04f0e78ca08ddc17180bc5ed2bb Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 15 Jan 2026 11:52:43 -0500 Subject: [PATCH 10/91] Replace CALL with FAST_CALL when function is exported with "fast:" prefix --- src/engine/CodeValidator.v3 | 16 +++++++++++++++- src/engine/Module.v3 | 9 +++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index 2372ca1a7..24b25887c 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -416,7 +416,21 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e checkAndPopArgs(sig.results); setUnreachable(); } - CALL, FAST_CALL => { + CALL => { + var func = parser.readFuncRef(); + if (func == null) return; + checkSignature(func.sig); + + // fast call: if function is exported with fast name, replace the bytecode with FAST_CALL + for (i < module.exports.length) { + def ex = module.exports[i]; + if (ex.1 == func && Strings.startsWith(ex.0, "fast:")) { + this.func.replaceCall(opcode_pos); + } + } + + } + FAST_CALL => { var func = parser.readFuncRef(); if (func == null) return; checkSignature(func.sig); diff --git a/src/engine/Module.v3 b/src/engine/Module.v3 index f1598f07c..4b37e48f0 100644 --- a/src/engine/Module.v3 +++ b/src/engine/Module.v3 @@ -170,6 +170,15 @@ class FuncDecl(sig_index: int) extends Decl { if (cur_bytecode == orig_bytecode) return; cur_bytecode[pc] = orig_bytecode[pc]; } + def replaceCall(pc: int) { + // "orig" will become a copy of the original code, to allow in-place modification of old code + if (cur_bytecode == orig_bytecode) orig_bytecode = Arrays.dup(orig_bytecode); + if (cur_bytecode[pc] != Opcode.CALL.code) { + def realOp = Opcodes.find(0, cur_bytecode[pc]); + System.error("replace bytecode", Strings.format1("not replacing call (got %s)", realOp.mnemonic)); + } + cur_bytecode[pc] = byte.!(Opcode.FAST_CALL.code); + } def reset() -> this { if (cur_bytecode == orig_bytecode) return; ArrayUtil.copyInto(cur_bytecode, 0, orig_bytecode, 0, orig_bytecode.length); From f6bb78de42cde654443754339c96ef10f7310114 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 21 Jan 2026 15:30:27 -0500 Subject: [PATCH 11/91] AOT compile fast functions declared in export name --- src/engine/compiler/SinglePassCompiler.v3 | 17 ++++- src/engine/x86-64/X86_64MasmRegs.v3 | 13 ++-- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 30 ++++---- src/engine/x86-64/X86_64Target.v3 | 72 ++++++++++++++++++- 4 files changed, 108 insertions(+), 24 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 0c420fd6c..89ddea3f4 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -172,7 +172,13 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl pushSpcFrame(initial_frame); // Emit prologue, which allocates the frame and initializes various registers. - if (!fast) emitPrologue(); + if (fast) { + masm.emit_nop(); + masm.emit_nop(); + } else { + emitPrologue(); + + } // Visit all local declarations. it.dispatchLocalDecls(this); @@ -2153,7 +2159,14 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Return includes epilogue def emitReturn(ctl: SpcControl) { // All explicit RETURN instructions branch here. - masm.bindLabel(ret_label); + if (ret_label != null) { + masm.bindLabel(ret_label); + ret_label = null; + } + masm.emit_nop(); + masm.emit_nop(); + + var results = sig.results; // fix values? diff --git a/src/engine/x86-64/X86_64MasmRegs.v3 b/src/engine/x86-64/X86_64MasmRegs.v3 index 0668c35a5..9f789233c 100644 --- a/src/engine/x86-64/X86_64MasmRegs.v3 +++ b/src/engine/x86-64/X86_64MasmRegs.v3 @@ -94,11 +94,11 @@ component X86_64MasmRegs { var xint = IntExecEnv.new(); xint.sp = xspc.sp = RSP; - xint.func_arg = xspc.func_arg = RDX; - xint.vsp = xspc.vsp = RSI; + xint.func_arg = xspc.func_arg = RDX; // cache of frame (callee-restore) + xint.vsp = xspc.vsp = RSI; xint.vfp = xspc.vfp = R11; - xint.mem0_base = xspc.mem0_base = R10; - xint.instance = xspc.instance = RDI; + xint.mem0_base = xspc.mem0_base = R10; // cache of frame (callee-restore) + xint.instance = xspc.instance = RDI; // cache of frame (callee-restore) xint.runtime_arg0 = xspc.runtime_arg0 = RSI; xint.runtime_arg1 = xspc.runtime_arg1 = RDX; xint.runtime_arg2 = xspc.runtime_arg2 = RCX; @@ -114,7 +114,7 @@ component X86_64MasmRegs { xint.ip = RAX; xint.func_decl = R12; xint.eip = R13; - xint.dispatch = R14; + xint.dispatch = R14; // cache of field (see how it is saved/stored in interpreter) xint.xmm0 = XMM0; xint.xmm1 = XMM1; xint.xmm2 = XMM2; @@ -163,7 +163,8 @@ component X86_64MasmRegs { // A register allocator for interpreter contexts. def INT_ALLOC = (fun -> RegAlloc { var pools = [ - RegPool32.new([RCX, RDX, R8, R9]), + RegPool32.new([RCX, RDX, R8, R9]), // could use callee-restore (but put at end) + // if callee-restore registers are used, have to emit a restore at the end RegPool32.new([XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14]) ]; return RegAlloc.new(CONFIG.poolMap, pools, null); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 8f0a54d2e..b01bd724b 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -45,7 +45,7 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { def r_tmp0 = G(xenv.tmp0); // RCX def r_tmp1 = G(xenv.tmp1); // RDX mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, - IcCodeRef.new(ic.header.fastDispatchTableOffset), true, ic); + if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { @@ -1544,25 +1544,26 @@ def genFastCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { ivar_CURPC ]; - //masm.emit_debugger_breakpoint(); - for (i < all_ivars.length) { - asm.pushq_r(all_ivars[i].0); - } + masm.emit_debugger_breakpoint(); + //for (i < all_ivars.length) { + // asm.pushq_r(all_ivars[i].0); + //} + masm.saveCallerIVars(r_ip, r_stp, r_curpc, all_ivars); asm.pushq_r(G(regs.func_arg)); // push function onto stack - //masm.saveCallerIVars(r_ip, r_stp, r_curpc, all_ivars); // saveCallerIVars (move to macro assembler) // look at runtime calls in int, and int->spc calls masm.emit_store_curstack_vsp(regs.vsp); - //masm.emit_debugger_breakpoint(); + masm.emit_debugger_breakpoint(); asm.movq_r_r(Target.V3_PARAM_GPRS[1], G(regs.func_arg)); // function (rdx) asm.movq_r_i(Target.V3_PARAM_GPRS[2], int.!(Pointer.atObject(ic) - Pointer.NULL)); // load into rdx + // dispatch is in r14 (don't overwrite, just access directly) // Load {null} for the receiver. asm.movq_r_i(Target.V3_PARAM_GPRS[0], 0); // Call {X86_64Spc.fastCompile} directly. //masm.emit_debugger_breakpoint(); masm.emit_call_abs(codePointer(X86_64Spc.fastCompile)); - //masm.emit_debugger_breakpoint(); + masm.emit_debugger_breakpoint(); asm.q.add_r_i(R.RSP, Pointer.SIZE); // pop function off stack // Check for non-null abrupt return. var unwind = X86_64Label.new(); @@ -1573,13 +1574,13 @@ def genFastCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { asm.movq_r_r(scratch, Target.V3_RET_GPRS[1]); // entrypoint asm.movq_r_r(G(regs.func_arg), Target.V3_RET_GPRS[0]); // function - for (i < all_ivars.length) { - asm.popq_r(all_ivars[all_ivars.length - i - 1].0); - } - //masm.restoreCallerIVars(r_ip, r_stp, r_eip, r_instance, r_func_decl, r_mem0_base, r_vfp, all_ivars); + //for (i < all_ivars.length) { + // asm.popq_r(all_ivars[all_ivars.length - i - 1].0); + //} + masm.restoreCallerIVars(r_ip, r_stp, r_eip, r_instance, r_func_decl, r_mem0_base, r_vfp, all_ivars); masm.emit_load_curstack_vsp(regs.vsp); - //masm.emit_debugger_breakpoint(); + masm.emit_debugger_breakpoint(); asm.ijmp_r(scratch); // jump to entrypoint asm.invalid(); @@ -1720,6 +1721,9 @@ component X86_64Spc { // The global stub simply consults the execution strategy. var result = X86_64ExecutionStrategy.!(Execute.tiering).fastCompile(wf, ic); // no condition that tiering uses SPC (int => fast SPC) return (result.wf, result.entrypoint, result.thrown); + // need to compute _a_ new vfp + // bump the stack pointer? + // goal: avoid having to make new frame entirely } private def tierupCompile(wf: WasmFunction) -> (WasmFunction, Pointer, Throwable) { // The global stub simply consults the execution strategy. diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 754186088..fbef09684 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -253,10 +253,16 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { def onFuncValidationFinish(module: Module, func: FuncDecl, err: ErrorGen) { if (err != null && !err.ok()) return; Target.setUnconditionalInterpreterEntryIfMultiTier(func); + + for (i < module.exports.length) { + def ex = module.exports[i]; + if (ex.1 == func && Strings.startsWith(ex.0, "fast:")) { + System.puts(Strings.format1("fast function %s\n", ex.0)); + } + } } def onNewFunction(wf: WasmFunction, err: ErrorGen) { Target.setUnconditionalInterpreterEntryIfMultiTier(wf.decl); - X86_64Spc.setFastCompileFor(wf.instance.module, wf.decl); } def onFuncProbeInsert1(module: Module, func: FuncDecl, offset: int, p: Probe) { @@ -268,7 +274,7 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { def fastCompile(wf: WasmFunction, ic: X86_64InterpreterCode) -> SpcResultForStub { var module = wf.instance.module; var code = module.target_module.spc_code; - var compiler = newCompiler(module.filename, true, ic); + var compiler = newCompiler(module.filename, true, null); var masm = X86_64MacroAssembler.!(compiler.masm), w = masm.asm.w; // generate code for the function @@ -297,10 +303,70 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { } return SpcResultForStub(wf, entrypoint, null); } + def fastCompileEntireModule(module: Module, size: u32, interpreter_fallback: bool, err: ErrorGen, ballast: u32) { + // ensure entrypoint and lazy compile stubs are generated + X86_64PreGenStubs.gen(); + + var compiler = newCompiler(module.filename, true, null); + var w = compiler.w; + + // generate code for all functions + var bounds = Array<(int, int)>.new(module.functions.length); + var suberr = if(!interpreter_fallback, err); + for (i = 0; err.ok() && i < module.functions.length; i++) { + var f = module.functions[i]; + if (f.imported()) continue; + for (j < module.exports.length) { + def ex = module.exports[j]; + if (ex.1 == f && Strings.startsWith(ex.0, "fast:")) { + var start = w.atEnd().pos; + var compiled = compiler.gen(module, f, suberr); + if (compiled) bounds[i] = (start, w.end()); + else bounds[i] = (-1, -1); + } + } + } + + // copy and map code + var length = u64.view(w.atEnd().pos) + ballast; + var mapping = Mmap.reserve(length, Mmap.PROT_WRITE), range = mapping.range; // TODO: handle failure + var masm = X86_64MacroAssembler.!(compiler.masm); + masm.setTargetAddress(u64.view(range.start - Pointer.NULL)); + Target.copyInto(mapping.range, 0, w); + // TODO: for security, move embedded references out of the code region and make it non-writable + Mmap.protect(range.start, u64.!(range.end - range.start), Mmap.PROT_WRITE | Mmap.PROT_READ | Mmap.PROT_EXEC); + for (i < bounds.length) { + var b = bounds[i]; + if (b.0 >= 0) { + var addr = mapping.range.start; + var f = module.functions[i]; + Target.setFastTargetCode(f, addr + b.0, addr + b.1); + } else { + var f = module.functions[i]; + if (Trace.compiler) Trace.OUT.put1("func[%d] initial compile failed", f.func_index).ln(); + X86_64Spc.setInterpreterFallback(f); + } + } + // XXX: reduce duplication with {X86_64SpcModuleCode.appendCode}. + var code = X86_64SpcModuleCode.new(mapping); + if (masm.source_locs != null) { + code.sourcePcs = Vector.new(); + code.sourcePcs.putv(masm.source_locs); + } + if (masm.embeddedRefOffsets != null) { + if (code.embeddedRefOffsets == null) code.embeddedRefOffsets = Vector.new(); + code.embeddedRefOffsets.putv(masm.embeddedRefOffsets); + } + + module.target_module = TargetModule(code); + RiRuntime.registerUserCode(code); + module.target_module.spc_code.keepAlive(); + Debug.afterCompileModule(module); + } // XXX not an exhaustive way to add stubs. but what is? def onModuleFinish(module: Module, size: u32, err: ErrorGen) { - installStubForModule(module, X86_64Spc.setFastCompileFor); + fastCompileEntireModule(module, size, false, err, 1024); } } From bcc3dcd86f3a795c1d48bb5fdc740b1233442403 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 21 Jan 2026 16:06:06 -0500 Subject: [PATCH 12/91] Add fast prologue/epilogue stubs --- src/engine/compiler/SinglePassCompiler.v3 | 11 ++++++----- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 9 +++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 89ddea3f4..80313bc71 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -173,11 +173,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Emit prologue, which allocates the frame and initializes various registers. if (fast) { - masm.emit_nop(); - masm.emit_nop(); + emitFastPrologue(); } else { emitPrologue(); - } // Visit all local declarations. @@ -2163,8 +2161,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.bindLabel(ret_label); ret_label = null; } - masm.emit_nop(); - masm.emit_nop(); + emitFastEpilogue1(); @@ -2191,10 +2188,14 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_addw_r_i(regs.sp, frame.frameSize); // | masm.emit_ret(); // / } else { + emitFastEpilogue2(); emitFastDispatch(); } } def emitFastDispatch() -> void; + def emitFastPrologue() -> void; + def emitFastEpilogue1() -> void; + def emitFastEpilogue2() -> void; def emitOsrEntry(osr_entry_label: MasmLabel, state: Array) { if (Trace.compiler) Trace.OUT.put1(" OSR (+%d)", osr_entry_label.create_pos).ln(); masm.bindLabel(osr_entry_label); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index b01bd724b..d90b46a6f 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -47,6 +47,15 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } + def emitFastPrologue() { + asm.nop1(); + } + def emitFastEpilogue1() { + asm.nop1(); + } + def emitFastEpilogue2() { + asm.nop1(); + } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { var b = pop(), a = popReg(); From 50c5bcfc9bcbcc2d802f78ce12da51cd85ce14b2 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 22 Jan 2026 14:59:45 -0500 Subject: [PATCH 13/91] Add small frame in fast call to save vfp (for local variables) --- src/engine/compiler/SinglePassCompiler.v3 | 33 +++++++++++++++++++ src/engine/x86-64/X86_64Frames.v3 | 6 ++++ src/engine/x86-64/X86_64MasmRegs.v3 | 5 +++ src/engine/x86-64/X86_64SinglePassCompiler.v3 | 17 +++++++++- 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 80313bc71..0c5325455 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -31,6 +31,39 @@ class SpcExecEnv { var runtime_ret1: Reg; var ret_throw: Reg; var scratch: Reg; + + def dup() -> SpcExecEnv { + def env = SpcExecEnv.new(); + + env.frameSize = this.frameSize; + env.vsp_slot = this.vsp_slot; + env.vfp_slot = this.vfp_slot; + env.pc_slot = this.pc_slot; + env.instance_slot = this.instance_slot; + env.inlined_instance_slot = this.inlined_instance_slot; + env.wasm_func_slot = this.wasm_func_slot; + env.mem0_base_slot = this.mem0_base_slot; + env.inlined_mem0_base_slot = this.inlined_mem0_base_slot; + env.accessor_slot = this.accessor_slot; + + env.sp = this.sp; + env.func_arg = this.func_arg; + env.vsp = this.vsp; + env.vfp = this.vfp; + env.mem0_base = this.mem0_base; + env.instance = this.instance; + env.runtime_arg0 = this.runtime_arg0; + env.runtime_arg1 = this.runtime_arg1; + env.runtime_arg2 = this.runtime_arg2; + env.runtime_arg3 = this.runtime_arg3; + env.runtime_arg4 = this.runtime_arg4; + env.runtime_ret0 = this.runtime_ret0; + env.runtime_ret1 = this.runtime_ret1; + env.ret_throw = this.ret_throw; + env.scratch = this.scratch; + + return env; + } } def INITIAL_VALUE_STACK_SIZE = 16; diff --git a/src/engine/x86-64/X86_64Frames.v3 b/src/engine/x86-64/X86_64Frames.v3 index 6c68543ec..bf880f247 100644 --- a/src/engine/x86-64/X86_64Frames.v3 +++ b/src/engine/x86-64/X86_64Frames.v3 @@ -21,6 +21,12 @@ layout X86_64InterpreterFrame { =104; } +// XXX: this frame may be differently sized depending on other touched registers +layout X86_64InterpreterFastCallFrame { + +0 vfp : i64; // Pointer + =8; +} + // Layout of an SPC frame. Same 104-byte footprint as {X86_64InterpreterFrame}. // Slots used by the interpreter but not by SPC are omitted. layout X86_64SpcFrame { diff --git a/src/engine/x86-64/X86_64MasmRegs.v3 b/src/engine/x86-64/X86_64MasmRegs.v3 index 9f789233c..53f9ef1b1 100644 --- a/src/engine/x86-64/X86_64MasmRegs.v3 +++ b/src/engine/x86-64/X86_64MasmRegs.v3 @@ -151,6 +151,8 @@ component X86_64MasmRegs { // The execution environment for interpreter compilation contexts. def INT_EXEC_ENV = t.1; + def FAST_SPC_EXEC_ENV = SPC_EXEC_ENV.dup(); + // A register allocator for single-pass compilation contexts. def SPC_ALLOC = (fun -> RegAlloc { var pools = [ @@ -190,3 +192,6 @@ component X86_64MasmRegs { return reg; } } + +def nothing = X86_64MasmRegs.FAST_SPC_EXEC_ENV.frameSize = X86_64InterpreterFastCallFrame.size; +def nothing2 = X86_64MasmRegs.FAST_SPC_EXEC_ENV.vfp_slot = MasmAddr(X86_64MasmRegs.FAST_SPC_EXEC_ENV.sp, X86_64InterpreterFastCallFrame.vfp.offset); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index d90b46a6f..b16abb2bd 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -31,7 +31,7 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { var ic: X86_64InterpreterCode; new(ic, extensions: Extension.set, limits: Limits, config: RegConfig, fast: bool) - super(X86_64MasmRegs.SPC_EXEC_ENV, mmasm, + super(if(fast, X86_64MasmRegs.FAST_SPC_EXEC_ENV, X86_64MasmRegs.SPC_EXEC_ENV), mmasm, if(fast, X86_64MasmRegs.INT_ALLOC.copy(), X86_64MasmRegs.SPC_ALLOC.copy()), extensions, limits, fast) { mmasm.trap_stubs = TRAPS_STUB; @@ -47,7 +47,16 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } + // TODO do we need to spill VFP if the function has no locals? when exactly is spilling VFP needed? + // and can it be determined independent of call site? def emitFastPrologue() { + // Allocate (very cheap) stack frame + masm.emit_subw_r_i(regs.sp, frame.frameSize); + // spill VFP + masm.emit_mov_m_r(ValueKind.REF, frame.vfp_slot, regs.vfp); + // Compute VFP = VSP - sig.params.length * SLOT_SIZE + masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); // XXX: use 3-addr adjustment of VFP + masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); asm.nop1(); } def emitFastEpilogue1() { @@ -55,6 +64,12 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { } def emitFastEpilogue2() { asm.nop1(); + asm.nop1(); + // restore VFP + masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); + masm.emit_addw_r_i(regs.sp, frame.frameSize); + asm.nop1(); + asm.nop1(); } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { From 599e42ce33bbd72cb34e8c6761f62d13a1f7ea65 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Fri, 23 Jan 2026 16:09:35 -0500 Subject: [PATCH 14/91] Add test files/programs --- fast_call2.wasm | Bin 0 -> 43 bytes fast_call2.wat | 7 + fast_call_export.wasm | Bin 0 -> 54 bytes fast_call_export.wat | 10 ++ fast_call_nop.wasm | Bin 0 -> 53 bytes fast_call_nop.wat | 10 ++ fast_call_param.wasm | Bin 0 -> 91 bytes fast_call_param.wat | 18 +++ int/Export | 9 ++ int/Export.v3 | 12 ++ int/Export.wasm | Bin 0 -> 8230 bytes int/Interpreter | 9 ++ int/Interpreter.v3 | 293 ++++++++++++++++++++++++++++++++++++++++ int/Interpreter.wasm | Bin 0 -> 13303 bytes int/InterpreterBug | Bin 0 -> 14264 bytes int/InterpreterBug.v3 | 25 ++++ int/InterpreterBug.wasm | Bin 0 -> 5307 bytes int/RiRuntime | 9 ++ int/RiRuntime.wasm | Bin 0 -> 4434 bytes slow_call.wasm | Bin 0 -> 68 bytes slow_call_nop.wasm | Bin 0 -> 46 bytes slow_call_nop.wat | 7 + 22 files changed, 409 insertions(+) create mode 100644 fast_call2.wasm create mode 100644 fast_call2.wat create mode 100644 fast_call_export.wasm create mode 100644 fast_call_export.wat create mode 100644 fast_call_nop.wasm create mode 100644 fast_call_nop.wat create mode 100644 fast_call_param.wasm create mode 100644 fast_call_param.wat create mode 100755 int/Export create mode 100644 int/Export.v3 create mode 100644 int/Export.wasm create mode 100755 int/Interpreter create mode 100644 int/Interpreter.v3 create mode 100644 int/Interpreter.wasm create mode 100755 int/InterpreterBug create mode 100644 int/InterpreterBug.v3 create mode 100644 int/InterpreterBug.wasm create mode 100755 int/RiRuntime create mode 100644 int/RiRuntime.wasm create mode 100644 slow_call.wasm create mode 100644 slow_call_nop.wasm create mode 100644 slow_call_nop.wat diff --git a/fast_call2.wasm b/fast_call2.wasm new file mode 100644 index 0000000000000000000000000000000000000000..b3dcbf2bfd73fa58e127a050a851e7c035a258d2 GIT binary patch literal 43 ycmZQbEY4+QU|?WmWlUgTtY>CsVqjqBU}VWn%*L#;06G4wFH9z literal 0 HcmV?d00001 diff --git a/fast_call2.wat b/fast_call2.wat new file mode 100644 index 000000000..3dd58686b --- /dev/null +++ b/fast_call2.wat @@ -0,0 +1,7 @@ +(module + (func $f (result i32) + i32.const 10) + (func (export "main") (result i32) + call $f + ) +) diff --git a/fast_call_export.wasm b/fast_call_export.wasm new file mode 100644 index 0000000000000000000000000000000000000000..de5abe4d8a74f8a24c8d888a332931be286cbba9 GIT binary patch literal 54 zcmZQbEY4+QU|?WmWlUgTtY>CsVqjnwX5vUoEH1H1%g<+EV98C)%wu5W;$~uDaAe|U JVGv;81_0r`2ebeH literal 0 HcmV?d00001 diff --git a/fast_call_export.wat b/fast_call_export.wat new file mode 100644 index 000000000..20c428045 --- /dev/null +++ b/fast_call_export.wat @@ -0,0 +1,10 @@ +;; export name holds fast information, we don't modify binary ahead of time + +(module + (func $fast (export "fast:foo") (result i32) + (i32.const 2) + ) + (func (export "main") (result i32) + (call $fast) + ) +) diff --git a/fast_call_nop.wasm b/fast_call_nop.wasm new file mode 100644 index 0000000000000000000000000000000000000000..403dc7cf1dac9ad70c13cfaf0ac80a170e8d6a3b GIT binary patch literal 53 zcmZQbEY4+QU|?Y6U`k+MNMK;BXJ%mra@jc;S#lFI^B9=81euu_xPge1!HHW+oY9ei F8vvyN1z-RG literal 0 HcmV?d00001 diff --git a/fast_call_nop.wat b/fast_call_nop.wat new file mode 100644 index 000000000..c406ac91a --- /dev/null +++ b/fast_call_nop.wat @@ -0,0 +1,10 @@ +(module + (func $f) + (func $g) + (func (export "main") (result i32) + i64.const 11 + drop + call $g + i32.const 0 + ) +) diff --git a/fast_call_param.wasm b/fast_call_param.wasm new file mode 100644 index 0000000000000000000000000000000000000000..c70071c25eaade813ac8547a90cd3b2846efe266 GIT binary patch literal 91 zcmZQbEY4+QU|?Y6V@_bKX8>Zx`UD2XdM18Gw(`uX)Vy?-g3^*q1_owkCPpT94n~&T n#LPSfCN4!LJ_ZE_mU_qM?5vI}>bSWD7#tbJ8G$4NgyaSQ2wV?q literal 0 HcmV?d00001 diff --git a/fast_call_param.wat b/fast_call_param.wat new file mode 100644 index 000000000..b3f4ad728 --- /dev/null +++ b/fast_call_param.wat @@ -0,0 +1,18 @@ +(module + (import "wizeng" "puti" (func $puti (param i32))) + (func $f (param i32) (result i32) + local.get 0 + if (result i32) + i32.const 999 + else + i32.const -216 + end + ) + (func (export "main") (result i32) + (call $f (i32.const 1)) + call $puti + (call $f (i32.const 0)) + call $puti + i32.const 0 + ) +) diff --git a/int/Export b/int/Export new file mode 100755 index 000000000..df2a0f18a --- /dev/null +++ b/int/Export @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +S=${BASH_SOURCE[0]} +while [ -h "$S" ]; do + DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) + S=$(readlink "$S") + [[ $S != /* ]] && S=$DIR/$S +done +DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) +wizeng $DIR/Export.wasm "$@" diff --git a/int/Export.v3 b/int/Export.v3 new file mode 100644 index 000000000..2409223df --- /dev/null +++ b/int/Export.v3 @@ -0,0 +1,12 @@ +export "fast:foo" def foo(x: int, y: int) -> int { + var val = y; + for (i < x) { + val += i * y; + } + return val; +} + +export "main" def main() -> int { + System.puts(Strings.format1("%d\n", foo(11, 2))); + return 0; +} diff --git a/int/Export.wasm b/int/Export.wasm new file mode 100644 index 0000000000000000000000000000000000000000..65fa630c5756a892cb837eeb1aa7b0398e3baab3 GIT binary patch literal 8230 zcmc&(Ta08!d9JE+?XI5bTI_|my?E=iy~ZG|S=RP=J*@4iUGLgUxW?puvD@PwJUz2B zJG1REmWX?B96&&X6-<-|BCR5#<-rz+06|d{d5IHQ0VzBXiHArb!a|X9QKFy-MIh(< z{yN>$y}L%vQ)Z_7)T#5=fB(Pw>x}B1KdY5e`tNslch&sEdZb4WC!-NBDJ~=Ru)-hi zjLd0F@UemqPP8_ht~TWO37`>+vUx3PbwYn zSI$55#P;g2KfWJ6w!QhpL;Vjcll(Ke{1B?9nbKLVv?|I(Yu(7QOl6r#bVK1c!EF$WtQWS=8C!W8A{XV)ZN*~WTY>( zF13p1InJ{F#&G*dmE~vqXE(Q>G%6eR9$D{eRj%~T4;NQ9H&v0I?X7O8yzxz0t%A14 z7fzkN|ADuhdDqXs`#pEQ_kHjGz%M-b#t;7Dn||q+f8|$y?bm?xBaTZ}o0{ z+o8j6eZ<|n+#|Js$ecRqCU9gnRxfBI)){c){F;a{Pgy2YqCnB00b=<4tv^}~0i zOI`*1x<=c2yBdMF1jg^t%i z8?Sx7VA23V5MpW}PIa^KiY(Yc_{bJkBq8I9#N(3s1R}sNxy7U%ss*k-bGieLh9Xn1 z@yMs|Az73PwaEaF2T^k^ntxK<;HisoZ?K;in%On853IG4wh%6MUK_ye+vM8`qtl31kje@_;gs7C8`}17 zB%~A(moSX=qAHE65YSf?mV+d5*LRo>dH4ZmLKzOi_YBNVRUn*I!E`82)vm&WSM`>A zW2a@f=EoB*olYy^%ztqPR_Eb=CZqops>EGaf#EIYJ5&~;vwfNBwDK%mpvK{={DuuV zjOLF|?Z?Fw1XYC}u{8Mom3q7u^yA^&)}RYd#-|JB%jCRZzRC+?gW-j};TPg?Oe=nk zOTPlbFU~%dGL0;xDBJeyzXPT^gD!{FH%JU;eODBJh2P@q0~xajwX+yWXsvLf;k>!P zg$qVxySru0@yUFZnI%^sDD*SO&-`(hoDj(0f zH*=9#=JPdH={PBFkU-QfxW$NT+(FojvaU^^EL||-fr*GJnj&Ofl;(ts2toxXSBN4G z4Q4otBO;?ZX!Q(XVjL+bFQKfXQ^yxtrjr;`%a_G=4FPckPuKo;H~9qK`CUn)Yy`jo z#K4mg)ru=Isvt(`Dn%GlZwQ?U28628WfZGJ!OoN8G}s&lVM*1GG}s zS0bSG?@u#{+JNYBJrNJO`@C6mhk#R6YL@sb^7oydn}Ln7SUnL7ygkG+PW?WBr;v-t zu8T10Ch9=PZYvVQV`X;^%43jr+t3h3M|I{fxw_#c}@8|sdz_+3;hPD`_4ulx2 z`ZgW!TWy;~)N72H0!jCnHptXQrj|^bzTumfIf(TxiowxQv2vP6P9A0CQIbdDb6-sJ zNLm_*Q6*A<+%ZJCFtSfe@N;B7Y$TpR+1mMF8sUwoUtt@Yn#YD2=~F;+9OZFTgE-2J zBd$zk6p1nrkuQ-z_T3cw8-oAW^p#Es{Fr%I4Z5;Exv zut>}9a&spOF787*xE-^Gb^&A=_#0xbnlM;7kBJBJY z{R8}rD9LXzsXG^vt@#ulNKzaAkgEB)0c-`l;b!;4TNH>k%^huL;R0q9@aHE|?uZzdmqBXgKRx<{s|?;#eq6VQYkKv%;2NwFIHpphW?cXOlg`xCMx8GG72ZZX2K_0Gk|`Qg8P@ilWPRvc<;=tWbQb?A%1&O^RK4}oCfvKJFlUS1>-3jfjZWB`5 zTR=+cLr)9eZUYhO@`OW&>_U0vn*yw3$So$WfDGS=pxa3=&ddzLrx5`u&>$%h;rleaRNjC2`)kJ7k{V zxj^8y_ItttZIiwzJhB(O{(!WQ*_a6)kV`UolGJSU#jcr58sV71SK8efc~4q^RNuTHu6x+&jTQ~tR)0XrSF>N1rAp%vK&RTmXbaE!xL zrlE^NG_c7VS~>{>$$*J&g1Jd-NfN`2iX1Oy-WPsk3MUF0D zVlTs-ir%1?x=?~Am8+DwiDeE?Nr}|GP8Lf#8P^8F!I&iDFv)|y8GN{_qR!L}Wz1~doACu{#!%9bF;trO>9hymfW1a^XZz6yuwD})gnCd&F4=owXb%pJ4# zPbD9+QHFfD*ezc0irWHD7C4@2 ziOzdDtD00*$;&a`m$#^s1(+z*wg&D#r^ZtjOM|u*jh4=#K)UhNZmVApb1#25;mGOJ(`dNXew)CW99-D8ot6s zaN_#*_(%fX6HhcR1Q9QKq%^iPwq}mjy?I*vB%v9 z-l75aY}5@8J=yf3$H-ha5nl1Mlem+3bsjE&IgR5PDjs3neeoT7$(ThZQ^yjXQgGgg z-4xz}fQFkPoaIsWNL|1e^9DO7l8cdtr}z&GR)~0txhntX8oy+RuNz+8bC_^R4cMZF z<{I890N#$sZS1QOylJRkU(0q}M+_M%Sjw%qZNEl)X1gQ}?F=+Cu}jjjQKKc&)QP1e zoAuQlGkHtjbN(Oseth-P5x-&holpPg_5xfAci`?X&dP?9pF0 zO;*^C*E+cu)!z88rp7O+y|qU!H{pP_|4nSsIH+3zuTm++4}W&AQ2@yJk%|A~R|fh7 zpF@u}703MH)#7t{bNg&>cxrolb6e&*m>X_x`m?=_C;f^%^ykm@mseL-``hPVd)?1r z-Rj0pZ+-RAE0$4KfzSQRdvb2X{dS-KYVB-8-48eYgZ;Cs51#8S_itU^Twm`m z4@IXGw8QPk`{cvVN^kvqA6L#Bd~U)Q=Q&>VaZG|l9KG%KI~MLdc2_uY^1f52x%P7X_har%ZSUqI z1E}gB>-Qe*Z)2W%X?z~2^|}G$sy2SnkG-_rU+Hi6H=qEv?uniL@IC%&@;JBB8}`<5 U<@h>$e%8(^b literal 0 HcmV?d00001 diff --git a/int/Interpreter b/int/Interpreter new file mode 100755 index 000000000..55ced8cc9 --- /dev/null +++ b/int/Interpreter @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +S=${BASH_SOURCE[0]} +while [ -h "$S" ]; do + DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) + S=$(readlink "$S") + [[ $S != /* ]] && S=$DIR/$S +done +DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) +wizeng $DIR/Interpreter.wasm "$@" diff --git a/int/Interpreter.v3 b/int/Interpreter.v3 new file mode 100644 index 000000000..9cc0be2dd --- /dev/null +++ b/int/Interpreter.v3 @@ -0,0 +1,293 @@ +export "fast:const0" def const0() -> int { return 0; } +export "fast:const1" def const1() -> int { return 1; } +export "fast:constN" def constN(n: int) -> int { return n; } +export "fast:add" def add(l: int, r: int) -> int { return l + r; } +export "fast:sub" def sub(l: int, r: int) -> int { return l - r; } +export "fast:seq" def seq(f: int, s: int) -> int { return s; } +export "fast:select" def select(c: int, t: int, f: int) -> int { return if(c != 0, t, f); } +export "fast:nop" def nop() -> void {} + +def HANDLER_CONST0 = CiWasmTarget.functionId(const0); +def HANDLER_CONST1 = CiWasmTarget.functionId(const1); +def HANDLER_CONSTN = CiWasmTarget.functionId(constN); +def HANDLER_ADD = CiWasmTarget.functionId(add); +def HANDLER_SUB = CiWasmTarget.functionId(sub); +def HANDLER_SEQ = CiWasmTarget.functionId(seq); +def HANDLER_SELECT = CiWasmTarget.functionId(select); +def HANDLER_NOP = CiWasmTarget.functionId(nop); + +export "main" def main() -> int { + //def prog = Select(Sub(ConstN(1), Const1), Add(Const1, ConstN(100)), Seq(Sub(Add(Const1, ConstN(2)), Const0), ConstN(15))); + def prog = AST.If(Const1, ConstN(2), ConstN(3)); + + //def prog = Const1; + def bytecode = compile(prog); + def val = eval(bytecode); + + def f: Func.F = wasmCompile(bytecode); + def val_ = f.f(); + + def buf = StringBuilder.new(); + prog.display(buf); + buf.ln(); + buf.put1("=> %d", val); + buf.ln(); + buf.put1("=> %d", val_); + buf.ln(); + System.puts(buf.extract()); + + call(); + return 0; +} + +def CALL_FUNC = CiWasmTarget.functionId(call); + +def call() { + System.puts(Strings.format1("call=%d\n", CALL_FUNC)); +} + +def eval(bytecode: Array) -> int { + def vstk = ArrayStack.new(); + var pc = 0; + while (pc < bytecode.length) { + def instruction = Ref.at(bytecode, pc); + def opcode = instruction.opcode; + def operand = instruction.operand; + pc += Instruction.size; + + match (opcode) { + CONST0 => vstk.push(0); + CONST1 => vstk.push(1); + CONSTN => vstk.push(operand); + ADD => { + def right = vstk.pop(); + def left = vstk.pop(); + vstk.push(left + right); + } + SUB => { + def right = vstk.pop(); + def left = vstk.pop(); + vstk.push(left - right); + } + SEQ => { + def snd = vstk.pop(); + def fst = vstk.pop(); + vstk.push(snd); + } + SELECT => { + def snd = vstk.pop(); + def fst = vstk.pop(); + def cond = vstk.pop(); + vstk.push(if(cond != 0, fst, snd)); + } + IF => { + def cond = vstk.pop(); + if (cond != 0) pc += operand; + } + ELSE => { + pc += operand; + } + END => {} // nop + } + } + return vstk.peek(); +} + +enum Opcode(handler: int) { + CONST0 (HANDLER_CONST0) + CONST1 (HANDLER_CONST1) + CONSTN (HANDLER_CONSTN) + ADD (HANDLER_ADD) + SUB (HANDLER_SUB) + SEQ (HANDLER_SEQ) + SELECT (HANDLER_SELECT) + IF (HANDLER_NOP) + ELSE (HANDLER_NOP) + END (HANDLER_NOP) +} + +layout Instruction { + +0 opcode: Opcode; + +1 operand: byte; + =2; +} + +type AST { + case Const0 { + def compile(w: DataWriter) { + w.putb(Opcode.CONST0.tag).putb(0); + } + def display(s: StringBuilder) { + s.putc('0'); + } + } + case Const1 { + def compile(w: DataWriter) { + w.putb(Opcode.CONST1.tag).putb(0); + } + def display(s: StringBuilder) { + s.putc('1'); + } + } + case ConstN(n: byte) { + def compile(w: DataWriter) { + w.putb(Opcode.CONSTN.tag).putb(n); + } + def display(s: StringBuilder) { + s.putd(n); + } + } + case Add(left: AST, right: AST) { + def compile(w: DataWriter) { + left.compile(w); + right.compile(w); + w.putb(Opcode.ADD.tag).putb(0); + } + def display(s: StringBuilder) { + s.putc('('); + left.display(s); + s.puts(" + "); + right.display(s); + s.putc(')'); + } + } + case Sub(left: AST, right: AST) { + def compile(w: DataWriter) { + left.compile(w); + right.compile(w); + w.putb(Opcode.SUB.tag).putb(0); + } + def display(s: StringBuilder) { + s.putc('('); + left.display(s); + s.puts(" - "); + right.display(s); + s.putc(')'); + } + } + case Seq(fst: AST, snd: AST) { + def compile(w: DataWriter) { + fst.compile(w); + snd.compile(w); + w.putb(Opcode.SEQ.tag).putb(0); + } + def display(s: StringBuilder) { + s.putc('('); + fst.display(s); + s.puts(" ; "); + snd.display(s); + s.putc(')'); + } + } + // eager evaluation of branches + case Select(cond: AST, left: AST, right: AST) { + def compile(w: DataWriter) { + cond.compile(w); + left.compile(w); + right.compile(w); + w.putb(Opcode.SELECT.tag).putb(0); + } + def display(s: StringBuilder) { + s.puts("(select "); + cond.display(s); + s.putc(' '); + left.display(s); + s.putc(' '); + right.display(s); + s.putc(')'); + } + } + // lazy evaluation of branches + case If(cond: AST, left: AST, right: AST) { + def compile(w: DataWriter) { + cond.compile(w); + w.putb(Opcode.IF.tag); + def hole1 = w.pos; + left.compile(w); + w.data[hole1] = byte.!(w.pos - hole1 + 1); + w.putb(Opcode.ELSE.tag); + def hole2 = w.pos; + right.compile(w); + w.data[hole2] = byte.!(w.pos - hole2 + 1); + w.putb(Opcode.END.tag).putb(0); + + } + def display(s: StringBuilder) { + s.puts("(if "); + cond.display(s); + s.putc(' '); + left.display(s); + s.putc(' '); + right.display(s); + s.putc(')'); + } + } + + def compile(w: DataWriter); + def display(s: StringBuilder); +} + +def Const0 = AST.Const0; +def Const1 = AST.Const1; +def ConstN = AST.ConstN; +def Add = AST.Add; +def Sub = AST.Sub; +def Seq = AST.Seq; +def Select = AST.Select; +def If = AST.If; + +def compile(prog: AST) -> Array { + def w = DataWriter.new(); + + prog.compile(w); + + return w.extract(); +} + +type Func { + case F(f: () -> int); +} + +def wasmCompile(bytecode: Array) -> Func.F { + def w = DataWriter.new(); + + w.put_uleb32(0); // 0 locals + + var pc = 0; + while (pc < bytecode.length) { + def instruction = Ref.at(bytecode, pc); + def opcode = instruction.opcode; + def operand = instruction.operand; + pc += Instruction.size; + + // setup for handler, if necessary (guest-level operands) + match (opcode) { + CONSTN => { + w.putb(I32_CONST); + w.put_sleb32(operand); + } + _ => ; + } + // call handler function + w.putb(CALL); + w.put_uleb32(u32.!(opcode.handler)); + } + w.putb(END); + + // create wasm function + def sig = CiWasmTarget.functionTypeId(); + def wasm = w.extract(); + def fid = wave.new_func(sig, Pointer.atContents(wasm), wasm.length); + if (fid < 0) { + System.puts("failed to compile wasm function\n"); + System.error("error", "failed to compile"); + } + def func = CiRuntime.forgeClosure(Pointer.NULL + fid, void); + + return Func.F(func); +} + +def END: byte = 0x0B; +def CALL: byte = 0x10; +def DROP: byte = 0x1A; +def I32_CONST: byte = 0x41; diff --git a/int/Interpreter.wasm b/int/Interpreter.wasm new file mode 100644 index 0000000000000000000000000000000000000000..efa0a14d209036a0fbc675b325e7378e090c282a GIT binary patch literal 13303 zcmc&*dvIJ=dB5jA_H|dK4)*NT6<1emZko2b#>LMJZPzv2h|F`>=k}HEAp_c z2VJyQEP^c{STd481^XdlKP1@hig|jR0#x%&&UyxM?Zr7TBGf zU$|g7rr(Uuotj>1PNx0o_NjBNdM8f%owKd^bEo3-mgjuo{h<0e<)(kwjBVSF>ndd_ zM=6!VcizT>O$_DiLeWvSa)@Tz0J&_I@L$PuogA=oZV^4l@qLUdVB}m-C=`?`mkWhl z!2yY4exT?S^Nw8{#O#55u9(Lp`E#6tS19C*MfVYISuI!--iM^6E|xEr^B*M3WiM`a zS{JOXxw&|5zIDO2yiV=(Y^*GQy4LROpPX;DJ3FnxOmCM}$@K29f`VYyrlzbR(`+xD zwuX~tyl8DQ=_isF9?TUMm}le2G{d)EWg&HDVi7ZzLX z&eHO^^B1n&F?#*j%}1`={)X4T@jbuw-uFGUvZ~&%9#$VvkErm2>d=SOi4UvekE)NT zkE&ZfrjCAG-SY|c_TN_HpH!bx_kLRK{ERyAS@oFGpHtP(tG!=P`yW@ke@E>q{n2+t zYmR04zwRS4v?9w-8Y*dM%l|OBx3r~IBh#Kq5tRQ0BlQ(+jk|}m9Xg&?p;NYe?f4&% z$rb;T@{B%3r9_tn*92Er`~ym@M1KsOS=(*PG`d}FHL5ClIvIQm=z_V(3SLw3wHmW6 zzX*uGPh?S?M-Nnl_QutLJ4c88P| zs;C@XUbP|@#3KdT+wjpNSoY^+UE4v3j)AOlMXh>}pc-5qTn6cVRd~s*L{D)NIPijq z3xniLH5XYY+(YQ)B6l__G_anEHeo%jbZ*RcBNf^X1gMFI1+A)=&hR3?5xsX2Gn~ld z3`gVPY6nYD&e-7yCOV+1y+DnCqRk~;tuUnB+lgjYZD@xCFx&|3vVyKEzHj*-6$Met zSoyI3MRt|F5^cqrb`)?5g>Y?E1+T-_uk*hM)mmzJMdUUdZ6?NWupNT5LI>O6?#Y^l zc3o~L0kEqbVF>)%jc}-MWaw6zW<>?SONE|U%hlzGO-1Q^g6jw_$K5dJX;*uV zFh`Ue*tLBFfC|w90C2dTC^UGzsPsP`PBcUv4jUZ~LxXwj`T7wE5Yp=@3P!qtqI{z$ z|B{OGUtLi}Dym54)~Tedg=$F`Bl{ROnU5}7!HyA~*X3Yz#N(WN6aWIpe?mO2m{>5v zMYV97(QaNBuo+zneQX_4@j1)qEET#C<#lNwfCTCOpepe|1PPIf$MoQV4G*LLMc?O= z!PU{rd`6E_mcb3=DuVaHb;RyrKD2xI482kLpEh2k3_%s`3U-cE{EsER6_wD{mj77K z*Dx3K>|l4W3j;q$ypF0UR6%7W`VtrRL^oAir-Y%YV=e+NmoJzHmWMA3u|53*kjdAC zureVU8Ubp?9Ye)!Da=Cn$iM>!%>Q08RrYI3d}N4%=^`N7!QM0vSpMT?TPcr-$IvDn zYzN5vII}fZ_Q$U>_GATP3>wDoyAAABAd%G|jhW!4beq{tmkn^Uc?ACNr_64a;3}a~ zMI|Z+9LvN1bHVXeASw~FC&3941uq_gX6PF2*$h-Ba%vZn2^~h*2I3IJM;X#WmH*R( zTz5~dSX^Rf)f`RR(jJ1o-3j)A1+i@U8uxBkK`YmeGj`GVUW6)p$05?b+f5^$$2h@FYgl)aRJ{vEZ zh6E7k5ZuGUe?_2jD13Dr)_{{T2u06W+GQV)?3!+rUqb3mJsWXOY72>5PLx}UR*nt8 zZV}uwj5?ge`UBa=1jb}1!nFS|9a`nOzJSo1v3V1O=?SPKvT#S74|;dO0yKpdLP~1v zP^XE_iZi9yNRT`raa7a}17g??+=~D0L=qyo{g5VIKCuY5YAoW?mYB-)%cKP1YUnL^ z6Gi_LAtMkD3Xtf_j3Ci7CV)XI75~pf0*oJK3M-RjQs|mlFxM9?W4caoXoP7c7yX2g zs1R+VbvRLB8EFe*khGN_H`Xhq!v9 zeqWvaS7cS%M50FqD46aEfDnI;SXGx1+mxY@x?#itBdAHueqb6#bPzN}msESEJ_T=Bm>bvm@kN~*Uxan*oOVtOSS*4- zGq`btL77t!VDLb0WRd}O(5t#8$3PCI0nM6*i=tS&GxT^?$EbE+pg2GSa+Wye|GUTs zS|Qb{4IynL7T1Ucc13H0ksuU%n%H2AvZ$I3&7`V_0I{^wXfQPtXawm7d{e$vApX>| z7)Po@+MWpzFKk9m{u2`zIyL}O1~F6egL-PmI80nihj#T4l7yg(4Oby&ia6-nH_}73 zY>;KM1K0=}F3NAFsU#>3a8gAk=?WAc4(b6^-MVa?1BJbd2mlefs2#^lNYdqsFS;mH ziz!hQ9zCK(67ANUAd2cxm)3Y3Jzp4u=NiTeSsFRgC>X{HWGoLO$!BT6>{v51MSwpj zT;gT4;u|N(uNAo+><?{TI)M3};jSg62>bzkhPbP92wz|&t4gZ<~ zg1JZ>=>`ggSo=5+Sx9=(mrO&915y3}%SeD$Ez9zMDW-|DS`wL&f|hXzC&R?&84-d~ zaxytO;zfZ8;3^7`&xvLZ4_&lZoW)?AAs@n#B#j3Fi05fbRA3H?^pY;t@ezY_!uVlw zHpemFioT8jDc@g7+B1<_iWU|dICLkFG5c9=Wz2q#570&P>0VRHlpgLgW`u;l0>p3j zx+Ed@3JD3WT=Bm~5h7JY)(#67BdZqV`!r$Ev;2k68NF)ongSVAcsW$!36G*eE(0R zV1Zu(8MTpkf9UZc>A*|V0gSxVsKQlEx+-+jRo=v992V(ldE=v&&eKcr5bujHhX2aU zDM?~RsfG^zp?+-ycazr_$ZP1Z`Jy!CPS?Md7;$z9Yntk?7~f&?0v^ zsw`GL z0mhXcnWTgrV0&SrP z)r0oEhIXd3!U3C=w2>oIDY5Kvt5u**#V?@Phf~dMp;FwgPf*UIS6Naz^D3SD-Eo;%w$83RA z{LdStCuH@f`7P1wt+=)9rW~XK=MYP2hA7+IZQ#gnE((#Ix~F*BlsK@qU^X7?8-QoI z!mR_AjdX)6nh*q%fN9Q?(tk#fNFE1h+e0QcAvZZr<9gTf|A#noNZf9I&oCR2pEgVq zhOjD9mlsg8!61zZTR1KtIvDSuPqS1>x)#vMj}YmiAXG5_3y=bp8#L_mJ3MKq3M$d` zpKPf*5IKv3u3RAc(c@%O4>WikRf*79J-^5WE6`}I;zbe=Q5(I2zx*PO|F~QUPD6}h zpWz^`I0qtoSr5)Of>Yc$+z>7d*b>VlI$}x4+CmmrT*%dBNhW1oV5#k+I`V@WiY~Z% zSkBym`8cK~3>1X{B@7^Tl$grWOl8P;NJn09x`87Z$mDQTO%L3jIm#kP&X7S=7!rKl zS=`P`aZVa!Fl* z&?5!zq8D*hibM)H>I9t4qEeHy2QM{yP%?Q`S|DcG9QX!g0U^#aTO>z;97CYSm3_4O z*w23G@PYvr$MZ5mjoYj;;01rC?DSWUjAhC>T>W8Kn^*|L4J!U94@UQ z`s1Pyf_3ndP^n)IKVn#56$Y-|FB`6L&j7C9f!!UpCVpelU?bN1L^StjL~}nx{S8^e zTvFkZLqd`6krnn76`(2CjY`)?(d4Q8F2(01*P^@4-DWm_sQBF)<4_ zBr-phJV274B}a&DxUz^=+AskZtIaI>pE2;~AHi_+62F5RP{~M5B0}PCCk&jt(=iz) zLV1cv&AK5{%&1@sC+{Gp-T+$0UYNOfD`Akyml7U?%WLUyA317%kfnyeRZ=PKS8V1mkIgi-IzYo{r`qi8`EZuE)Aq!5u8Y z{za%Dm41qi(84^+lp>g$qd%A@(qM{@LxqD}C39JqLN;eH5g8CG$^-K&X%z|HK21i9)C zM~{9GEJTm-TPkTbP@YVqzLt@1_KzrzJSQX1%Lqzs{}YmMArr`9hJq9WA#57=xR+R|avZw#;=SC}ljZB<>;+ z@>@v>U_<`qpV61QzE*XmR?S6FMN+Hgf=0Je&1EXpfYH}j5Ke^P4RxxQty6K`3|Q3> zTBbmCf(CyXGm6JAGWau9XD}nxJ?KDZhDfH8WMPRC(Zn8HumXpr280EtGZ)+*?FL>2 zO$Z!YsOI$?x@1X@-HwMtb52G`SkXOF7D#1sX$Kyw+>;I(um6F|N#JhAGPD5Nlh{*egH92Q{U ziP(b%Q~^4SC-llJsgIG8m^?h-AFT8jWrzy>zqkBHyW_#@vYl-{ZhmBDaCH`bL$-5G z56SXB(xdc~?pq;d9hJT$V!DnGrvUBXMO1y=SyWTt_G8-F)%Nv|?MZ$=4lc_g-PmL4 zwf*=v`Jd=t>jzd3_sU-LV6S=A+9}_$Qr0haUvE;uKd%w%x4Kw=vu5NkGPAyyY5!}c z{nJeQXPNeoGVQ<0v|s2G{g3;4|J2v}%Qf7*)HnM5zTRJV_wd~{v;J;P|9M3JZ}6H> z;Sl0W7%fvl*W)nGb1ce5Pyl*?3BK=Jn+K+ydJA9Nx^-d<^?@1gSx#CPu8dFajX66 z^R{AMy}4YQtxv6+M!GKPwwB_Q*Xi19I|hvXJU+)Kdpul?ekq?E_+0AmH^JEl z{`NVCa@I#sl38xEHW#a3;e|)*ca>G|DIbI@||nFP+}h4~Q2x_mMI0wr=S|!W*ua z1zEZ@u*-9!_@1BKnj4iDZ?EXX;Onp>gD2}JmztgWTs&HD);q5$_xfihuiVr}(YWbr z`-sGFj;k)uqS1?w7}RaU(Zt=OM<|_Lqf_>Jn9SeRe9 zeoJOGFn(%jHa@*)_l` z9JS7ffcFf`#@eF@NoQiS;k}pjqj%;_|HiEuC0}!9cK&p2c64rR=iZygvcis=Q#S=C zNv=IQwX|Sp?i)(hIfGZ&4d~{q^lOugOZ8T~e~rEq@SC>wbA;XAvvBu3H?dw0?KiK7 zz31Rf{S+qgvN;8Cz3ziEO7#H_-m*rhSo*w3?$G*yDH(_c8PO%wibEY9>h+Tde~lIQ0rHbZX!D8eI^&d}`0`V;jQ9_8wmkpE|X)XZMMX;PpMbZ`}yKG`9CG z8^P;id*8aX7ab&QkDs567nrSY+jO#id~(zn-NaxYoM!@*Zj{M#wsXz;zm4c-OGtwU(O4>P_U~_kix(DgtX`nL8y(oeWZ> zbm@tpN6#>I_fTS$JsZ4djlGG`ca6P$Bk-Qx_ih9p+k4*@_ys%&h99@?nr|OPRWVna zeFr0U3Ql16Uv}Gk^Gpit;l6WI7M>tKu;q?gr@kB?LuCY`jB66_Cf~Ioxc%-;>#%2= zr;J!2wKIvJ9yHQSk~Jy@@LcOj^JF}Idu`!#4={ed1Hj~!6K88v^XDWiCK4W{^aU`r z%`AOfLPB=fK-%$ePZu(4cD^&c;Wie|n59kWF#%s#0D@@#zm$k|$} UVJ4#bn5!*t;*0?xt|x&11xP$it^fc4 literal 0 HcmV?d00001 diff --git a/int/InterpreterBug b/int/InterpreterBug new file mode 100755 index 0000000000000000000000000000000000000000..a88079884ac045c9524394129b06524883b48ba5 GIT binary patch literal 14264 zcmcgydw5jUwclsvOy(qv%m7hGMLmIm4%)zkhX$|c009ndfJm^WT&j5uNhB{P14gga zfdj~N)FSFF)_MiC)q2~4qBfu%G6@F7))KT9#d>)to*1w^RDxLM{?^{-Odi_W-aqbq z-HL?d|m%8YN`FY zXq}^9kDzCDZJTJ;f>zJpDTDpjrDu84HC{>c88G`x`>$(pn*E-rtMAIZlop@p)9zj1 zQ}SLjmSISXb!hjF+Hp3OGOp##oh?_RbUS9pPHFZ@#fupWpRfJfr1_}aI#`QMnu~ zRhzQGtt#%7v=het=U{D|(Cc3?_bO5dX6QTe+v7wyUO*$QKwIGR>Yqs9M%B+U_dQ#u zFt+4#Mek6I)6fdY`{IQ@btfAM3^7g4YsCr$%N6RL{HpujSr{OEUUVqQ19mNWK-H3` zRj67qo&jfCtX+${d|*advWG9#+dz2u5WQ6bG7r{z2x<2(wYco#JOU+spr;~m<{>@h zYq3IKPy_ctqd+FCSR$HJcoR!8s2Eq8gPNxIF!#!_geQInAM}t$@-;9TEF=*M!Ip6= z=3kA8q&5&QA_aN$vx2HkUI3)=-5VPtR;#j3jAU`mlkMJhv5g&SdtqU7b`y#lVcr5BepV; z!b;6qs&4jt|9lRu=gb2~E5n&DO42dA+t6x}@mRR49q?gpK8rf-@+l$O`Em3OLjKScYRH*e1CJ)1u&ZKn3vt!D3bEWJuGIjy5--sdu>b!#zg) z3lVJyi+?9SPQEtWUO0Ci%YSfhzQlKnD(7zCx%}N#qdTUb7D&Le0Kj8BkhcJ(Sg>B zMN8~AH{N)ZukGh?My%gt~krOy#4x{G2jP8OUsq;WVM+W5d85pk~e@jZ#plA#pHi5*x)#~we5 zyj@&m3Iy?)G(pAQt0=wb;_)7PhT{gkN?enTOnxqMD*kqD`H?7*F-bHE++ugH_9X%s z6D^#he9TWP%S=7(Yqut>Wvr4 zlXtmS7Z58+r9)P7vA_#FN*4t>G* z3Z^Uoxl$oXW z`U&)mye^(W3*&R;O|a%%Xcq zYX-${jbb;Fo(aMzydpD9yK?vMFqe+QU^{5?V4qm~X z(T*M0636`J3B8St5j7(sv}z1TIzw9rzEs*bZ`>xfX%yWAh|((9JU1S1+~tG6VkbS| zbri`NgD#9rk?28sg*@FDBBWJGLBJvlEIccvWhp!9LT!iY(+MZXhk*fmu<36UcX(*0 z6exCrTuN#){)lwbv^TS0T`%N;A8>SBYpEP7giId5E*#)DfOzZ~cND(MmN~dzlrtzeoC^XpAZ&sg6KSCP4`mnNVCo2H$L2_C3a5`%ol)=H=ZB61Af!(T7HO|)ge#vuXIUKGS6s;CuS^x zPRZnO-RU*o-(!D4KWStO7P=mx;G0$((^^`p1R-r}OVtKCxtO-Ri#oN=)0%$Z7?ec0 z*)g1wycf5>9y&2m?l#N4RAP={%|U%XuW!hv{-=S>TDuu_C>{F72^2xZhbF4E<)>9V z2)OmWd2S;PHZise`J{Wrz%g139aL+%w3gyisWu9}&qEkOVj%=?A~mq&KzLB05JXlkjllBZ@$ma|8mVhfuEkA@9Kk6JI>{^-xXi%C%@g z@_tBG;+709DDsOXKu0U6iwAGcJ$xIv4MHTI9e9YxEWPzh*am4Eb}6nH)F5_f3Jn3X zm4|9LidW(O!fBBe__}b#;mH84AbdNJO=3O<5pxR6pr~!L!lS{=Tf8=fy4*T^gx2eb zbtVE-$blE-nx?tDi)NC$0@01F6hW(L{kJh<+2k`hz-5u{QKyKi9P znRYqSR3EoFdM1@h@Oygi`Enaw2hvT#>@{A&JiL}HHu+4C8gG3@#A!DY7LDGu@u1w7 zSQJRem?-zTubfny#-k-XCT?Q|FoLGiXVAKf?!-{ys(uTN*H2?QvgBS=*6fFgwchT8 zYEe*WK;Pk~m9O)Jzd@Buz;KEV;J@ts3M|>1ORWww+9+I>ZVI z+scE028$$DNJkEe7)BJHO|}OA!JCf}qi2QmoC0!5`ohux)$rxwk%s%;&BO@r#klFJ zeaD5rQ2y|o9S)Dz3z}x01{B(`EJ&U3Ym9XN4!e22*v-5>Mh8q=tRU*$QR5-XMvw;* zyI@3wIc?1DG)8h~p7fFKFiGWs!T6y#3yWaj69x0}>`@dpjW~^v0CWyoq%{Or3YuvO zXj9-crcgNN^s`NcX2Z?1O_U}(;8po2cAY&^r3?M+-0)j61x^3 z&d&n6&x`mk1koUnI2W>c?5A~fW{@b<4_&D+9y&5b&9n_>t?L8??LYBe~Oc)yueT7JXGS?p*F209J6EC>P~Ij8p}`-PCygaEeeFpY*w~w#p^!j+hH^gM~0^2`+ z5_yGdjp83vMh#%+770C=g7Z6Iwb>1x?;zX8Q&app9)=U z`#kT2CHsuu12-;YL>oH+Cri9#CeOggm*Nb)Ye0VgEy{q+Me*l3uO#eNbTcbL#APM< ziOs#~n2z`Cv3;nBmojod!SYLDmB{Ym!!JMnzb>p!X1l2&4&ubD1{sZ0C#v>A>|O#u*- zc_Ll}d5RG9INvh}4H(BHdR%@%aE%ERXM_FtEu_?jp7Toxp{Ai0M5P2}QTKmSUy%Cp zX(hgJR*vCsgh;Cns5Fd~*ep+(qd4M?2o`pBj&wa+(y&(I?-oz6B4t7 zs``;YI<65rB1(d~pZuOeCT4MB;E5a*!2Q12>;}0zNRY4kJr{v{(Zzf&t#+CCg?khF zuAKBB-F9Lc!iLL?*7+jO-*o!Z2jRZt(ZIbk-Tb6DTAGVLwTN(xdlC?v-;uhd1_1ToDu^ z$n;cFO`lxxSx`Y2tjN>Z1$V?#fdWJd)+#ZMmmY{b-M^r9mO$V~qy2yh;`blx!b#Rh zb7^O}aYEnxSVnk`2aGGB5)22pHDExI+G5$hC9hoykG`jXvqy29IKe2)w_lj>!X0En z?*}6&_;Drdhv-2ySloRd2EnB!)J}F&LVOkxpBl{r+n9k0x`@@phS8?&Y};(rhy&w- z6WBofJd{KtNK=Etp7?Vvc^gm!okCphYZ0zW^TZa`eA2u~to!yUhaMtJPA5;i1a;^I%H z0-aOzMp)%JF=c7|J|;G`PnPE6c=%Q$kYXPHnN}#DPmX1DUC-wrhW{33fnD{|uhkF~ z*y+AR8x8BjGcsKS_%rfeZbp!UPcSI%2?;3Da<#>fN77y16m1IKF5EgjWbuhp$gbTh zdgb4K%-Z<`!&J;;2Ky*&Cf2CIA8-?XbBdN;X1saWGL!UNm8fmgthtGN3-L|jeUC1l z*cW&Yy~7>TbOX5sxB6N1LkV4vSAT*drX#2Xcw2I>{(!eLo5}64p|AiROZl6e-s5rK zJDZ5|M|@ZmRN>V-@EZ8>)%roVQAM{YiU-gnT_+G7p)ip&U^7Y0gpu|IrMLSTLbR2e zV!t0V`uI#fDPGs*V&HD`OK;djOCC6#G;q3;?~rR}xkP z6L^D}tx~QJS@MlsNC2Y2_I_TF4=?yia$0Up#liqF`}fn*pY(A5!qYazGWdG`sjk7K zrldi+s7g$U+>?H!0&dk45AxX<9p$(Sb>uMXK^QZN?xuu@$(f2Dh=&u`7ss z=!*wuEj~nxA&Mp8hU9+wz`#q3MTqYHE%*_?j?gCY{KEq-KynsVLqh$FO!s|snZz1Z zZ=K5D(sd&XV}5k`V~FGDr-uX9Q@eO@791;d)Z*DO*{vW%=x1>A`ZG2nULsF^-MxAb zs$g|ZHn~2}q`-$C>KKp$`O_&78G3IDM4JoAiN-%nZQj5nP=EuIoLt{Lry^xQx!lF@ z6{l#Xq|KQB$j0>*clr3Kw`9+yQYRUgm8z&f;DH)wmdX)zzd&}e9ML6pmoXOKu_TD& zA%_IKe*X7v$V=V0@cYJs_fn}Jw71|j7)J}f*5iLjDA-!FR2`!2L7xYPw-+!R9#Vsj zy8yq&!Lt+43D^ht1dt~wZ0Qh%y)FgWy8r{=wFOxrU=v_FU?-px@FCzRz-e1R_EW%b0BwMM0H@8yase7(5nvhM$AG^;Mki!B4^RgnIiCZ3 z43Om@8xOb>kl_fj)i`c;y=Y@c0gpIYbocozD*0LTo_rRaHk(Cr7P9D~n_0B&DhDgQ z2yuRp%mOYIJV)7KfO1ZhEdpc?_OLZ~GWN3@8G8Zn>RiU&1N;q;Kaa60fXZyF1h5Iv z4tNjnSAYUpqC;f%8ep2u!|DL*0e=PzwnK-2g@CCJy4&G{Pz$r*kb#nbvEbhYvZoCa zV{c*60z2#}n8WVcA7sDYAC`6opOZR+ZPLEr9_f?KC#0Ot`L;YjUEWgL(r3fA*QcJa zy?gwm%}Cnp-nI$$!WB*SP3vB;zO(!-d*`}C_7B&|^3msp$vC@Ze?@_;AJXNG zcAMknEq2H26|&=hp2%_Z3@djG_KlDp{qzI-xvM^7`48=JMjeNoKmPCo=VO2a zKmXL}Sv*1VE^d;ppE=Tb^Xg&Fwv2M+?O&8DpI)&-8G3$`GJ0o|GHF&snf}o_WzJI@ zm6EEH()&C2NU0m%lrpqV>B_wu*|4qCq%mFBNzcz-A$|PXIw|8j_e*0I=E&tAA7asG zbZPB{4@imIlhT1*gdDH&B>yX_)r`R5xbHH9y_vASZxi30?b#aCL z;GD4i%iM|#$Ka-n(RW5NDiXBKiy8EsZS&!ai8+7ER;z6f^ zdopjl{}yLuneP1QkT&OUhO|4|?myt%xBQ^UxFYAh(hrzdoo8qe=u|W z#PL~oJ{ZZ$Sh{gg{tFXbs~=k7`kiCl;7dP0=-PF~Aa{GjsWI|r3rlh4h}x%rCB zMGM23ZM)VDegCrY!+I`j8!BJEXK3lZjhP+s2L@gCt72E+<*@7hMNdeFT@OmBFAv$2 zKb*8pnX}Tq=wjX8a`7-}*Toa1%=(kkn*Yjk{_L9Z&KKSo?|k*n3C{N}ndto6HPfB> zo91U#Z5ola{C{lrS5n1xHQ~s7zI?ADR<~hce z-D10@Y`HBuwcVCT9<;qS^?+^v@@cja>prwid%W0Q_xMQrn(+_W*N=a~zGeKM?0-H{ zEDt_8QqG;wBo|EhxxBFWpuD+wn0w2Fq3-J{huRla4zVA7@{nWdxt}3A!q))|e&q#} zqPm7Pvdz*4M*lszgUd1JBZ&sA`AXfTa9#)NiwybppS>PO;*?=NI31H1RL3Rw#hB?`Kal zmF>kJ?uf5|RD@Wvfq8J?_yHQA8n70zZ@(kJ8Z(NR>MWJ2vr3sCfBFc}A3p%qgGxbv zE!*JQ3_4L(Jy>NPx5^sbpydX?QYp@-C@Zx$GQ(cV8s#FkTP7`#O3nw=1C}C2H8VSl z0(PPO4$98}XHb_UnGKe3sz`P=3FS=5!LA4V9I#!=K$N%R^vhs5Hai<@bFiyyPIfKY z#i&=>WL5*X747wCKZ){}HU+dY0a>8$WT!FTVRtf*J%e2Y7-!F7SJ?-#Y3S4KE_M&v zyHM^!`2ork04BTGAQ|gXUIMrbkPnzHpTp+LgV|HEn>idVHWZOK$C1S@cR1KYv?l`! zP%lKe0C1C|uB@h>&90Ax!j0h&zNam%8oO))tEsPvuyNH5b)j)}O%>Jkp_=jI7Bn=} zHjP_W6RxVM9T$#_t1pYxEDMdBUo(GceWa!?MC;NGRv4vXYGw76wV^PJG!#d|HT6|&!EKG90c=!-BC{JAzKa{#;+p!(>zhL1=?#@3 zR?Qa|3ohr^r27|_0d=n!SUI(#BGlA0wX!md0<`+5Uk8f!y!Auv+ePsKBu%^k%0+XdD+p-6Q@rNBBB_EYjrB3D(6D-PAw6gQStaQmc2 z6E#>W$-<%9hKlLfx^nm#3oosoSpzSuxt)kKf!e(Cn@JE1q-hIQ7-m&j!!`BG z(5%!#WtDI*S~owmcurX(ug++O{zUcvXo@E30j6m7avHO08_LUSzfmv!9Lrqu738Ad z!X65T8^TQN2q(p55Zl}YL3?Y(wGD8IrIAL~z?D`EEpkOSG~ULlL(S8xxxN?Il{NAq z*pOA_M-Ic0#^wQVrC@gesQn7ye!xXI2dV!-lnViw$b=K*A&SgG)d)ayA z63byTw@B<=HuNO*kIunuhUFf&vHRG0ZFcr8{_SU@kK0)uJMRR2e;*ti1Uv(7mzx|B zSN}gB#Uw+zp;x(rnq@VWp=q}*422tdBMR~wj1hAs=Gz&~rw6I)5sez*0ij9}`L9yZ zi4Tnz6d|@)0ZB$i)Gf-t0*{q zYWv5i|8BLhjZ6)y)a2u|{s;6Jjt}8Os>Wtj%-{x1?U8_R2*EX6Rv%F*eyfoNwKpbO zQ4G`gdgK-iF5cKjT;7i>C7rNK7cZ`P-;$s92L{BVefH-Pv~x^>u2Rhyq=rL_L*Y<;MTo0{ int { + def x = A.Z(ay); + + x.foo(); + + return 0; +} + +def ay = A.Y; + +type A { + case X { + def foo() {} + } + case Y { + def foo() {} + } + case Z(a: A) { + def foo() { a.foo(); } + } + + def foo(); +} + + diff --git a/int/InterpreterBug.wasm b/int/InterpreterBug.wasm new file mode 100644 index 0000000000000000000000000000000000000000..dc25a1547290bd15158034dc6f6fc172e5b574a2 GIT binary patch literal 5307 zcma)ATWlLy89wLC&CWRSB~Ysax2+euS| zl(H0d#YG?x2q7WyutMM4OP*L~O*w0!@6W;{+?p^Y=1 z|D5yRuj3KPU|k9!tw1ot+)Jxw!3!s{;R6Nq~yh_{wm^RgX}x$Eb2g zF&Edpm29O!(!X(~opyxaWr>!JZtu2`c0Ih=@7}tSZVP4CtAi`I`psb~r1KW(@&H=7 zLVBJfl_PzDj}rvAi6HPDFA${?)b>iMT=M*qH$hk62SG4_PdNx=$-PT_WKSIPzRi$) zSb10peonCCrJZ5_w($J*biLcZt%NsBuC-Gs%J&#o7#Y?+bn3$&`RK<^*FS#dxlerZ zQ~N)?Z{ahajX!tx_~)NL@P!w?xM*Hnnz;81*7bQQcg)-01bj*f3yhXpv})2k$_~Hm zE^1-$iAvQ_%LOIEvd|(5<|03Qm1GN}qOuX;8{fb}`a9+o+Ff=Ry(p}R5Y%$5<{R;n zyNH!<+_ovTA{R1d!A(o;FDTc@SUHPYX+qN~5;ZTU@J!e;U*7$uvWAYMxzn;NsMsAwkMyn?B(*^ZAqFYdJ(#^nk3yNcA z!C%{5%V|OVrdYlX#QVjPSa8HF9ml5{{+1Mw9&|Y^9uTs-X#UMa@6k6~H0dD>P)DA% zC}b6Lis55gusWIS=qS@18STfuT0~?Jz*APc3kZ-O2fQ2X+6{CN&9>qIo~@`b49$;N z6A|svLG0(d(G(G}W!hh(fbV3kuR@4IVpj6}>>Qy8s=C})n$ z1R)umr$ixqQ zoyUYA%xjcQCXV*aSrE0gA32QVw(ID?oR=ZpCsdqfh;jr1hbv9X=wLPcrDe>aeVgC~ z^=G<~hhQ#&)$pel=}ngYh`w#Eppbt>M`#dQWHl)%wuUem zJIGDy1XYhZK`BNffFaZrw3rSA1)lo^bqp6!wiG}o`OIX5QbH7wJG@EqRqQ~cF#OBQ zkSeP?YBB$?NwrDiY)rWV9p4Sj&qy^r*@CULs=?yU_67;8BBJw1ZB8X!HSgmu*f46? z!ogvaiAxt3FI|y*?2lYBR$+g&4Y~}BPzC@wHLeO7Pxke z6f`9R5NftDFd#Iu!nd@=e-^j-@7p&xq)*cybIWbd3FE z=y(&c<(MNCP?N|2Lg&1H5}h~4Bc1p7-%~KT29Q)W1se^eHsypyA1$%jT3Io4j1dIm zjf|W*r0gG_*GS4~h}5bTX%dO8 ztt@wJ5ek$cdlgR@ut7`8H%>NRBLFDeXugKt`>oBH}JqG$BH6qg8yPJNai0B5DU-=+YCUPRXr#K z%AFjF2OX|ixjZT1_RMf)t)}iun_GkiH)J6dkV~R|zExeG^DduY*oEKc zx`0pMhc$9cspi4YdAWM#43#Tyk#MAzXWqjoE|XWXMC9%%5M$MXZ|1j5bt5_s$Q@#j zIvYv@kq2|`cW4N3J=Fy^vcjL>s)arxe2X>mpPCl#)6>G`Y2h2nK07V^=)`DN_+zso zItku3gFH+MmnMZbJ}DIM)g0z!M}!ldh-KdQow2?jo#gonJ}5ZLWUQA{Ye$o|Ezp5u zQIs*PN5RS1MS7zZP~M=bkX#gbcnXi!Tp{c!%GJMeS=bg>g0IV3@uR(YC|c%y%%6!h z>W9jl;iYYcjwx*|Ti=2=64OQu0QwU|oTcaQH%6RCJw-x01+k_UJ^5`A|QhsvKwaDsd9zn&@zNmlx5|?Dr7wM)|J_ zpiq&7-y2bohe=x`2yBoh+;7=D|xd3Yg zC<^ezZZ5JoIl249DNg2|v{)5qvjuo)T8DYwjOr%O1j=$=_QS{-sra5 zX=8}CCxpUvS6V&+ZD{#Oj-Aay{*1pJYI^xR=R40yxeLIjfr)RX<%#`)LP)7PZyQ z1)e_rf_|3mw6~fJlQ!-IAH?-$Dhson$?g?-2MUQK9!R_3S;2 zoE)v_HH@;${4I=Qm-$N=*RLZm-G=Aa`8|n0d!YkA_WCKlU);P=Ur(ByVCr)7@@8k) zTu1${d#lIYbUoSW@x?C?F@#`<$K{2#hnAi94gbrI?IE} z0|ird-ST!L?G2mV&eZJX=J`f_6`}_>R~kvDllBMIxq<_uU)mgATD{2cc%n%rzzd(H zcAE63_ZO)B6vi&WN$tlS<9)Af2v1vF=cLZ=&<8i%Z| zSvsO7ki7GSu9wr*i%IWrv9Y{8#Kw{Nm7B@+?yZ#}%+2(#lWn|l^r%(je7k!sX^$V< zoq?VyEM=;8cNjm@s9w#Aw#BsqR~|!>AZio@Wa04xPuYAk-Cnwx^iNnq)Yp2_Bf^t* KBi$Zm8~+2|nOxHV literal 0 HcmV?d00001 diff --git a/int/RiRuntime b/int/RiRuntime new file mode 100755 index 000000000..716d1b2e8 --- /dev/null +++ b/int/RiRuntime @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +S=${BASH_SOURCE[0]} +while [ -h "$S" ]; do + DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) + S=$(readlink "$S") + [[ $S != /* ]] && S=$DIR/$S +done +DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) +wizeng $DIR/RiRuntime.wasm "$@" diff --git a/int/RiRuntime.wasm b/int/RiRuntime.wasm new file mode 100644 index 0000000000000000000000000000000000000000..049ef40aa3e69f8aebd5db3e2624642b3499f831 GIT binary patch literal 4434 zcmb7HOOISf6|SmVb#Hf9kGmYlPGFL{t{#G5XR^vH6qJE)=aH#jFFj4GnJ(}OKbQy*wZ)354k6D^JAvuz2?1U_A8=Q zdaby&J9t?MGwi+4FQlmdk$FUr)_*F0;?tiwzWUkEef|sQpZwy5FMatdU;SF=>)-h1 zqie@5KJ~3LPd7e%4LUA9CFMB0@gtC{NxblKIu7jFy6zfRYYGbix!q2Kcvg3@N`vl)TIn>@9)kieecDkv$Xq2|uRO7N zS4p>`rCdono1j)BQYET|^!UT8-XaLITn}t4~D{PmcY>L@Qo}+1kir z70AjElASzc3WXxd1*;J+}Z7f!-fL*}P3;PjUN!ZHUM8}IT znJ1`CLVC*((rY<@j*AfJy*O$FC7$~Lbp#EnS_-g}eO5AMsUeG~9o{7SDo@~%wSRww zBGMYG?&OcJ)Lsh7{t+$Ex3vwwBiH;=iMzI20gJE}b6rU&b31{Yx4E7;P-h1uJCJ9-K}}$S@uY8&5@OeXK!*%VL@oO$-z(y zAmL^oL!it7Cvs9DBgg{Rj5|Fm7;dJJa*x~JP`$~R(YexO@)I(;kWbDbrH;8DOdW3` zx14j70x*dRAojaR2(rru9aUwTH|H~ro^mKe%l?I)i~$r?Tj7p@N}FoJqmS13+FnI7 zbc_*$%LnO_6_o6|EUo|{N+LwSh%hIZC{ct)4~i@5qscV4A65K}JwZqtXbn*L3dbyk z%BU+dOhE(N$VgX=|H3}d5czeqP03#LA|**lnd9VE>;_EaBf*i_gDqH)EKw(I~*X2|hsu;6~ z=K4L>7uy#|IF3*{6*29T{# z4+#OdQ$X=WhA}JGmn6boU0lUmQ+K7!5wRf*RZ0cylBr*EAEJ3lO@=as%SrNwClc8M z&5hSfl&k7e5=D;UowQ#1y5o7x6Oyi{Jte|;o?rr2XN?#GvA|{B#HU*~EHi+{Ct|nX{xbhYmM`@YxZ;awPMWrf4?w+Wipi0E%)F`y}T@FeQ zu}7T^&_L#)ockRb0zyx?z(xi92BQ}K2>Tv;ls+^q^uyCa^R!3<6dXtm|I!SNCvFl;LB{pT;)z zLlrLYGB(2`)JE$uw$P2jj2Q!g{sa?i)SKU$YM%BK3GWm05I(A)#RQd_c(f<$F2&*42Nik;!0w=?t`y?);hcm4ClwXNs(dK<-)8@v5}u`vXf5DM?B5zkWf8(UEC4@jNwZ4Qfpf9Bh)<3V4JL*~-XsMp`R z>UUo#Vb;G`^sW{I?9&UT#jBP5GobV8B5QuDk{T47#h}=Mp{|d Date: Fri, 23 Jan 2026 16:09:50 -0500 Subject: [PATCH 15/91] Add logic for specialized FAST_CALL bytecodes --- src/engine/Opcodes.v3 | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/engine/Opcodes.v3 b/src/engine/Opcodes.v3 index 4204e3bf1..f05052280 100644 --- a/src/engine/Opcodes.v3 +++ b/src/engine/Opcodes.v3 @@ -662,6 +662,62 @@ enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: //FAST_CALL46 (0x00, 0xFF, "fast_call46", imm.NONE, null) } +//def indexToFastCall(index: int) -> Opcode { +// var op: Opcode; +// match (index) { +// 0 => op = Opcode.FAST_CALL0; +// 1 => op = Opcode.FAST_CALL1; +// 2 => op = Opcode.FAST_CALL2; +// 3 => op = Opcode.FAST_CALL3; +// 4 => op = Opcode.FAST_CALL4; +// 5 => op = Opcode.FAST_CALL5; +// 6 => op = Opcode.FAST_CALL6; +// 7 => op = Opcode.FAST_CALL7; +// 8 => op = Opcode.FAST_CALL8; +// 9 => op = Opcode.FAST_CALL9; +// 10 => op = Opcode.FAST_CALL10; +// 11 => op = Opcode.FAST_CALL11; +// 12 => op = Opcode.FAST_CALL12; +// 13 => op = Opcode.FAST_CALL13; +// 14 => op = Opcode.FAST_CALL14; +// 15 => op = Opcode.FAST_CALL15; +// 16 => op = Opcode.FAST_CALL16; +// 17 => op = Opcode.FAST_CALL17; +// 18 => op = Opcode.FAST_CALL18; +// 19 => op = Opcode.FAST_CALL19; +// 20 => op = Opcode.FAST_CALL20; +// 21 => op = Opcode.FAST_CALL21; +// 22 => op = Opcode.FAST_CALL22; +// 23 => op = Opcode.FAST_CALL23; +// 24 => op = Opcode.FAST_CALL24; +// 25 => op = Opcode.FAST_CALL25; +// 26 => op = Opcode.FAST_CALL26; +// 27 => op = Opcode.FAST_CALL27; +// 28 => op = Opcode.FAST_CALL28; +// 29 => op = Opcode.FAST_CALL29; +// 30 => op = Opcode.FAST_CALL30; +// 31 => op = Opcode.FAST_CALL31; +// 32 => op = Opcode.FAST_CALL32; +// 33 => op = Opcode.FAST_CALL33; +// 34 => op = Opcode.FAST_CALL34; +// 35 => op = Opcode.FAST_CALL35; +// 36 => op = Opcode.FAST_CALL36; +// 37 => op = Opcode.FAST_CALL37; +// 38 => op = Opcode.FAST_CALL38; +// 39 => op = Opcode.FAST_CALL39; +// 40 => op = Opcode.FAST_CALL40; +// 41 => op = Opcode.FAST_CALL41; +// 42 => op = Opcode.FAST_CALL42; +// 43 => op = Opcode.FAST_CALL43; +// 44 => op = Opcode.FAST_CALL44; +// 45 => op = Opcode.FAST_CALL45; +// 46 => op = Opcode.FAST_CALL46; +// 47 => op = Opcode.FAST_CALL47; +// _ => System.error("indexToFastCall", "out of range"); +// } +// return op; +//} + // Enumeration of the different kinds of immediates to opcodes. enum ImmKind { ARRAY_TYPE_INDEX, // ARRAYT From 7a8843173f8ef447b3eb13654a0da0117551b8f4 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 11 Mar 2026 13:42:18 -0400 Subject: [PATCH 16/91] Add more instructions --- int/Interpreter.v3 | 174 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 142 insertions(+), 32 deletions(-) diff --git a/int/Interpreter.v3 b/int/Interpreter.v3 index 9cc0be2dd..13f0a1b9e 100644 --- a/int/Interpreter.v3 +++ b/int/Interpreter.v3 @@ -1,55 +1,92 @@ -export "fast:const0" def const0() -> int { return 0; } -export "fast:const1" def const1() -> int { return 1; } -export "fast:constN" def constN(n: int) -> int { return n; } -export "fast:add" def add(l: int, r: int) -> int { return l + r; } -export "fast:sub" def sub(l: int, r: int) -> int { return l - r; } -export "fast:seq" def seq(f: int, s: int) -> int { return s; } -export "fast:select" def select(c: int, t: int, f: int) -> int { return if(c != 0, t, f); } -export "fast:nop" def nop() -> void {} +export "fast:const0" def const0() -> long { return 0; } +export "fast:const1" def const1() -> long { return 1; } +export "fast:constN" def constN(n: int) -> long { return n; } +export "fast:add" def add(l: long, r: long) -> long { return l + r; } +export "fast:sub" def sub(l: long, r: long) -> long { return l - r; } +export "fast:fact" def fact(n: long) -> long { + var v: long = 1; + for (i < n) { + v *= i + 1; + } + return v; + } +export "fast:seq" def seq(f: long, s: long) -> long { return s; } +export "fast:select" def select(c: long, t: long, f: long) -> long { return if(c != 0, t, f); } +export "fast:if" def if_(c: long) -> bool { return c != 0; } +export "fast:nop" def nop() -> void {} +export "fast:print" def print(n: long) -> long { + System.puts(Strings.format1("%d\n", n)); + return 0; + } +export "fast:double" def double(n: long) -> long { return add(n, n); } def HANDLER_CONST0 = CiWasmTarget.functionId(const0); def HANDLER_CONST1 = CiWasmTarget.functionId(const1); def HANDLER_CONSTN = CiWasmTarget.functionId(constN); def HANDLER_ADD = CiWasmTarget.functionId(add); def HANDLER_SUB = CiWasmTarget.functionId(sub); +def HANDLER_FACT = CiWasmTarget.functionId(fact); def HANDLER_SEQ = CiWasmTarget.functionId(seq); def HANDLER_SELECT = CiWasmTarget.functionId(select); +def HANDLER_IF = CiWasmTarget.functionId(if_); def HANDLER_NOP = CiWasmTarget.functionId(nop); +def HANDLER_PRINT = CiWasmTarget.functionId(print); +def HANDLER_DOUBLE = CiWasmTarget.functionId(double); export "main" def main() -> int { + def buf = StringBuilder.new(); + //def prog = Select(Sub(ConstN(1), Const1), Add(Const1, ConstN(100)), Seq(Sub(Add(Const1, ConstN(2)), Const0), ConstN(15))); - def prog = AST.If(Const1, ConstN(2), ConstN(3)); + + //def prog = AST.If(Const1, ConstN(2), ConstN(3)); + def prog = Double(Fact(ConstN(13))); //def prog = Const1; def bytecode = compile(prog); def val = eval(bytecode); - def f: Func.F = wasmCompile(bytecode); - def val_ = f.f(); - - def buf = StringBuilder.new(); prog.display(buf); buf.ln(); buf.put1("=> %d", val); buf.ln(); + System.puts(buf.extract()); + + def f: Func.F = wasmCompile(bytecode); + def val_ = f.f(); + buf.put1("=> %d", val_); buf.ln(); System.puts(buf.extract()); - call(); return 0; } -def CALL_FUNC = CiWasmTarget.functionId(call); +def eval(bytecode: Array) -> long { + def vstk = ArrayStack.new(); + var pc = 0; -def call() { - System.puts(Strings.format1("call=%d\n", CALL_FUNC)); -} + // print out bytecode + def b = StringBuilder.new(); + while (pc < bytecode.length) { + b.put1("+%d ", pc); -def eval(bytecode: Array) -> int { - def vstk = ArrayStack.new(); - var pc = 0; + def instruction = Ref.at(bytecode, pc); + def opcode = instruction.opcode; + def operand = instruction.operand; + pc += Instruction.size; + + b.puts(opcode.name); + match (opcode) { + CONSTN, IF, ELSE => b.put1(" %d", operand); + _ => ; + } + b.ln(); + } + System.puts(b.extract()); + + pc = 0; while (pc < bytecode.length) { + System.puts(Strings.format1("pc=%d\n", pc)); def instruction = Ref.at(bytecode, pc); def opcode = instruction.opcode; def operand = instruction.operand; @@ -69,6 +106,23 @@ def eval(bytecode: Array) -> int { def left = vstk.pop(); vstk.push(left - right); } + FACT => { + def arg = vstk.pop(); + var val: long = 1; + for (i < arg) { + val *= i + 1; + } + vstk.push(val); + } + PRINT => { + def arg = vstk.pop(); + System.puts(Strings.format1("%d\n", arg)); + vstk.push(0); + } + DOUBLE => { + def arg = vstk.pop(); + vstk.push(arg + arg); + } SEQ => { def snd = vstk.pop(); def fst = vstk.pop(); @@ -82,7 +136,7 @@ def eval(bytecode: Array) -> int { } IF => { def cond = vstk.pop(); - if (cond != 0) pc += operand; + if (cond == 0) pc += operand; } ELSE => { pc += operand; @@ -99,11 +153,14 @@ enum Opcode(handler: int) { CONSTN (HANDLER_CONSTN) ADD (HANDLER_ADD) SUB (HANDLER_SUB) + FACT (HANDLER_FACT) SEQ (HANDLER_SEQ) SELECT (HANDLER_SELECT) - IF (HANDLER_NOP) + IF (HANDLER_IF) ELSE (HANDLER_NOP) END (HANDLER_NOP) + PRINT (HANDLER_PRINT) + DOUBLE (HANDLER_DOUBLE) } layout Instruction { @@ -151,6 +208,39 @@ type AST { s.putc(')'); } } + case Fact(arg: AST) { + def compile(w: DataWriter) { + arg.compile(w); + w.putb(Opcode.FACT.tag).putb(0); + } + def display(s: StringBuilder) { + s.puts("(fact "); + arg.display(s); + s.putc(')'); + } + } + case Print(arg: AST) { + def compile(w: DataWriter) { + arg.compile(w); + w.putb(Opcode.PRINT.tag).putb(0); + } + def display(s: StringBuilder) { + s.puts("(print "); + arg.display(s); + s.putc(')'); + } + } + case Double(arg: AST) { + def compile(w: DataWriter) { + arg.compile(w); + w.putb(Opcode.DOUBLE.tag).putb(0); + } + def display(s: StringBuilder) { + s.puts("(double "); + arg.display(s); + s.putc(')'); + } + } case Sub(left: AST, right: AST) { def compile(w: DataWriter) { left.compile(w); @@ -201,14 +291,14 @@ type AST { case If(cond: AST, left: AST, right: AST) { def compile(w: DataWriter) { cond.compile(w); - w.putb(Opcode.IF.tag); + w.putb(Opcode.IF.tag).putb(0); def hole1 = w.pos; left.compile(w); - w.data[hole1] = byte.!(w.pos - hole1 + 1); - w.putb(Opcode.ELSE.tag); + w.putb(Opcode.ELSE.tag).putb(0); + w.data[hole1 - 1] = byte.!(w.pos - hole1); def hole2 = w.pos; right.compile(w); - w.data[hole2] = byte.!(w.pos - hole2 + 1); + w.data[hole2 - 1] = byte.!(w.pos - hole2); w.putb(Opcode.END.tag).putb(0); } @@ -232,9 +322,12 @@ def Const1 = AST.Const1; def ConstN = AST.ConstN; def Add = AST.Add; def Sub = AST.Sub; +def Fact= AST.Fact; +def Print = AST.Print; def Seq = AST.Seq; def Select = AST.Select; def If = AST.If; +def Double = AST.Double; def compile(prog: AST) -> Array { def w = DataWriter.new(); @@ -245,7 +338,7 @@ def compile(prog: AST) -> Array { } type Func { - case F(f: () -> int); + case F(f: () -> long); } def wasmCompile(bytecode: Array) -> Func.F { @@ -269,25 +362,42 @@ def wasmCompile(bytecode: Array) -> Func.F { _ => ; } // call handler function - w.putb(CALL); - w.put_uleb32(u32.!(opcode.handler)); + if (opcode.handler != HANDLER_NOP) { + w.putb(CALL); + w.put_uleb32(u32.!(opcode.handler)); + } + // post-handler wasm bytecodes + match (opcode) { + IF => { + w.putb(IF); + w.putb(RESULT_I64); + } + ELSE => w.putb(ELSE); // didn't emit handler anyway + END => w.putb(END); // didn't emit handler anyway + _ => ; + } } w.putb(END); // create wasm function - def sig = CiWasmTarget.functionTypeId(); + def sig = CiWasmTarget.functionTypeId(); def wasm = w.extract(); def fid = wave.new_func(sig, Pointer.atContents(wasm), wasm.length); if (fid < 0) { System.puts("failed to compile wasm function\n"); System.error("error", "failed to compile"); } - def func = CiRuntime.forgeClosure(Pointer.NULL + fid, void); + def func = CiRuntime.forgeClosure(Pointer.NULL + fid, void); return Func.F(func); } +def IF: byte = 0x04; +def ELSE: byte = 0x05; def END: byte = 0x0B; def CALL: byte = 0x10; def DROP: byte = 0x1A; def I32_CONST: byte = 0x41; +def I64_CONST: byte = 0x42; + +def RESULT_I64: byte = 0x7E; From 9fd68644b29ffc90839aef243dbc40dee64520a4 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 18 Mar 2026 16:46:27 -0400 Subject: [PATCH 17/91] Remove use of fast frame --- src/engine/x86-64/X86_64MasmRegs.v3 | 4 ++-- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 19 +++---------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/engine/x86-64/X86_64MasmRegs.v3 b/src/engine/x86-64/X86_64MasmRegs.v3 index 53f9ef1b1..d1fe06a79 100644 --- a/src/engine/x86-64/X86_64MasmRegs.v3 +++ b/src/engine/x86-64/X86_64MasmRegs.v3 @@ -193,5 +193,5 @@ component X86_64MasmRegs { } } -def nothing = X86_64MasmRegs.FAST_SPC_EXEC_ENV.frameSize = X86_64InterpreterFastCallFrame.size; -def nothing2 = X86_64MasmRegs.FAST_SPC_EXEC_ENV.vfp_slot = MasmAddr(X86_64MasmRegs.FAST_SPC_EXEC_ENV.sp, X86_64InterpreterFastCallFrame.vfp.offset); +def nothing = X86_64MasmRegs.FAST_SPC_EXEC_ENV.frameSize = 0; +def nothing2 = X86_64MasmRegs.FAST_SPC_EXEC_ENV.vfp_slot = MasmAddr(X86_64MasmRegs.FAST_SPC_EXEC_ENV.sp, X86_64InterpreterFrame.vfp.offset); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index b16abb2bd..a797f17c8 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -47,29 +47,16 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } - // TODO do we need to spill VFP if the function has no locals? when exactly is spilling VFP needed? - // and can it be determined independent of call site? def emitFastPrologue() { - // Allocate (very cheap) stack frame - masm.emit_subw_r_i(regs.sp, frame.frameSize); - // spill VFP - masm.emit_mov_m_r(ValueKind.REF, frame.vfp_slot, regs.vfp); - // Compute VFP = VSP - sig.params.length * SLOT_SIZE - masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); // XXX: use 3-addr adjustment of VFP + // Compute VFP = VSP - sig.params.length * SLOT_SIZE (no native stack frame needed) + masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); - asm.nop1(); } def emitFastEpilogue1() { - asm.nop1(); } def emitFastEpilogue2() { - asm.nop1(); - asm.nop1(); - // restore VFP + // Restore VFP from interpreter frame (always in sync; no fast frame was allocated) masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); - masm.emit_addw_r_i(regs.sp, frame.frameSize); - asm.nop1(); - asm.nop1(); } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { From 03b6ccde3f45cc23b5adf89e843757e0d79b81f4 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 1 Apr 2026 12:32:03 -0400 Subject: [PATCH 18/91] Add FAST_CALL 0-47 for each unused bytecode, and minor merge fixes --- src/engine/BytecodeIterator.v3 | 56 +++- src/engine/CodeValidator.v3 | 86 +++++- src/engine/Module.v3 | 7 +- src/engine/Opcodes.v3 | 269 +++++++++++------- src/engine/v3/V3Interpreter.v3 | 4 +- src/engine/x86-64/X86_64Interpreter.v3 | 51 +++- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 14 +- src/engine/x86-64/X86_64Target.v3 | 6 +- src/util/BytecodeVisitor.v3 | 2 +- 9 files changed, 366 insertions(+), 129 deletions(-) diff --git a/src/engine/BytecodeIterator.v3 b/src/engine/BytecodeIterator.v3 index 1f1b58c4e..1a1c9845f 100644 --- a/src/engine/BytecodeIterator.v3 +++ b/src/engine/BytecodeIterator.v3 @@ -217,7 +217,6 @@ class BytecodeIterator { BR_TABLE => v.visit_BR_TABLE(cp.read_labels()); RETURN => v.visit_RETURN(); CALL => v.visit_CALL(read_FUNC()); - FAST_CALL => v.visit_FAST_CALL(read_FUNC()); CALL_INDIRECT => v.visit_CALL_INDIRECT(read_SIG(), read_TABLE()); RETURN_CALL => v.visit_RETURN_CALL(read_FUNC()); RETURN_CALL_INDIRECT => v.visit_RETURN_CALL_INDIRECT(read_SIG(), read_TABLE()); @@ -780,6 +779,61 @@ class BytecodeIterator { RESUME_THROW => v.visit_RESUME_THROW(read_CONT(), read_TAG(), read_HANDLERS()); RESUME_THROW_REF => v.visit_RESUME_THROW_REF(read_CONT(), read_HANDLERS()); SWITCH => v.visit_SWITCH(read_CONT(), read_TAG()); + + /* here, we require that replacing CALL with FAST_CALL does not touch the + * operand, so that the original function can still be recovered from the bytecode itself + * + * in other places, where we have the module, we can go direct from bytecode to func + */ + // FIXME wrap into _ clause + FAST_CALL0 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL1 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL2 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL3 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL4 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL5 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL6 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL7 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL8 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL9 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL10 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL11 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL12 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL13 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL14 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL15 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL16 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL17 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL18 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL19 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL20 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL21 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL22 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL23 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL24 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL25 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL26 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL27 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL28 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL29 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL30 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL31 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL32 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL33 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL34 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL35 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL36 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL37 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL38 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL39 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL40 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL41 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL42 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL43 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL44 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL45 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL46 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); + FAST_CALL47 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); } } def trace(out: StringBuilder, module: Module, tracer: InstrTracer) { diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index 24b25887c..281b14a01 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -425,16 +425,90 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e for (i < module.exports.length) { def ex = module.exports[i]; if (ex.1 == func && Strings.startsWith(ex.0, "fast:")) { - this.func.replaceCall(opcode_pos); + if (Trace.validation) Trace.OUT.puts(" function declared as fast: "); + + var fast_idx = -1; + def fast_funcs = module.fast_funcs; + // look for existing FAST_CALL instruction allocated for this function + for (i < fast_funcs.length) { + if (func == fast_funcs[i]) { + fast_idx = i; + if (Trace.validation) Trace.OUT.put1("allocated as FAST_CALL%d, ", fast_idx); + break; + } + } + // not found? allocate FAST_CALL instruction, if there's space + if (fast_idx < 0) { + if (fast_funcs.length < 48) { + fast_idx = fast_funcs.length; + if (Trace.validation) Trace.OUT.put1("not found, allocating FAST_CALL%d, ", fast_idx); + fast_funcs.put(func); + } else { + if (Trace.validation) Trace.OUT.puts("not found, FAST_CALL table is full, "); + } + } + // replace the bytecode, if it's found or allocated + if (fast_idx >= 0) { + //if (Trace.validation) Trace.OUT.put2("replaceCall(opcode_pos, fast_idx)\n", opcode_pos, fast_idx); + if (Trace.validation) Trace.OUT.puts("replacing call\n"); + this.func.replaceCall(opcode_pos, fast_idx); + } else { + if (Trace.validation) Trace.OUT.puts("not replacing\n"); + } } } } - FAST_CALL => { - var func = parser.readFuncRef(); - if (func == null) return; - checkSignature(func.sig); - } + // code should have FAST_CALL replaced after CALL + + FAST_CALL0 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL1 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL2 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL3 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL4 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL5 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL6 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL7 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL8 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL9 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL10 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL11 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL12 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL13 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL14 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL15 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL16 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL17 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL18 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL19 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL20 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL21 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL22 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL23 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL24 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL25 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL26 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL27 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL28 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL29 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL30 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL31 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL32 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL33 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL34 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL35 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL36 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL37 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL38 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL39 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL40 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL41 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL42 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL43 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL44 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL45 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL46 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL47 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); CALL_INDIRECT => { var sig = parser.readSigRef(); var table = parser.readTableRef(); diff --git a/src/engine/Module.v3 b/src/engine/Module.v3 index 4b37e48f0..c7438ecba 100644 --- a/src/engine/Module.v3 +++ b/src/engine/Module.v3 @@ -17,6 +17,7 @@ class Module(filename: string) { def exports = Vector<(string, Decl)>.new(); def elems = Vector.new(); def data = Vector.new(); + def fast_funcs = Vector.new(); def custom_sections = Vector.new(); var probes: Array>; var dyn_probes: Vector<(int, int, Probe)>; @@ -170,14 +171,16 @@ class FuncDecl(sig_index: int) extends Decl { if (cur_bytecode == orig_bytecode) return; cur_bytecode[pc] = orig_bytecode[pc]; } - def replaceCall(pc: int) { + def replaceCall(pc: int, idx: int) { // "orig" will become a copy of the original code, to allow in-place modification of old code if (cur_bytecode == orig_bytecode) orig_bytecode = Arrays.dup(orig_bytecode); + // sanity check if (cur_bytecode[pc] != Opcode.CALL.code) { def realOp = Opcodes.find(0, cur_bytecode[pc]); System.error("replace bytecode", Strings.format1("not replacing call (got %s)", realOp.mnemonic)); } - cur_bytecode[pc] = byte.!(Opcode.FAST_CALL.code); + cur_bytecode[pc] = byte.!(Opcodes.indexToFastCall(idx).code); + // do NOT replace the operands, as a convenience for BytecodeIterator } def reset() -> this { if (cur_bytecode == orig_bytecode) return; diff --git a/src/engine/Opcodes.v3 b/src/engine/Opcodes.v3 index f05052280..db9c56009 100644 --- a/src/engine/Opcodes.v3 +++ b/src/engine/Opcodes.v3 @@ -612,111 +612,56 @@ enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: SWITCH (0x00, 0xE6, "switch", imm.CONT_TAG, null) // fast call instructions - FAST_CALL (0x00, 0x17, "fast_call", imm.FUNC, null) - //FAST_CALL0 (0x00, 0x27, "fast_call0", imm.NONE, null), - //FAST_CALL1 (0x00, 0xC5, "fast_call1", imm.NONE, null), - //FAST_CALL2 (0x00, 0xC6, "fast_call2", imm.NONE, null), - //FAST_CALL3 (0x00, 0xC7, "fast_call3", imm.NONE, null), - //FAST_CALL4 (0x00, 0xC8, "fast_call4", imm.NONE, null), - //FAST_CALL5 (0x00, 0xC9, "fast_call5", imm.NONE, null), - //FAST_CALL6 (0x00, 0xCA, "fast_call6", imm.NONE, null), - //FAST_CALL7 (0x00, 0xCB, "fast_call7", imm.NONE, null), - //FAST_CALL8 (0x00, 0xCC, "fast_call8", imm.NONE, null), - //FAST_CALL9 (0x00, 0xCD, "fast_call9", imm.NONE, null), - //FAST_CALL10 (0x00, 0xCE, "fast_call10", imm.NONE, null), - //FAST_CALL11 (0x00, 0xCF, "fast_call11", imm.NONE, null), - //FAST_CALL12 (0x00, 0xD7, "fast_call12", imm.NONE, null), - //FAST_CALL13 (0x00, 0xD8, "fast_call13", imm.NONE, null), - //FAST_CALL14 (0x00, 0xD9, "fast_call14", imm.NONE, null), - //FAST_CALL15 (0x00, 0xDA, "fast_call15", imm.NONE, null), - //FAST_CALL16 (0x00, 0xDB, "fast_call16", imm.NONE, null), - //FAST_CALL17 (0x00, 0xDC, "fast_call17", imm.NONE, null), - //FAST_CALL18 (0x00, 0xDD, "fast_call18", imm.NONE, null), - //FAST_CALL19 (0x00, 0xDE, "fast_call19", imm.NONE, null), - //FAST_CALL20 (0x00, 0xDF, "fast_call20", imm.NONE, null), - //FAST_CALL21 (0x00, 0xE0, "fast_call21", imm.NONE, null), - //FAST_CALL22 (0x00, 0xE1, "fast_call22", imm.NONE, null), - //FAST_CALL23 (0x00, 0xE2, "fast_call23", imm.NONE, null), - //FAST_CALL24 (0x00, 0xE3, "fast_call24", imm.NONE, null), - //FAST_CALL25 (0x00, 0xE4, "fast_call25", imm.NONE, null), - //FAST_CALL26 (0x00, 0xE5, "fast_call26", imm.NONE, null), - //FAST_CALL27 (0x00, 0xE6, "fast_call27", imm.NONE, null), - //FAST_CALL28 (0x00, 0xE7, "fast_call28", imm.NONE, null), - //FAST_CALL29 (0x00, 0xE8, "fast_call29", imm.NONE, null), - //FAST_CALL30 (0x00, 0xE9, "fast_call30", imm.NONE, null), - //FAST_CALL31 (0x00, 0xEA, "fast_call31", imm.NONE, null), - //FAST_CALL32 (0x00, 0xEB, "fast_call32", imm.NONE, null), - //FAST_CALL33 (0x00, 0xEC, "fast_call33", imm.NONE, null), - //FAST_CALL34 (0x00, 0xED, "fast_call34", imm.NONE, null), - //FAST_CALL35 (0x00, 0xEE, "fast_call35", imm.NONE, null), - //FAST_CALL36 (0x00, 0xEF, "fast_call36", imm.NONE, null), - //FAST_CALL37 (0x00, 0xF2, "fast_call37", imm.NONE, null), - //FAST_CALL38 (0x00, 0xF3, "fast_call38", imm.NONE, null), - //FAST_CALL39 (0x00, 0xF4, "fast_call39", imm.NONE, null), - //FAST_CALL40 (0x00, 0xF5, "fast_call40", imm.NONE, null), - //FAST_CALL41 (0x00, 0xF6, "fast_call41", imm.NONE, null), - //FAST_CALL42 (0x00, 0xF7, "fast_call42", imm.NONE, null), - //FAST_CALL43 (0x00, 0xF8, "fast_call43", imm.NONE, null), - //FAST_CALL44 (0x00, 0xF9, "fast_call44", imm.NONE, null), - //FAST_CALL45 (0x00, 0xFA, "fast_call45", imm.NONE, null), - //FAST_CALL46 (0x00, 0xFF, "fast_call46", imm.NONE, null) + FAST_CALL0 (0x00, 0x27, "fast_call0", imm.NONE, null), + FAST_CALL1 (0x00, 0xC5, "fast_call1", imm.NONE, null), + FAST_CALL2 (0x00, 0xC6, "fast_call2", imm.NONE, null), + FAST_CALL3 (0x00, 0xC7, "fast_call3", imm.NONE, null), + FAST_CALL4 (0x00, 0xC8, "fast_call4", imm.NONE, null), + FAST_CALL5 (0x00, 0xC9, "fast_call5", imm.NONE, null), + FAST_CALL6 (0x00, 0xCA, "fast_call6", imm.NONE, null), + FAST_CALL7 (0x00, 0xCB, "fast_call7", imm.NONE, null), + FAST_CALL8 (0x00, 0xCC, "fast_call8", imm.NONE, null), + FAST_CALL9 (0x00, 0xCD, "fast_call9", imm.NONE, null), + FAST_CALL10 (0x00, 0xCE, "fast_call10", imm.NONE, null), + FAST_CALL11 (0x00, 0xCF, "fast_call11", imm.NONE, null), + FAST_CALL12 (0x00, 0xD7, "fast_call12", imm.NONE, null), + FAST_CALL13 (0x00, 0xD8, "fast_call13", imm.NONE, null), + FAST_CALL14 (0x00, 0xD9, "fast_call14", imm.NONE, null), + FAST_CALL15 (0x00, 0xDA, "fast_call15", imm.NONE, null), + FAST_CALL16 (0x00, 0xDB, "fast_call16", imm.NONE, null), + FAST_CALL17 (0x00, 0xDC, "fast_call17", imm.NONE, null), + FAST_CALL18 (0x00, 0xDD, "fast_call18", imm.NONE, null), + FAST_CALL19 (0x00, 0xDE, "fast_call19", imm.NONE, null), + FAST_CALL20 (0x00, 0xDF, "fast_call20", imm.NONE, null), + FAST_CALL21 (0x00, 0xE0, "fast_call21", imm.NONE, null), + FAST_CALL22 (0x00, 0xE1, "fast_call22", imm.NONE, null), + FAST_CALL23 (0x00, 0xE2, "fast_call23", imm.NONE, null), + FAST_CALL24 (0x00, 0xE3, "fast_call24", imm.NONE, null), + FAST_CALL25 (0x00, 0xE4, "fast_call25", imm.NONE, null), + FAST_CALL26 (0x00, 0xE5, "fast_call26", imm.NONE, null), + FAST_CALL27 (0x00, 0xE6, "fast_call27", imm.NONE, null), + FAST_CALL28 (0x00, 0xE7, "fast_call28", imm.NONE, null), + FAST_CALL29 (0x00, 0xE8, "fast_call29", imm.NONE, null), + FAST_CALL30 (0x00, 0xE9, "fast_call30", imm.NONE, null), + FAST_CALL31 (0x00, 0xEA, "fast_call31", imm.NONE, null), + FAST_CALL32 (0x00, 0xEB, "fast_call32", imm.NONE, null), + FAST_CALL33 (0x00, 0xEC, "fast_call33", imm.NONE, null), + FAST_CALL34 (0x00, 0xED, "fast_call34", imm.NONE, null), + FAST_CALL35 (0x00, 0xEE, "fast_call35", imm.NONE, null), + FAST_CALL36 (0x00, 0xEF, "fast_call36", imm.NONE, null), + FAST_CALL37 (0x00, 0xF2, "fast_call37", imm.NONE, null), + FAST_CALL38 (0x00, 0xF3, "fast_call38", imm.NONE, null), + FAST_CALL39 (0x00, 0xF4, "fast_call39", imm.NONE, null), + FAST_CALL40 (0x00, 0xF5, "fast_call40", imm.NONE, null), + FAST_CALL41 (0x00, 0xF6, "fast_call41", imm.NONE, null), + FAST_CALL42 (0x00, 0xF7, "fast_call42", imm.NONE, null), + FAST_CALL43 (0x00, 0xF8, "fast_call43", imm.NONE, null), + FAST_CALL44 (0x00, 0xF9, "fast_call44", imm.NONE, null), + FAST_CALL45 (0x00, 0xFA, "fast_call45", imm.NONE, null), + FAST_CALL46 (0x00, 0xFF, "fast_call46", imm.NONE, null), + FAST_CALL47 (0x00, 0x17, "fast_call47", imm.FUNC, null) } -//def indexToFastCall(index: int) -> Opcode { -// var op: Opcode; -// match (index) { -// 0 => op = Opcode.FAST_CALL0; -// 1 => op = Opcode.FAST_CALL1; -// 2 => op = Opcode.FAST_CALL2; -// 3 => op = Opcode.FAST_CALL3; -// 4 => op = Opcode.FAST_CALL4; -// 5 => op = Opcode.FAST_CALL5; -// 6 => op = Opcode.FAST_CALL6; -// 7 => op = Opcode.FAST_CALL7; -// 8 => op = Opcode.FAST_CALL8; -// 9 => op = Opcode.FAST_CALL9; -// 10 => op = Opcode.FAST_CALL10; -// 11 => op = Opcode.FAST_CALL11; -// 12 => op = Opcode.FAST_CALL12; -// 13 => op = Opcode.FAST_CALL13; -// 14 => op = Opcode.FAST_CALL14; -// 15 => op = Opcode.FAST_CALL15; -// 16 => op = Opcode.FAST_CALL16; -// 17 => op = Opcode.FAST_CALL17; -// 18 => op = Opcode.FAST_CALL18; -// 19 => op = Opcode.FAST_CALL19; -// 20 => op = Opcode.FAST_CALL20; -// 21 => op = Opcode.FAST_CALL21; -// 22 => op = Opcode.FAST_CALL22; -// 23 => op = Opcode.FAST_CALL23; -// 24 => op = Opcode.FAST_CALL24; -// 25 => op = Opcode.FAST_CALL25; -// 26 => op = Opcode.FAST_CALL26; -// 27 => op = Opcode.FAST_CALL27; -// 28 => op = Opcode.FAST_CALL28; -// 29 => op = Opcode.FAST_CALL29; -// 30 => op = Opcode.FAST_CALL30; -// 31 => op = Opcode.FAST_CALL31; -// 32 => op = Opcode.FAST_CALL32; -// 33 => op = Opcode.FAST_CALL33; -// 34 => op = Opcode.FAST_CALL34; -// 35 => op = Opcode.FAST_CALL35; -// 36 => op = Opcode.FAST_CALL36; -// 37 => op = Opcode.FAST_CALL37; -// 38 => op = Opcode.FAST_CALL38; -// 39 => op = Opcode.FAST_CALL39; -// 40 => op = Opcode.FAST_CALL40; -// 41 => op = Opcode.FAST_CALL41; -// 42 => op = Opcode.FAST_CALL42; -// 43 => op = Opcode.FAST_CALL43; -// 44 => op = Opcode.FAST_CALL44; -// 45 => op = Opcode.FAST_CALL45; -// 46 => op = Opcode.FAST_CALL46; -// 47 => op = Opcode.FAST_CALL47; -// _ => System.error("indexToFastCall", "out of range"); -// } -// return op; -//} // Enumeration of the different kinds of immediates to opcodes. enum ImmKind { @@ -905,9 +850,14 @@ component Opcodes { def code_pages = [page_FB, page_FC, page_FD, page_FE]; def var longestName: int; def var num_subpages: int; + def var fast_calls: Array; private var nameMap: HashMap; new() { + fast_calls = Array.new(48); + for (i < 48) { + fast_calls[i] = indexToFastCall(i); + } for (op in Opcode) { if (op == Opcode.INVALID) continue; init(op); @@ -916,7 +866,8 @@ component Opcodes { attributes[InternalOpcode.PROBE.code] = OpcodeAttribute.INTERNAL | OpcodeAttribute.PROBE; attributes[InternalOpcode.WHAMM_PROBE.code] = OpcodeAttribute.INTERNAL | OpcodeAttribute.PROBE; attributes[InternalOpcode.BREAK_PROBE.code] = OpcodeAttribute.INTERNAL | OpcodeAttribute.PROBE; - attributes[Opcode.FAST_CALL.tag] = OpcodeAttribute.INTERNAL; + for (op in fast_calls) + attributes[op.tag] = OpcodeAttribute.INTERNAL; for (op in [Opcode.END, Opcode.I32_CONST, Opcode.I64_CONST, Opcode.F32_CONST, Opcode.F64_CONST, Opcode.GLOBAL_GET, Opcode.REF_NULL, Opcode.REF_FUNC, Opcode.STRUCT_NEW, Opcode.STRUCT_NEW_DEFAULT, @@ -1229,6 +1180,116 @@ component Opcodes { } } } + def indexToFastCall(index: int) -> Opcode { + var op: Opcode; + match (index) { + 0 => op = Opcode.FAST_CALL0; + 1 => op = Opcode.FAST_CALL1; + 2 => op = Opcode.FAST_CALL2; + 3 => op = Opcode.FAST_CALL3; + 4 => op = Opcode.FAST_CALL4; + 5 => op = Opcode.FAST_CALL5; + 6 => op = Opcode.FAST_CALL6; + 7 => op = Opcode.FAST_CALL7; + 8 => op = Opcode.FAST_CALL8; + 9 => op = Opcode.FAST_CALL9; + 10 => op = Opcode.FAST_CALL10; + 11 => op = Opcode.FAST_CALL11; + 12 => op = Opcode.FAST_CALL12; + 13 => op = Opcode.FAST_CALL13; + 14 => op = Opcode.FAST_CALL14; + 15 => op = Opcode.FAST_CALL15; + 16 => op = Opcode.FAST_CALL16; + 17 => op = Opcode.FAST_CALL17; + 18 => op = Opcode.FAST_CALL18; + 19 => op = Opcode.FAST_CALL19; + 20 => op = Opcode.FAST_CALL20; + 21 => op = Opcode.FAST_CALL21; + 22 => op = Opcode.FAST_CALL22; + 23 => op = Opcode.FAST_CALL23; + 24 => op = Opcode.FAST_CALL24; + 25 => op = Opcode.FAST_CALL25; + 26 => op = Opcode.FAST_CALL26; + 27 => op = Opcode.FAST_CALL27; + 28 => op = Opcode.FAST_CALL28; + 29 => op = Opcode.FAST_CALL29; + 30 => op = Opcode.FAST_CALL30; + 31 => op = Opcode.FAST_CALL31; + 32 => op = Opcode.FAST_CALL32; + 33 => op = Opcode.FAST_CALL33; + 34 => op = Opcode.FAST_CALL34; + 35 => op = Opcode.FAST_CALL35; + 36 => op = Opcode.FAST_CALL36; + 37 => op = Opcode.FAST_CALL37; + 38 => op = Opcode.FAST_CALL38; + 39 => op = Opcode.FAST_CALL39; + 40 => op = Opcode.FAST_CALL40; + 41 => op = Opcode.FAST_CALL41; + 42 => op = Opcode.FAST_CALL42; + 43 => op = Opcode.FAST_CALL43; + 44 => op = Opcode.FAST_CALL44; + 45 => op = Opcode.FAST_CALL45; + 46 => op = Opcode.FAST_CALL46; + 47 => op = Opcode.FAST_CALL47; + _ => System.error("indexToFastCall", "out of range"); + } + return op; + } + def fastCallToIndex(op: Opcode) -> int { + var idx: int; + match (op) { + FAST_CALL0 => idx = 0; + FAST_CALL1 => idx = 1; + FAST_CALL2 => idx = 2; + FAST_CALL3 => idx = 3; + FAST_CALL4 => idx = 4; + FAST_CALL5 => idx = 5; + FAST_CALL6 => idx = 6; + FAST_CALL7 => idx = 7; + FAST_CALL8 => idx = 8; + FAST_CALL9 => idx = 9; + FAST_CALL10 => idx = 10; + FAST_CALL11 => idx = 11; + FAST_CALL12 => idx = 12; + FAST_CALL13 => idx = 13; + FAST_CALL14 => idx = 14; + FAST_CALL15 => idx = 15; + FAST_CALL16 => idx = 16; + FAST_CALL17 => idx = 17; + FAST_CALL18 => idx = 18; + FAST_CALL19 => idx = 19; + FAST_CALL20 => idx = 20; + FAST_CALL21 => idx = 21; + FAST_CALL22 => idx = 22; + FAST_CALL23 => idx = 23; + FAST_CALL24 => idx = 24; + FAST_CALL25 => idx = 25; + FAST_CALL26 => idx = 26; + FAST_CALL27 => idx = 27; + FAST_CALL28 => idx = 28; + FAST_CALL29 => idx = 29; + FAST_CALL30 => idx = 30; + FAST_CALL31 => idx = 31; + FAST_CALL32 => idx = 32; + FAST_CALL33 => idx = 33; + FAST_CALL34 => idx = 34; + FAST_CALL35 => idx = 35; + FAST_CALL36 => idx = 36; + FAST_CALL37 => idx = 37; + FAST_CALL38 => idx = 38; + FAST_CALL39 => idx = 39; + FAST_CALL40 => idx = 40; + FAST_CALL41 => idx = 41; + FAST_CALL42 => idx = 42; + FAST_CALL43 => idx = 43; + FAST_CALL44 => idx = 44; + FAST_CALL45 => idx = 45; + FAST_CALL46 => idx = 46; + FAST_CALL47 => idx = 47; + _ => System.error("fastCallToIndex", "not a FAST_CALL instruction"); + } + return idx; + } } // Renders instructions as text. diff --git a/src/engine/v3/V3Interpreter.v3 b/src/engine/v3/V3Interpreter.v3 index 2af335ae5..2dd1728c2 100644 --- a/src/engine/v3/V3Interpreter.v3 +++ b/src/engine/v3/V3Interpreter.v3 @@ -371,7 +371,7 @@ class V3Interpreter extends WasmStack { RETURN => { doReturn(frame.fp, frame.func.sig); } - CALL, FAST_CALL => { + CALL, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39, FAST_CALL40, FAST_CALL41, FAST_CALL42, FAST_CALL43, FAST_CALL44, FAST_CALL45, FAST_CALL46, FAST_CALL47 => { var func_index = codeptr.read_uleb32(); var f = frame.func.instance.functions[func_index]; return doCallFunction(f); @@ -1640,7 +1640,7 @@ class V3Interpreter extends WasmStack { // XXX: use read_opcode_and_skip() var opcode = codeptr.read_opcode_but_skip_probe(frame.func.decl); match (opcode) { - CALL, CALL_REF, FAST_CALL => { + CALL, CALL_REF, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39, FAST_CALL40, FAST_CALL41, FAST_CALL42, FAST_CALL43, FAST_CALL44, FAST_CALL45, FAST_CALL46, FAST_CALL47 => { codeptr.skip_leb(); frame.pc = codeptr.pos; } diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index 0698a35f5..1c4c53711 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -1323,7 +1323,56 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { genPopFrameAndRet(); // FAST_CALL - bindHandler(Opcode.FAST_CALL); + // TODO patch the dispatch table so it goes to the code directly, + // instead of this fast function lookup + bindHandler(Opcode.FAST_CALL0); + bindHandler(Opcode.FAST_CALL1); + bindHandler(Opcode.FAST_CALL2); + bindHandler(Opcode.FAST_CALL3); + bindHandler(Opcode.FAST_CALL4); + bindHandler(Opcode.FAST_CALL5); + bindHandler(Opcode.FAST_CALL6); + bindHandler(Opcode.FAST_CALL7); + bindHandler(Opcode.FAST_CALL8); + bindHandler(Opcode.FAST_CALL9); + bindHandler(Opcode.FAST_CALL10); + bindHandler(Opcode.FAST_CALL11); + bindHandler(Opcode.FAST_CALL12); + bindHandler(Opcode.FAST_CALL13); + bindHandler(Opcode.FAST_CALL14); + bindHandler(Opcode.FAST_CALL15); + bindHandler(Opcode.FAST_CALL16); + bindHandler(Opcode.FAST_CALL17); + bindHandler(Opcode.FAST_CALL18); + bindHandler(Opcode.FAST_CALL19); + bindHandler(Opcode.FAST_CALL20); + bindHandler(Opcode.FAST_CALL21); + bindHandler(Opcode.FAST_CALL22); + bindHandler(Opcode.FAST_CALL23); + bindHandler(Opcode.FAST_CALL24); + bindHandler(Opcode.FAST_CALL25); + bindHandler(Opcode.FAST_CALL26); + bindHandler(Opcode.FAST_CALL27); + bindHandler(Opcode.FAST_CALL28); + bindHandler(Opcode.FAST_CALL29); + bindHandler(Opcode.FAST_CALL30); + bindHandler(Opcode.FAST_CALL31); + bindHandler(Opcode.FAST_CALL32); + bindHandler(Opcode.FAST_CALL33); + bindHandler(Opcode.FAST_CALL34); + bindHandler(Opcode.FAST_CALL35); + bindHandler(Opcode.FAST_CALL36); + bindHandler(Opcode.FAST_CALL37); + bindHandler(Opcode.FAST_CALL38); + bindHandler(Opcode.FAST_CALL39); + bindHandler(Opcode.FAST_CALL40); + bindHandler(Opcode.FAST_CALL41); + bindHandler(Opcode.FAST_CALL42); + bindHandler(Opcode.FAST_CALL43); + bindHandler(Opcode.FAST_CALL44); + bindHandler(Opcode.FAST_CALL45); + bindHandler(Opcode.FAST_CALL46); + bindHandler(Opcode.FAST_CALL47); //masm.emit_debugger_breakpoint(); var dispatchLabel = X86_64Label.new(); // genTagPush(BpTypeCode.I32.code); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index a797f17c8..a2fd81e3c 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -1566,11 +1566,11 @@ def genFastCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { masm.emit_store_curstack_vsp(regs.vsp); masm.emit_debugger_breakpoint(); - asm.movq_r_r(Target.V3_PARAM_GPRS[1], G(regs.func_arg)); // function (rdx) - asm.movq_r_i(Target.V3_PARAM_GPRS[2], int.!(Pointer.atObject(ic) - Pointer.NULL)); // load into rdx + asm.movq_r_r(G(Target.V3_PARAM_GPRS[1]), G(regs.func_arg)); // function (rdx) + asm.movq_r_i(G(Target.V3_PARAM_GPRS[2]), int.!(Pointer.atObject(ic) - Pointer.NULL)); // load into rdx // dispatch is in r14 (don't overwrite, just access directly) // Load {null} for the receiver. - asm.movq_r_i(Target.V3_PARAM_GPRS[0], 0); + asm.movq_r_i(G(Target.V3_PARAM_GPRS[0]), 0); // Call {X86_64Spc.fastCompile} directly. //masm.emit_debugger_breakpoint(); masm.emit_call_abs(codePointer(X86_64Spc.fastCompile)); @@ -1578,12 +1578,12 @@ def genFastCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { asm.q.add_r_i(R.RSP, Pointer.SIZE); // pop function off stack // Check for non-null abrupt return. var unwind = X86_64Label.new(); - asm.q.cmp_r_i(Target.V3_RET_GPRS[2], 0); + asm.q.cmp_r_i(G(Target.V3_RET_GPRS[2]), 0); asm.jc_rel_near(C.NZ, unwind); // Tail-call the result of the compile. var scratch = X86_64Regs.R9; - asm.movq_r_r(scratch, Target.V3_RET_GPRS[1]); // entrypoint - asm.movq_r_r(G(regs.func_arg), Target.V3_RET_GPRS[0]); // function + asm.movq_r_r(scratch, G(Target.V3_RET_GPRS[1])); // entrypoint + asm.movq_r_r(G(regs.func_arg), G(Target.V3_RET_GPRS[0])); // function //for (i < all_ivars.length) { // asm.popq_r(all_ivars[all_ivars.length - i - 1].0); @@ -1599,7 +1599,7 @@ def genFastCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { // Simply return the {Throwable} object. ?? asm.bind(unwind); - asm.movq_r_r(Target.V3_RET_GPRS[0], Target.V3_RET_GPRS[2]); + asm.movq_r_r(G(Target.V3_RET_GPRS[0]), G(Target.V3_RET_GPRS[2])); asm.ret(); } def genFastNopStub(ic: X86_64InterpreterCode, w: DataWriter) { diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index fbef09684..0e710a65b 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -249,6 +249,7 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { def onModuleFinish(module: Module, size: u32, err: ErrorGen) { disableLazyNameDecodingDuringGC(module); + fastCompileEntireModule(module, size, false, err, 1024); } def onFuncValidationFinish(module: Module, func: FuncDecl, err: ErrorGen) { if (err != null && !err.ok()) return; @@ -363,11 +364,6 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { module.target_module.spc_code.keepAlive(); Debug.afterCompileModule(module); } - - // XXX not an exhaustive way to add stubs. but what is? - def onModuleFinish(module: Module, size: u32, err: ErrorGen) { - fastCompileEntireModule(module, size, false, err, 1024); - } } // Base class of all strategies that use SPC. diff --git a/src/util/BytecodeVisitor.v3 b/src/util/BytecodeVisitor.v3 index adc822bfe..cacd6c738 100644 --- a/src/util/BytecodeVisitor.v3 +++ b/src/util/BytecodeVisitor.v3 @@ -70,7 +70,7 @@ class BytecodeVisitor { def visit_BR_TABLE (labels: Range) { visitControl(Opcode.BR_TABLE); } def visit_RETURN () { visitControl(Opcode.RETURN); } def visit_CALL (func_index: u31) { visitCallDirect(Opcode.CALL, func_index, SLOW); } - def visit_FAST_CALL (func_index: u31) { visitCallDirect(Opcode.FAST_CALL, func_index, FAST); } + def visit_FAST_CALL (fast_index: int, func_index: u31) { visitCallDirect(Opcodes.indexToFastCall(fast_index), func_index, FAST); } def visit_CALL_INDIRECT (sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.CALL_INDIRECT, sig_index, table_index, SLOW); } def visit_RETURN_CALL (func_index: u31) { visitCallDirect(Opcode.RETURN_CALL, func_index, TAIL); } def visit_RETURN_CALL_INDIRECT(sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.RETURN_CALL_INDIRECT, sig_index, table_index, TAIL); } From 6cd1466b6d0cd917d33afb15d94b5371754bfea9 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 1 Apr 2026 18:21:42 -0400 Subject: [PATCH 19/91] Patch the dispatch table with fast-compiled functions (and use them) + others * added FastIntTuning.useFastFunctions which could control use of fast functions * added Mmap.reserve32 to use MAP_32BIT to force 4-byte addresses in dispatch table * allow PROT_WRITE in executable code for the dispatch table patching - probably needs to be refined to be just the table region * added u32leb_size helper (should really be removed) * add fast_call_idx so that we can get opcode from function later for patching * advance PC beyond operands (which remain in place, orig function index) --- src/engine/CodeValidator.v3 | 1 + src/engine/Module.v3 | 1 + src/engine/Tuning.v3 | 1 + src/engine/x86-64/Mmap.v3 | 10 +++++++ src/engine/x86-64/X86_64Interpreter.v3 | 12 ++++++++ src/engine/x86-64/X86_64PreGenStubs.v3 | 4 +-- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 7 +++++ src/engine/x86-64/X86_64Target.v3 | 29 +++++++++++++++++-- 8 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index 281b14a01..d7b939791 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -441,6 +441,7 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e if (fast_idx < 0) { if (fast_funcs.length < 48) { fast_idx = fast_funcs.length; + func.fast_call_idx = fast_idx; if (Trace.validation) Trace.OUT.put1("not found, allocating FAST_CALL%d, ", fast_idx); fast_funcs.put(func); } else { diff --git a/src/engine/Module.v3 b/src/engine/Module.v3 index c7438ecba..b19b3f0b9 100644 --- a/src/engine/Module.v3 +++ b/src/engine/Module.v3 @@ -143,6 +143,7 @@ class FuncDecl(sig_index: int) extends Decl { var frame_var_tags: Array; // value tags for frame variables var target_code: TargetCode; var fast_target_code: TargetCode; + var fast_call_idx: int = -1; var tierup_trigger: int = int.max; var handlers = FuncHandlerInfo.new(); diff --git a/src/engine/Tuning.v3 b/src/engine/Tuning.v3 index c7a6f837b..4fa9fa903 100644 --- a/src/engine/Tuning.v3 +++ b/src/engine/Tuning.v3 @@ -42,6 +42,7 @@ component FastIntTuning { def inlineGlobalAccess = true; // enable inline access of (primitive) globals def stealFlagBitForMemory64 = true; // use a bit in the memarg flags for memory64 def whammProbeTrampolineNumPages = 1024; + def useFastFunctions = true; // treat functions exported with `fast:` in the name as fast functions } // Tuning settings for the single-pass compiler that have no effect on correctness. diff --git a/src/engine/x86-64/Mmap.v3 b/src/engine/x86-64/Mmap.v3 index 672bba1c9..cdf21e2ae 100644 --- a/src/engine/x86-64/Mmap.v3 +++ b/src/engine/x86-64/Mmap.v3 @@ -18,6 +18,16 @@ component Mmap { RiGc.registerFinalizer(mapping, range.unmap); return mapping; } + def reserve32(size: u64, prot: int) -> Mapping { + var flags = LinuxConst.MAP_PRIVATE | LinuxConst.MAP_ANONYMOUS | 0x40; // 0x40 = MAP_32BIT + var r = Linux.syscall(LinuxConst.SYS_mmap, (Pointer.NULL, size, prot, flags, 0, 0)); + if (r.0 == -1) return null; + var start = Pointer.NULL + r.0, end = start + i64.view(size); + var range = MemoryRange.new(start, end); + var mapping = Mapping.new(range); + RiGc.registerFinalizer(mapping, range.unmap); + return mapping; + } def protect(start: Pointer, size: u64, prot: int) -> bool { var r = Linux.syscall(LinuxConst.SYS_mprotect, (start, size, prot)); return r.0 == 0; diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index 1c4c53711..736eb37a7 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -1373,12 +1373,24 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { bindHandler(Opcode.FAST_CALL45); bindHandler(Opcode.FAST_CALL46); bindHandler(Opcode.FAST_CALL47); + masm.emit_intentional_crash(); //masm.emit_debugger_breakpoint(); var dispatchLabel = X86_64Label.new(); // genTagPush(BpTypeCode.I32.code); // asm.movq_m_i(vsph[0].value, 770); // incrementVsp(); + /* TODO What should happen in a FAST_CALL? + * + * Ideally, we've patched the dispatch table with exactly what appears in fast_target_code + * so it instantly jumps there and so we don't have to set up the jump first. + * + * Fast function implementation should include code to skip the original operand as + * part of incrementing pc (will be done over in SPC). + * + * But, we could keep this for a quasi-fast call? + */ + genReadUleb32(r_tmp1); asm.movq_r_m(r_tmp0, r_instance.plus(offsets.Instance_functions)); asm.movq_r_m(func_arg, r_tmp0.plusR(r_tmp1, offsets.REF_SIZE, offsets.Array_contents)); diff --git a/src/engine/x86-64/X86_64PreGenStubs.v3 b/src/engine/x86-64/X86_64PreGenStubs.v3 index 74985e55f..959c732a0 100644 --- a/src/engine/x86-64/X86_64PreGenStubs.v3 +++ b/src/engine/x86-64/X86_64PreGenStubs.v3 @@ -222,8 +222,8 @@ component X86_64PreGenStubs { ic.header.probedDispatchTableOffset, ic.header.fastDispatchTableOffset); - // Write-protect the executable code for security and debugging - Mmap.protect(range.start + ic.header.codeStart, u64.!(ic.header.codeEnd - ic.header.codeStart), Mmap.PROT_READ | Mmap.PROT_EXEC); + // XXX: PROT_WRITE included to allow runtime dispatch table patching + Mmap.protect(range.start + ic.header.codeStart, u64.!(ic.header.codeEnd - ic.header.codeStart), Mmap.PROT_READ | Mmap.PROT_WRITE | Mmap.PROT_EXEC); // The host call stub is part of interpreter code (TODO: does it need to be?) hostCallStub.start = ic.start + ic.header.hostCallStubOffset; diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index a2fd81e3c..634b13691 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -3,6 +3,11 @@ // XXX: reduce duplication with MacroAssembler def G = X86_64MasmRegs.toGpr, X = X86_64MasmRegs.toXmmr; +def u32leb_size(v: int) -> int { + var n = 1, data = u32.view(v); + while (data >= 0x80) { data = data >> 7; n++; } + return n; +} def R: X86_64Regs; def C: X86_64Conds; def A(ma: MasmAddr) -> X86_64Addr { @@ -48,6 +53,8 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } def emitFastPrologue() { + // Advance r_ip past the ULEB32 operand (original CALL function index) + asm.add_r_i(G(X86_64MasmRegs.INT_EXEC_ENV.ip), u32leb_size(func.func_index)); // Compute VFP = VSP - sig.params.length * SLOT_SIZE (no native stack frame needed) masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 0e710a65b..dcb88c903 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -79,9 +79,32 @@ component Target { Trace.OUT.ln(); } } - f.fast_target_code = TargetCode(addr); + f.fast_target_code = TargetCode(addr); + patchFastCallDispatch(f, addr); Debug.afterCompile(f, u64.view(addr - Pointer.NULL)); } + def patchFastCallDispatch(f: FuncDecl, addr: Pointer) { + if (f.fast_call_idx < 0) return; + def opcode = Opcodes.indexToFastCall(f.fast_call_idx); + def ic = X86_64PreGenStubs.getInterpreterCode(); + // XXX Patch only fast dispatch tables + def fast_offset = ic.header.fastDispatchTableOffset; + def entry = ic.start + fast_offset + opcode.code * FastIntTuning.dispatchEntrySize; + if (Trace.compiler) { + Trace.OUT.puts("patching dispatch type\n"); + Trace.OUT.put1("start 0x%x\n", u64.view(ic.start)); + Trace.OUT.put1("entry 0x%x\n", u64.view(entry)); + Trace.OUT.put1("addr 0x%x\n", u64.view(addr)); + } + // XXX we require 8 entry size because of `addr` position + match (FastIntTuning.dispatchEntrySize) { + 4 => entry.store(u32.view(addr)); + 8 => entry.store(long.view(addr)); + // 2-byte relative case would need a relative offset + } + if (Trace.compiler) Trace.OUT.puts("patched successfully\n"); + } + def pregenIntoFile(filename: string) -> ErrorBuilder { var data = System.fileLoad(filename); var err = ErrorBuilder.new().puts("interpreter generator: "); @@ -328,9 +351,9 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { } } - // copy and map code + // copy and map code (reserve32 ensures address fits in 32 bits for dispatch table patching) var length = u64.view(w.atEnd().pos) + ballast; - var mapping = Mmap.reserve(length, Mmap.PROT_WRITE), range = mapping.range; // TODO: handle failure + var mapping = Mmap.reserve32(length, Mmap.PROT_WRITE), range = mapping.range; // TODO: handle failure var masm = X86_64MacroAssembler.!(compiler.masm); masm.setTargetAddress(u64.view(range.start - Pointer.NULL)); Target.copyInto(mapping.range, 0, w); From 7e7013be28d6042042f9c6166b2698342c9e94df Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 2 Apr 2026 11:56:02 -0400 Subject: [PATCH 20/91] Cleaned up some stuff --- src/engine/CodeValidator.v3 | 4 +- src/engine/Module.v3 | 2 +- src/engine/Opcodes.v3 | 4 +- src/engine/compiler/SinglePassCompiler.v3 | 74 ++++++++++--------- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 18 ----- 5 files changed, 44 insertions(+), 58 deletions(-) diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index d7b939791..0815a7714 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -422,7 +422,7 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e checkSignature(func.sig); // fast call: if function is exported with fast name, replace the bytecode with FAST_CALL - for (i < module.exports.length) { + if (FastIntTuning.useFastFunctions) for (i < module.exports.length) { def ex = module.exports[i]; if (ex.1 == func && Strings.startsWith(ex.0, "fast:")) { if (Trace.validation) Trace.OUT.puts(" function declared as fast: "); @@ -434,7 +434,7 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e if (func == fast_funcs[i]) { fast_idx = i; if (Trace.validation) Trace.OUT.put1("allocated as FAST_CALL%d, ", fast_idx); - break; + break; } } // not found? allocate FAST_CALL instruction, if there's space diff --git a/src/engine/Module.v3 b/src/engine/Module.v3 index b19b3f0b9..ecdabfcdf 100644 --- a/src/engine/Module.v3 +++ b/src/engine/Module.v3 @@ -179,7 +179,7 @@ class FuncDecl(sig_index: int) extends Decl { if (cur_bytecode[pc] != Opcode.CALL.code) { def realOp = Opcodes.find(0, cur_bytecode[pc]); System.error("replace bytecode", Strings.format1("not replacing call (got %s)", realOp.mnemonic)); - } + } cur_bytecode[pc] = byte.!(Opcodes.indexToFastCall(idx).code); // do NOT replace the operands, as a convenience for BytecodeIterator } diff --git a/src/engine/Opcodes.v3 b/src/engine/Opcodes.v3 index db9c56009..0998599ea 100644 --- a/src/engine/Opcodes.v3 +++ b/src/engine/Opcodes.v3 @@ -32,7 +32,6 @@ enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: RETURN_CALL_INDIRECT (0x00, 0x13, "return_call_indirect", imm.SIG_TABLE, null), CALL_REF (0x00, 0x14, "call_ref", imm.SIG, null), RETURN_CALL_REF (0x00, 0x15, "return_call_ref", imm.SIG, null), - // Fast handler custom instruction DELEGATE (0x00, 0x18, "delegate", imm.LABEL, null), CATCH_ALL (0x00, 0x19, "catch_all", imm.NONE, null), DROP (0x00, 0x1A, "drop", imm.NONE, null), @@ -866,8 +865,7 @@ component Opcodes { attributes[InternalOpcode.PROBE.code] = OpcodeAttribute.INTERNAL | OpcodeAttribute.PROBE; attributes[InternalOpcode.WHAMM_PROBE.code] = OpcodeAttribute.INTERNAL | OpcodeAttribute.PROBE; attributes[InternalOpcode.BREAK_PROBE.code] = OpcodeAttribute.INTERNAL | OpcodeAttribute.PROBE; - for (op in fast_calls) - attributes[op.tag] = OpcodeAttribute.INTERNAL; + for (op in fast_calls) attributes[op.tag] = OpcodeAttribute.INTERNAL; for (op in [Opcode.END, Opcode.I32_CONST, Opcode.I64_CONST, Opcode.F32_CONST, Opcode.F64_CONST, Opcode.GLOBAL_GET, Opcode.REF_NULL, Opcode.REF_FUNC, Opcode.STRUCT_NEW, Opcode.STRUCT_NEW_DEFAULT, diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 0c5325455..5f8845ba5 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -205,11 +205,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl pushSpcFrame(initial_frame); // Emit prologue, which allocates the frame and initializes various registers. - if (fast) { - emitFastPrologue(); - } else { - emitPrologue(); - } + emitPrologue(); // Visit all local declarations. it.dispatchLocalDecls(this); @@ -386,36 +382,43 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (!cond) bailout(Strings.format3(msg, p1, p2, p3)); } def emitPrologue() { - // Allocate stack frame - masm.emit_subw_r_i(regs.sp, frame.frameSize); - - // Spill VSP - emit_spill_vsp(regs.vsp); // XXX: track VSP-spilled state - // Spill wf: WasmFunction - masm.emit_mov_m_r(ValueKind.REF, frame.wasm_func_slot, regs.func_arg); - // Load wf.instance and spill - masm.emit_v3_WasmFunction_instance_r_r(regs.instance, regs.func_arg); - masm.emit_mov_m_r(ValueKind.REF, frame.instance_slot, regs.instance); - // Clear FrameAccessor - masm.emit_mov_m_l(frame.accessor_slot, 0); // XXX: value kind - // Clear inlined whamm instance - if (SpcTuning.inlineWhammProbes && SpcTuning.intrinsifyWhammProbe) { - masm.emit_mov_m_l(frame.inlined_instance_slot, 0); + if (!fast) { + // Allocate stack frame + masm.emit_subw_r_i(regs.sp, frame.frameSize); + + // Spill VSP + emit_spill_vsp(regs.vsp); // XXX: track VSP-spilled state + // Spill wf: WasmFunction + masm.emit_mov_m_r(ValueKind.REF, frame.wasm_func_slot, regs.func_arg); + // Load wf.instance and spill + masm.emit_v3_WasmFunction_instance_r_r(regs.instance, regs.func_arg); + masm.emit_mov_m_r(ValueKind.REF, frame.instance_slot, regs.instance); + // Clear FrameAccessor + masm.emit_mov_m_l(frame.accessor_slot, 0); // XXX: value kind + // Clear inlined whamm instance + if (SpcTuning.inlineWhammProbes && SpcTuning.intrinsifyWhammProbe) { + masm.emit_mov_m_l(frame.inlined_instance_slot, 0); + } + } else { + masm.emit_addw_r_i(X86_64MasmRegs.INT_EXEC_ENV.ip, uleb_size(func.func_index)); } // Compute VFP = VSP - sig.params.length * SLOT_SIZE masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); // XXX: use 3-addr adjustment of VFP masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); - // XXX: skip spilling of VFP - masm.emit_mov_m_r(ValueKind.REF, frame.vfp_slot, regs.vfp); - // Load instance.memories[0].start into MEM0_BASE and spill - if (module.memories.length > 0) { - // XXX: skip loading memory base if function doesn't access memory - masm.emit_v3_Instance_memories_r_r(regs.mem0_base, regs.instance); - masm.emit_v3_Array_elem_r_ri(ValueKind.REF, regs.mem0_base, regs.mem0_base, 0); - masm.emit_v3_Memory_start_r_r(regs.mem0_base, regs.mem0_base); - masm.emit_mov_m_r(ValueKind.REF, frame.mem0_base_slot, regs.mem0_base); + if (!fast) { + // XXX: skip spilling of VFP + masm.emit_mov_m_r(ValueKind.REF, frame.vfp_slot, regs.vfp); + + // Load instance.memories[0].start into MEM0_BASE and spill + if (module.memories.length > 0) { + // XXX: skip loading memory base if function doesn't access memory + masm.emit_v3_Instance_memories_r_r(regs.mem0_base, regs.instance); + masm.emit_v3_Array_elem_r_ri(ValueKind.REF, regs.mem0_base, regs.mem0_base, 0); + masm.emit_v3_Memory_start_r_r(regs.mem0_base, regs.mem0_base); + masm.emit_mov_m_r(ValueKind.REF, frame.mem0_base_slot, regs.mem0_base); + } } } def visitLocalDecl(count: u32, vtc: ValueTypeCode) { @@ -2194,7 +2197,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.bindLabel(ret_label); ret_label = null; } - emitFastEpilogue1(); @@ -2221,14 +2223,12 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_addw_r_i(regs.sp, frame.frameSize); // | masm.emit_ret(); // / } else { - emitFastEpilogue2(); + // Restore VFP from interpreter frame + masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); emitFastDispatch(); } } def emitFastDispatch() -> void; - def emitFastPrologue() -> void; - def emitFastEpilogue1() -> void; - def emitFastEpilogue2() -> void; def emitOsrEntry(osr_entry_label: MasmLabel, state: Array) { if (Trace.compiler) Trace.OUT.put1(" OSR (+%d)", osr_entry_label.create_pos).ln(); masm.bindLabel(osr_entry_label); @@ -3605,3 +3605,9 @@ type WhammInlineConfig(swap_membase: bool, swap_instance: bool, is_inlined: bool // The SPC emits a stub at {stub_label} for each handler in the function. The stub restores the // expected state of the environment, then jumps to {dest_label} to continue execution at handler. type SpcHandlerInfo(is_dummy: bool, func_end: bool, dest_label: MasmLabel, stub_label: MasmLabel, merge_state: Array); + +def uleb_size(v: int) -> int { + var n = 1, data = u32.view(v); + while (data >= 0x80) { data = data >> 7; n++; } + return n; +} diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 634b13691..75f4651f1 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -3,11 +3,6 @@ // XXX: reduce duplication with MacroAssembler def G = X86_64MasmRegs.toGpr, X = X86_64MasmRegs.toXmmr; -def u32leb_size(v: int) -> int { - var n = 1, data = u32.view(v); - while (data >= 0x80) { data = data >> 7; n++; } - return n; -} def R: X86_64Regs; def C: X86_64Conds; def A(ma: MasmAddr) -> X86_64Addr { @@ -52,19 +47,6 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } - def emitFastPrologue() { - // Advance r_ip past the ULEB32 operand (original CALL function index) - asm.add_r_i(G(X86_64MasmRegs.INT_EXEC_ENV.ip), u32leb_size(func.func_index)); - // Compute VFP = VSP - sig.params.length * SLOT_SIZE (no native stack frame needed) - masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); - masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); - } - def emitFastEpilogue1() { - } - def emitFastEpilogue2() { - // Restore VFP from interpreter frame (always in sync; no fast frame was allocated) - masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); - } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { var b = pop(), a = popReg(); From b8a1636741cc2d8a8973b038d3e3e5fe20c68e2e Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 2 Apr 2026 12:10:17 -0400 Subject: [PATCH 21/91] Remove unused stubs and deps --- src/engine/x86-64/X86_64MacroAssembler.v3 | 28 ---- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 149 ------------------ 2 files changed, 177 deletions(-) diff --git a/src/engine/x86-64/X86_64MacroAssembler.v3 b/src/engine/x86-64/X86_64MacroAssembler.v3 index ad7b1d891..8e1753b61 100644 --- a/src/engine/x86-64/X86_64MacroAssembler.v3 +++ b/src/engine/x86-64/X86_64MacroAssembler.v3 @@ -47,34 +47,6 @@ class X86_64MacroAssembler extends MacroAssembler { } } - def saveIVar(r: X86_64Gpr, ivars: Array<(X86_64Gpr, X86_64Addr)>) { - for (t in ivars) { - if (t.0 == r) asm.movq_m_r(t.1, r); - } - } - def saveCallerIVars(r_ip: X86_64Gpr, r_stp: X86_64Gpr, r_curpc: X86_64Gpr, - ivars: Array<(X86_64Gpr, X86_64Addr)>) { - saveIVar(r_ip, ivars); - saveIVar(r_stp, ivars); - if (!FeatureDisable.stacktraces) saveIVar(r_curpc, ivars); - } - def restoreReg(r: X86_64Gpr, ivars: Array<(X86_64Gpr, X86_64Addr)>) { - for (t in ivars) { - if (t.0 == r) asm.movq_r_m(r, t.1); - } - } - def restoreCallerIVars(r_ip: X86_64Gpr, r_stp: X86_64Gpr, r_eip: X86_64Gpr, - r_instance: X86_64Gpr, r_func_decl: X86_64Gpr, r_mem0_base: X86_64Gpr, r_vfp: X86_64Gpr, - ivars: Array<(X86_64Gpr, X86_64Addr)>) { - restoreReg(r_ip, ivars); - restoreReg(r_stp, ivars); - restoreReg(r_eip, ivars); - restoreReg(r_instance, ivars); - restoreReg(r_func_decl, ivars); - restoreReg(r_mem0_base, ivars); - restoreReg(r_vfp, ivars); - } - // Label operations def newLabel(create_pos: int) -> X86_64MasmLabel { return X86_64MasmLabel.new(create_pos, asm.newLabel()); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 75f4651f1..22f61280e 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -1428,8 +1428,6 @@ class X86_64SpcCompileStub extends RiUserCode { def V3_SPC_ENTRY_FUNC = X86_64PreGenFunc<(WasmFunction, Pointer, Pointer), Throwable>.new("v3-spc-entry", null, genSpcEntryFunc); def LAZY_COMPILE_STUB = X86_64PreGenStub.new("spc-lazy-compile", X86_64SpcCompileStub.new("lazy"), genLazyCompileStub); -def FAST_COMPILE_STUB = X86_64PreGenStub.new("spc-fast-compile", X86_64SpcCompileStub.new("fast"), genFastCompileStub); -def FAST_CALL_NOP = X86_64PreGenStub.new("spc-fast-nop", X86_64SpcCompileStub.new("fast"), genFastNopStub); def TIERUP_COMPILE_STUB = X86_64PreGenStub.new("spc-tierup-compile", X86_64SpcCompileStub.new("tierup"), genTierUpCompileStub); def TRAPS_STUB = X86_64SpcTrapsStub.new(); def TRAPS_PREGEN = X86_64PreGenStub.new("spc-trap", TRAPS_STUB, genTrapsStub); @@ -1485,141 +1483,6 @@ def genLazyCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { asm.movq_r_r(G(Target.V3_RET_GPRS[0]), G(Target.V3_RET_GPRS[2])); asm.ret(); } -/* This stub should: - * - save program state (i.e. an epilogue as if it was a call/new frame) - * - compile the function (given register constraints imposed by fast int) - * - rewrite the `fast_target_code` field with this new function - * - restore program state - * - jump into the new `fast_target_code` (or re-dispatch on itself) - */ -def genFastCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { - if (SpcTuning.disable) return; - var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); - var asm = X86_64Assembler.!(masm.asm); - var regs = X86_64MasmRegs.SPC_EXEC_ENV; - var func_arg = G(regs.func_arg); - - var xenv = X86_64MasmRegs.INT_EXEC_ENV; - - // TODO ensure that register use is compatible with fast-int usage - def r_mem0_base = G(xenv.mem0_base); - def r_vfp = G(xenv.vfp); - def r_vsp = G(xenv.vsp); - def r_stp = G(xenv.stp); - def r_ip = G(xenv.ip); - def r_eip = G(xenv.eip); - def r_func_decl = G(xenv.func_decl); - def r_instance = G(xenv.instance); - def r_curpc = G(xenv.curpc); - - def m_mem0_base = R.RSP.plus(X86_64InterpreterFrame.mem0_base.offset); - def m_vfp = R.RSP.plus(X86_64InterpreterFrame.vfp.offset); - def m_vsp = R.RSP.plus(X86_64InterpreterFrame.vsp.offset); - def m_stp = R.RSP.plus(X86_64InterpreterFrame.stp.offset); - def m_ip = R.RSP.plus(X86_64InterpreterFrame.ip.offset); - def m_eip = R.RSP.plus(X86_64InterpreterFrame.eip.offset); - def m_func_decl = R.RSP.plus(X86_64InterpreterFrame.func_decl.offset); - def m_instance = R.RSP.plus(X86_64InterpreterFrame.instance.offset); - def m_curpc = R.RSP.plus(X86_64InterpreterFrame.curpc.offset); - - def ivar_MEM0_BASE = (r_mem0_base, m_mem0_base); - def ivar_VFP = (r_vfp, m_vfp); - def ivar_VSP = (r_vsp, m_vsp); - def ivar_STP = (r_stp, m_stp); - def ivar_IP = (r_ip, m_ip); - def ivar_EIP = (r_eip, m_eip); - def ivar_FUNC_DECL = (r_func_decl, m_func_decl); - def ivar_INSTANCE = (r_instance, m_instance); - def ivar_CURPC = (r_curpc, m_curpc); - - def all_ivars = [ - ivar_MEM0_BASE, - ivar_VFP, - ivar_VSP, - ivar_STP, - ivar_IP, - ivar_EIP, - ivar_FUNC_DECL, - ivar_INSTANCE, - ivar_CURPC - ]; - - masm.emit_debugger_breakpoint(); - //for (i < all_ivars.length) { - // asm.pushq_r(all_ivars[i].0); - //} - masm.saveCallerIVars(r_ip, r_stp, r_curpc, all_ivars); - asm.pushq_r(G(regs.func_arg)); // push function onto stack - // saveCallerIVars (move to macro assembler) - // look at runtime calls in int, and int->spc calls - masm.emit_store_curstack_vsp(regs.vsp); - masm.emit_debugger_breakpoint(); - - asm.movq_r_r(G(Target.V3_PARAM_GPRS[1]), G(regs.func_arg)); // function (rdx) - asm.movq_r_i(G(Target.V3_PARAM_GPRS[2]), int.!(Pointer.atObject(ic) - Pointer.NULL)); // load into rdx - // dispatch is in r14 (don't overwrite, just access directly) - // Load {null} for the receiver. - asm.movq_r_i(G(Target.V3_PARAM_GPRS[0]), 0); - // Call {X86_64Spc.fastCompile} directly. - //masm.emit_debugger_breakpoint(); - masm.emit_call_abs(codePointer(X86_64Spc.fastCompile)); - masm.emit_debugger_breakpoint(); - asm.q.add_r_i(R.RSP, Pointer.SIZE); // pop function off stack - // Check for non-null abrupt return. - var unwind = X86_64Label.new(); - asm.q.cmp_r_i(G(Target.V3_RET_GPRS[2]), 0); - asm.jc_rel_near(C.NZ, unwind); - // Tail-call the result of the compile. - var scratch = X86_64Regs.R9; - asm.movq_r_r(scratch, G(Target.V3_RET_GPRS[1])); // entrypoint - asm.movq_r_r(G(regs.func_arg), G(Target.V3_RET_GPRS[0])); // function - - //for (i < all_ivars.length) { - // asm.popq_r(all_ivars[all_ivars.length - i - 1].0); - //} - masm.restoreCallerIVars(r_ip, r_stp, r_eip, r_instance, r_func_decl, r_mem0_base, r_vfp, all_ivars); - masm.emit_load_curstack_vsp(regs.vsp); - - masm.emit_debugger_breakpoint(); - asm.ijmp_r(scratch); // jump to entrypoint - - asm.invalid(); - asm.ret(); - - // Simply return the {Throwable} object. ?? - asm.bind(unwind); - asm.movq_r_r(G(Target.V3_RET_GPRS[0]), G(Target.V3_RET_GPRS[2])); - asm.ret(); -} -def genFastNopStub(ic: X86_64InterpreterCode, w: DataWriter) { - if (SpcTuning.disable) return; - var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); - var asm = X86_64Assembler.!(masm.asm); - var regs = X86_64MasmRegs.SPC_EXEC_ENV; - var func_arg = G(regs.func_arg); - - def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; - def r_ip = G(xenv.ip); - def r_dispatch = G(xenv.dispatch); - def r_tmp0 = G(xenv.tmp0); // RCX - def r_tmp1 = G(xenv.tmp1); // RDX - def ip_ptr = r_ip.plus(0); - - // simplified dispatch sequence - - var opcode = r_tmp0; - var base = r_tmp1; - - asm.movbzx_r_m(opcode, ip_ptr); - asm.inc_r(r_ip); - - // flattened 4 case - var addr = ic.start + ic.header.fastDispatchTableOffset; - asm.movd_r_m(base, X86_64Addr.new(null, opcode, 4, int.!(addr - Pointer.NULL))); - asm.ijmp_r(base); - - asm.invalid(); -} def genTierUpCompileStub(ic: X86_64InterpreterCode, w: DataWriter) { if (SpcTuning.disable) return; var masm = X86_64MacroAssembler.new(w, X86_64MasmRegs.CONFIG); @@ -1689,10 +1552,6 @@ component X86_64Spc { def invoke(wf: WasmFunction, sp: Pointer) -> Throwable { return V3_SPC_ENTRY_FUNC.get()(wf, sp, wf.decl.target_code.spc_entry); } - def setFastCompileFor(module: Module, decl: FuncDecl) { - if (Debug.runtime) Trace.OUT.put1("setFastCompile %q", decl.render(module.names, _)).ln(); - decl.fast_target_code = TargetCode(FAST_COMPILE_STUB.getEntry()); - } def setLazyCompileFor(module: Module, decl: FuncDecl) { if (Debug.runtime) Trace.OUT.put1("setLazyCompile %q", decl.render(module.names, _)).ln(); decl.target_code = TargetCode(LAZY_COMPILE_STUB.getEntry()); @@ -1717,14 +1576,6 @@ component X86_64Spc { var result = X86_64SpcStrategy.!(Execute.tiering).lazyCompile(wf); return (result.wf, result.entrypoint, result.thrown); } - private def fastCompile(wf: WasmFunction, ic: X86_64InterpreterCode) -> (WasmFunction, Pointer, Throwable) { - // The global stub simply consults the execution strategy. - var result = X86_64ExecutionStrategy.!(Execute.tiering).fastCompile(wf, ic); // no condition that tiering uses SPC (int => fast SPC) - return (result.wf, result.entrypoint, result.thrown); - // need to compute _a_ new vfp - // bump the stack pointer? - // goal: avoid having to make new frame entirely - } private def tierupCompile(wf: WasmFunction) -> (WasmFunction, Pointer, Throwable) { // The global stub simply consults the execution strategy. var result = X86_64SpcStrategy.!(Execute.tiering).tierupCompile(wf); From b48b03a0cd4c4e703584c75c241c672d5192bde9 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 2 Apr 2026 12:22:34 -0400 Subject: [PATCH 22/91] Build fast SPC exec env at the same time as other exec envs, remove dup --- src/engine/compiler/SinglePassCompiler.v3 | 33 ------------ src/engine/x86-64/X86_64MasmRegs.v3 | 64 +++++++++++------------ 2 files changed, 32 insertions(+), 65 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 5f8845ba5..46acb354c 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -31,39 +31,6 @@ class SpcExecEnv { var runtime_ret1: Reg; var ret_throw: Reg; var scratch: Reg; - - def dup() -> SpcExecEnv { - def env = SpcExecEnv.new(); - - env.frameSize = this.frameSize; - env.vsp_slot = this.vsp_slot; - env.vfp_slot = this.vfp_slot; - env.pc_slot = this.pc_slot; - env.instance_slot = this.instance_slot; - env.inlined_instance_slot = this.inlined_instance_slot; - env.wasm_func_slot = this.wasm_func_slot; - env.mem0_base_slot = this.mem0_base_slot; - env.inlined_mem0_base_slot = this.inlined_mem0_base_slot; - env.accessor_slot = this.accessor_slot; - - env.sp = this.sp; - env.func_arg = this.func_arg; - env.vsp = this.vsp; - env.vfp = this.vfp; - env.mem0_base = this.mem0_base; - env.instance = this.instance; - env.runtime_arg0 = this.runtime_arg0; - env.runtime_arg1 = this.runtime_arg1; - env.runtime_arg2 = this.runtime_arg2; - env.runtime_arg3 = this.runtime_arg3; - env.runtime_arg4 = this.runtime_arg4; - env.runtime_ret0 = this.runtime_ret0; - env.runtime_ret1 = this.runtime_ret1; - env.ret_throw = this.ret_throw; - env.scratch = this.scratch; - - return env; - } } def INITIAL_VALUE_STACK_SIZE = 16; diff --git a/src/engine/x86-64/X86_64MasmRegs.v3 b/src/engine/x86-64/X86_64MasmRegs.v3 index d1fe06a79..73af95b67 100644 --- a/src/engine/x86-64/X86_64MasmRegs.v3 +++ b/src/engine/x86-64/X86_64MasmRegs.v3 @@ -88,26 +88,27 @@ component X86_64MasmRegs { return config; })(); - // Build both the SPC and INT execution environments together. - private def t = (fun -> (SpcExecEnv, IntExecEnv) { + // Build the SPC, fast-SPC, and INT execution environments together. + private def t = (fun -> (SpcExecEnv, SpcExecEnv, IntExecEnv) { var xspc = SpcExecEnv.new(); + var xfast = SpcExecEnv.new(); var xint = IntExecEnv.new(); - xint.sp = xspc.sp = RSP; - xint.func_arg = xspc.func_arg = RDX; // cache of frame (callee-restore) - xint.vsp = xspc.vsp = RSI; - xint.vfp = xspc.vfp = R11; - xint.mem0_base = xspc.mem0_base = R10; // cache of frame (callee-restore) - xint.instance = xspc.instance = RDI; // cache of frame (callee-restore) - xint.runtime_arg0 = xspc.runtime_arg0 = RSI; - xint.runtime_arg1 = xspc.runtime_arg1 = RDX; - xint.runtime_arg2 = xspc.runtime_arg2 = RCX; - xint.runtime_arg3 = xspc.runtime_arg3 = R8; - xint.runtime_arg4 = xspc.runtime_arg4 = R9; - xint.ret_throw = xspc.ret_throw = RAX; - xint.runtime_ret0 = xspc.runtime_ret0 = RAX; - xint.runtime_ret1 = xspc.runtime_ret1 = RDX; - xint.scratch = xspc.scratch = RBP; + xint.sp = xspc.sp = xfast.sp = RSP; + xint.func_arg = xspc.func_arg = xfast.func_arg = RDX; // cache of frame (callee-restore) + xint.vsp = xspc.vsp = xfast.vsp = RSI; + xint.vfp = xspc.vfp = xfast.vfp = R11; + xint.mem0_base = xspc.mem0_base = xfast.mem0_base = R10; // cache of frame (callee-restore) + xint.instance = xspc.instance = xfast.instance = RDI; // cache of frame (callee-restore) + xint.runtime_arg0 = xspc.runtime_arg0 = xfast.runtime_arg0 = RSI; + xint.runtime_arg1 = xspc.runtime_arg1 = xfast.runtime_arg1 = RDX; + xint.runtime_arg2 = xspc.runtime_arg2 = xfast.runtime_arg2 = RCX; + xint.runtime_arg3 = xspc.runtime_arg3 = xfast.runtime_arg3 = R8; + xint.runtime_arg4 = xspc.runtime_arg4 = xfast.runtime_arg4 = R9; + xint.ret_throw = xspc.ret_throw = xfast.ret_throw = RAX; + xint.runtime_ret0 = xspc.runtime_ret0 = xfast.runtime_ret0 = RAX; + xint.runtime_ret1 = xspc.runtime_ret1 = xfast.runtime_ret1 = RDX; + xint.scratch = xspc.scratch = xfast.scratch = RBP; xint.curpc = R15; xint.stp = RBX; @@ -127,31 +128,32 @@ component X86_64MasmRegs { def m = MasmAddr(xspc.sp, _); - xint.accessor_slot = xspc.accessor_slot = m(X86_64InterpreterFrame.accessor.offset); - xint.instance_slot = xspc.instance_slot = m(X86_64InterpreterFrame.instance.offset); - xint.mem0_base_slot = xspc.mem0_base_slot = m(X86_64InterpreterFrame.mem0_base.offset); - xint.pc_slot = xspc.pc_slot = m(X86_64InterpreterFrame.curpc.offset); - xint.vfp_slot = xspc.vfp_slot = m(X86_64InterpreterFrame.vfp.offset); - xint.vsp_slot = xspc.vsp_slot = m(X86_64InterpreterFrame.vsp.offset); - xint.wasm_func_slot = xspc.wasm_func_slot = m(X86_64InterpreterFrame.wasm_func.offset); - xint.ip_slot = xspc.inlined_mem0_base_slot = m(X86_64InterpreterFrame.ip.offset); - xint.stp_slot = xspc.inlined_instance_slot = m(X86_64InterpreterFrame.stp.offset); + xint.accessor_slot = xspc.accessor_slot = xfast.accessor_slot = m(X86_64InterpreterFrame.accessor.offset); + xint.instance_slot = xspc.instance_slot = xfast.instance_slot = m(X86_64InterpreterFrame.instance.offset); + xint.mem0_base_slot = xspc.mem0_base_slot = xfast.mem0_base_slot = m(X86_64InterpreterFrame.mem0_base.offset); + xint.pc_slot = xspc.pc_slot = xfast.pc_slot = m(X86_64InterpreterFrame.curpc.offset); + xint.vfp_slot = xspc.vfp_slot = xfast.vfp_slot = m(X86_64InterpreterFrame.vfp.offset); + xint.vsp_slot = xspc.vsp_slot = xfast.vsp_slot = m(X86_64InterpreterFrame.vsp.offset); + xint.wasm_func_slot = xspc.wasm_func_slot = xfast.wasm_func_slot = m(X86_64InterpreterFrame.wasm_func.offset); + xint.ip_slot = xspc.inlined_mem0_base_slot = xfast.inlined_mem0_base_slot = m(X86_64InterpreterFrame.ip.offset); + xint.stp_slot = xspc.inlined_instance_slot = xfast.inlined_instance_slot = m(X86_64InterpreterFrame.stp.offset); xint.func_decl_slot = m(X86_64InterpreterFrame.func_decl.offset); xint.code_slot = m(X86_64InterpreterFrame.code.offset); xint.eip_slot = m(X86_64InterpreterFrame.eip.offset); xint.frameSize = xspc.frameSize = X86_64InterpreterFrame.size; + xfast.frameSize = 0; - return (xspc, xint); + return (xspc, xfast, xint); })(); // The execution environment for single-pass compilation contexts. def SPC_EXEC_ENV = t.0; + // The execution environment for fast single-pass compilation contexts. + def FAST_SPC_EXEC_ENV = t.1; // The execution environment for interpreter compilation contexts. - def INT_EXEC_ENV = t.1; - - def FAST_SPC_EXEC_ENV = SPC_EXEC_ENV.dup(); + def INT_EXEC_ENV = t.2; // A register allocator for single-pass compilation contexts. def SPC_ALLOC = (fun -> RegAlloc { @@ -193,5 +195,3 @@ component X86_64MasmRegs { } } -def nothing = X86_64MasmRegs.FAST_SPC_EXEC_ENV.frameSize = 0; -def nothing2 = X86_64MasmRegs.FAST_SPC_EXEC_ENV.vfp_slot = MasmAddr(X86_64MasmRegs.FAST_SPC_EXEC_ENV.sp, X86_64InterpreterFrame.vfp.offset); From f11a1144a78194b17ceedd6a3a307c23fab6278f Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 2 Apr 2026 18:59:52 -0400 Subject: [PATCH 23/91] save/restore caller IVars in SPC and across frame reconstruction --- src/engine/compiler/SinglePassCompiler.v3 | 20 ++++- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 82 +++++++++++++++++-- 2 files changed, 91 insertions(+), 11 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 46acb354c..b4a3f6e6d 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -2225,13 +2225,22 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl return label; } def getSpcInlinedFrameIp() -> long; + def saveCallerIVars(); + def restoreDispatchTableReg(); + def restoreCallerIVars(); // Emit code to materialize stack frames for each inlined function. def emitReconstructStackFrames(frames: Array) -> int { Metrics.spc_static_reconst.val++; masm.emit_inc_metric(Metrics.spc_dynamic_reconst); - def real_frame = frames[0]; - masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); + if (fast) { + // pc already saved + saveCallerIVars(); + } else { + def real_frame = frames[0]; + masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); + } + // NOTE we could use interpreter-backed registers for these instead of allocating new regs // load instance var inst_reg = allocTmp(ValueKind.REF); masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); @@ -2246,7 +2255,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var wasm_func_reg = allocTmp(ValueKind.REF); var inl_inst_reg: Reg, inl_mem0_reg: Reg; - if (whamm_config.is_inlined) { // XXX check individual configs? + if (whamm_config.is_inlined) { // TODO investigate, check individual configs? inl_inst_reg = allocTmp(ValueKind.REF); inl_mem0_reg = allocTmp(ValueKind.REF); masm.emit_mov_r_m(ValueKind.REF, inl_inst_reg, frame.inlined_instance_slot); @@ -2337,11 +2346,14 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (space > 0) { masm.emit_addw_r_i(regs.sp, space); masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); + if (fast) { + restoreCallerIVars(); + restoreDispatchTableReg(); + } } } else { emit(); } - } def unsupported() { success = false; // XXX: add opcode diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 22f61280e..058c8273d 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -23,6 +23,54 @@ def KIND_F64 = SpcConsts.KIND_F64; def KIND_V128 = SpcConsts.KIND_V128; def KIND_REF = SpcConsts.KIND_REF; +def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; + +def r_mem0_base = G(xenv.mem0_base); +def r_vfp = G(xenv.vfp); +def r_vsp = G(xenv.vsp); +def r_stp = G(xenv.stp); +def r_ip = G(xenv.ip); +def r_eip = G(xenv.eip); +def r_func_decl = G(xenv.func_decl); +def r_instance = G(xenv.instance); +def r_curpc = G(xenv.curpc); +def ip_ptr = r_ip.plus(0); +def r_dispatch = G(xenv.dispatch); +def r_tmp0 = G(xenv.tmp0); // RCX +def r_tmp1 = G(xenv.tmp1); // RDX + +def m_mem0_base = R.RSP.plus(X86_64InterpreterFrame.mem0_base.offset); +def m_vfp = R.RSP.plus(X86_64InterpreterFrame.vfp.offset); +def m_vsp = R.RSP.plus(X86_64InterpreterFrame.vsp.offset); +def m_stp = R.RSP.plus(X86_64InterpreterFrame.stp.offset); +def m_ip = R.RSP.plus(X86_64InterpreterFrame.ip.offset); +def m_eip = R.RSP.plus(X86_64InterpreterFrame.eip.offset); +def m_func_decl = R.RSP.plus(X86_64InterpreterFrame.func_decl.offset); +def m_instance = R.RSP.plus(X86_64InterpreterFrame.instance.offset); +def m_curpc = R.RSP.plus(X86_64InterpreterFrame.curpc.offset); + +def ivar_MEM0_BASE = (r_mem0_base, m_mem0_base); +def ivar_VFP = (r_vfp, m_vfp); +def ivar_VSP = (r_vsp, m_vsp); +def ivar_STP = (r_stp, m_stp); +def ivar_IP = (r_ip, m_ip); +def ivar_EIP = (r_eip, m_eip); +def ivar_FUNC_DECL = (r_func_decl, m_func_decl); +def ivar_INSTANCE = (r_instance, m_instance); +def ivar_CURPC = (r_curpc, m_curpc); + +def all_ivars = [ + ivar_MEM0_BASE, + ivar_VFP, + ivar_VSP, + ivar_STP, + ivar_IP, + ivar_EIP, + ivar_FUNC_DECL, + ivar_INSTANCE, + ivar_CURPC +]; + // Implements the target-specific parts of the single-pass compiler for X86-64. class X86_64SinglePassCompiler extends SinglePassCompiler { def w = DataWriter.new(); @@ -37,16 +85,36 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.trap_stubs = TRAPS_STUB; } def emitFastDispatch() { - // DISPATCH - def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; - def r_ip = G(xenv.ip); - def ip_ptr = r_ip.plus(0); - def r_dispatch = G(xenv.dispatch); - def r_tmp0 = G(xenv.tmp0); // RCX - def r_tmp1 = G(xenv.tmp1); // RDX mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } + private def saveIVar(r: X86_64Gpr) { + for (t in all_ivars) { + if (t.0 == r) asm.movq_m_r(t.1, r); + } + } + def saveCallerIVars() { + saveIVar(r_ip); + saveIVar(r_stp); + if (!FeatureDisable.stacktraces) saveIVar(r_curpc); + } + def restoreCurPcFromFrame() { + if (!FeatureDisable.stacktraces) restoreReg(r_curpc); + } + private def restoreReg(r: X86_64Gpr) { + for (t in all_ivars) { + if (t.0 == r) asm.movq_r_m(r, t.1); + } + } + def restoreCallerIVars() { + restoreReg(r_ip); + restoreReg(r_stp); + restoreReg(r_eip); + restoreReg(r_instance); + restoreReg(r_func_decl); + restoreReg(r_mem0_base); + restoreReg(r_vfp); + } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { var b = pop(), a = popReg(); From 4643990d48a91d69c1f24325c99d5a5b95771d76 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 2 Apr 2026 21:26:28 -0400 Subject: [PATCH 24/91] Complete stack reconstruction around fast compilation --- src/engine/Debug.v3 | 6 ++-- src/engine/compiler/SinglePassCompiler.v3 | 28 ++++++++++++++----- src/engine/x86-64/X86_64Frames.v3 | 6 ---- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 8 ++++-- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/engine/Debug.v3 b/src/engine/Debug.v3 index 55a445978..29b91af78 100644 --- a/src/engine/Debug.v3 +++ b/src/engine/Debug.v3 @@ -6,9 +6,9 @@ component Debug { // Debug tracing options. def paranoid = false; def verbose = false; - def interpreter = true; - def runtime = true; - def compiler = true; + def interpreter = false; + def runtime = false; + def compiler = false; def pregen = false; def stack = false; def memory = false; diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index b4a3f6e6d..f93c0b71a 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -78,6 +78,10 @@ def KIND_REF = SpcConsts.KIND_REF; def KIND_REF_U64 = SpcConsts.KIND_REF_U64; def KIND_CONT = SpcConsts.KIND_CONT; +// Unlike frame.frameSize, where it is 0 for fast contexts. These are always the +// true frame size (for stack reconstruction methods). +def FRAME_SIZE = X86_64InterpreterFrame.size; + // Compiles Wasm bytecode to machine code in a single pass via a MacroAssembler. class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAlloc, extensions: Extension.set, limits: Limits, fast: bool) extends BytecodeVisitor { def instrTracer = if(Trace.compiler, InstrTracer.new()); @@ -168,6 +172,11 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Push initial frame for top-level function state.frame_stack.clear(); + if (fast) { + // push a SpcFrame representing the interpreter frame already on the stack + var interp_frame = SpcFrame.new(null, module, 0, 0, 0, -1, null); + pushSpcFrame(interp_frame); + } var initial_frame = SpcFrame.new(func, module, 0, 0, func.num_slots(), 0, masm.newLabel(func.cur_bytecode.length)); pushSpcFrame(initial_frame); @@ -771,7 +780,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl setUnreachable(); } def visit_END() { - if (!isInlined()) { + if (needsEpilogue()) { var ctl_top = state.ctl_stack.peek(); if (ctl_top.opcode == Opcode.LOOP.code) { state.ctl_stack.pop(); @@ -2179,7 +2188,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } } - if (isInlined()) return; + if (!needsEpilogue()) return; // Compute VSP = VFP + state.sp emit_compute_vsp(regs.vsp, state.sp); @@ -2263,7 +2272,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } // Pre-allocate stack space for all reconstructed frames at once. - def total_space = (frames.length - 1) * (frame.frameSize + 8); + def total_space = (frames.length - 1) * (FRAME_SIZE + 8); masm.emit_subw_r_i(regs.sp, total_space); // Process the inlined frames (skip the outermost which already exists on native stack) @@ -2283,9 +2292,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Use inlined frame stub IP as return address for all reconstructed frames def return_addr = getSpcInlinedFrameIp(); - def frame_offset = offset * (frame.frameSize + 8); + def frame_offset = offset * (FRAME_SIZE + 8); // Write inlined frame stub IP as return address - def retaddr_slot = MasmAddr(regs.sp, frame_offset + frame.frameSize); + def retaddr_slot = MasmAddr(regs.sp, frame_offset + FRAME_SIZE); masm.emit_mov_m_l(retaddr_slot, return_addr); // get functions[func_index] and save into frame @@ -2340,6 +2349,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } unrefRegs(); frames_reconstructed = true; + if (Trace.compiler) Trace.OUT.puts("performing frame reconstruction\n"); def space = emitReconstructStackFrames(snapshotFrames()); emit(); frames_reconstructed = false; @@ -2791,10 +2801,10 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } state.frame_stack.push(frame); // Update cached copies from new top frame - it.reset(frame.func).at(frame.pc, -1); + if (frame.func != null) it.reset(frame.func).at(frame.pc, -1); module = frame.module; func = frame.func; - sig = func.sig; + sig = if(func != null, func.sig); num_locals = frame.num_locals; local_base_sp = frame.local_base_sp; ctl_base_sp = frame.ctl_base_sp; @@ -2820,6 +2830,10 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def isInlined() -> bool { return state.frame_stack.top > 1; } + def needsEpilogue() -> bool { + // inlined callees will fallthrough and don't need epilogue to be emitted + return !isInlined() || ctl_base_sp == 0; + } def inlineDepth() -> int { return state.frame_stack.top - 1; } diff --git a/src/engine/x86-64/X86_64Frames.v3 b/src/engine/x86-64/X86_64Frames.v3 index bf880f247..6c68543ec 100644 --- a/src/engine/x86-64/X86_64Frames.v3 +++ b/src/engine/x86-64/X86_64Frames.v3 @@ -21,12 +21,6 @@ layout X86_64InterpreterFrame { =104; } -// XXX: this frame may be differently sized depending on other touched registers -layout X86_64InterpreterFastCallFrame { - +0 vfp : i64; // Pointer - =8; -} - // Layout of an SPC frame. Same 104-byte footprint as {X86_64InterpreterFrame}. // Slots used by the interpreter but not by SPC are omitted. layout X86_64SpcFrame { diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 058c8273d..7978058f5 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -98,8 +98,12 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { saveIVar(r_stp); if (!FeatureDisable.stacktraces) saveIVar(r_curpc); } - def restoreCurPcFromFrame() { - if (!FeatureDisable.stacktraces) restoreReg(r_curpc); + def restoreDispatchTableReg() { + if (!FeatureDisable.globalProbes) { + // restore dispatch table from Interpreter.dispatchTable + def offsets = masm.getOffsets(); + asm.movq_r_m(r_dispatch, mmasm.absPointer(offsets.Interpreter_dispatchTable)); + } } private def restoreReg(r: X86_64Gpr) { for (t in all_ivars) { From 16ab7ba97dbfbbab75cf5ac3af423a86e5231e06 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 2 Apr 2026 21:42:27 -0400 Subject: [PATCH 25/91] Remove FAST_CALL47 and opcode mapped to 0xFF --- src/engine/BytecodeIterator.v3 | 1 - src/engine/CodeValidator.v3 | 1 - src/engine/Opcodes.v3 | 11 +++++------ src/engine/v3/V3Interpreter.v3 | 4 ++-- src/engine/x86-64/X86_64Interpreter.v3 | 1 - 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/engine/BytecodeIterator.v3 b/src/engine/BytecodeIterator.v3 index 1a1c9845f..6048b21e6 100644 --- a/src/engine/BytecodeIterator.v3 +++ b/src/engine/BytecodeIterator.v3 @@ -833,7 +833,6 @@ class BytecodeIterator { FAST_CALL44 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); FAST_CALL45 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); FAST_CALL46 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); - FAST_CALL47 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); } } def trace(out: StringBuilder, module: Module, tracer: InstrTracer) { diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index 0815a7714..a40970cab 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -509,7 +509,6 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e FAST_CALL44 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); FAST_CALL45 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); FAST_CALL46 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL47 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); CALL_INDIRECT => { var sig = parser.readSigRef(); var table = parser.readTableRef(); diff --git a/src/engine/Opcodes.v3 b/src/engine/Opcodes.v3 index 0998599ea..ccb857342 100644 --- a/src/engine/Opcodes.v3 +++ b/src/engine/Opcodes.v3 @@ -657,8 +657,7 @@ enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: FAST_CALL43 (0x00, 0xF8, "fast_call43", imm.NONE, null), FAST_CALL44 (0x00, 0xF9, "fast_call44", imm.NONE, null), FAST_CALL45 (0x00, 0xFA, "fast_call45", imm.NONE, null), - FAST_CALL46 (0x00, 0xFF, "fast_call46", imm.NONE, null), - FAST_CALL47 (0x00, 0x17, "fast_call47", imm.FUNC, null) + FAST_CALL46 (0x00, 0x17, "fast_call46", imm.FUNC, null) } @@ -849,12 +848,14 @@ component Opcodes { def code_pages = [page_FB, page_FC, page_FD, page_FE]; def var longestName: int; def var num_subpages: int; + def FAST_CALL_OPCODES = 47; def var fast_calls: Array; private var nameMap: HashMap; new() { - fast_calls = Array.new(48); - for (i < 48) { + + fast_calls = Array.new(FAST_CALL_OPCODES); + for (i < FAST_CALL_OPCODES) { fast_calls[i] = indexToFastCall(i); } for (op in Opcode) { @@ -1228,7 +1229,6 @@ component Opcodes { 44 => op = Opcode.FAST_CALL44; 45 => op = Opcode.FAST_CALL45; 46 => op = Opcode.FAST_CALL46; - 47 => op = Opcode.FAST_CALL47; _ => System.error("indexToFastCall", "out of range"); } return op; @@ -1283,7 +1283,6 @@ component Opcodes { FAST_CALL44 => idx = 44; FAST_CALL45 => idx = 45; FAST_CALL46 => idx = 46; - FAST_CALL47 => idx = 47; _ => System.error("fastCallToIndex", "not a FAST_CALL instruction"); } return idx; diff --git a/src/engine/v3/V3Interpreter.v3 b/src/engine/v3/V3Interpreter.v3 index 2dd1728c2..669b80bbe 100644 --- a/src/engine/v3/V3Interpreter.v3 +++ b/src/engine/v3/V3Interpreter.v3 @@ -371,7 +371,7 @@ class V3Interpreter extends WasmStack { RETURN => { doReturn(frame.fp, frame.func.sig); } - CALL, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39, FAST_CALL40, FAST_CALL41, FAST_CALL42, FAST_CALL43, FAST_CALL44, FAST_CALL45, FAST_CALL46, FAST_CALL47 => { + CALL, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39, FAST_CALL40, FAST_CALL41, FAST_CALL42, FAST_CALL43, FAST_CALL44, FAST_CALL45, FAST_CALL46 => { var func_index = codeptr.read_uleb32(); var f = frame.func.instance.functions[func_index]; return doCallFunction(f); @@ -1640,7 +1640,7 @@ class V3Interpreter extends WasmStack { // XXX: use read_opcode_and_skip() var opcode = codeptr.read_opcode_but_skip_probe(frame.func.decl); match (opcode) { - CALL, CALL_REF, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39, FAST_CALL40, FAST_CALL41, FAST_CALL42, FAST_CALL43, FAST_CALL44, FAST_CALL45, FAST_CALL46, FAST_CALL47 => { + CALL, CALL_REF, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39, FAST_CALL40, FAST_CALL41, FAST_CALL42, FAST_CALL43, FAST_CALL44, FAST_CALL45, FAST_CALL46 => { codeptr.skip_leb(); frame.pc = codeptr.pos; } diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index 736eb37a7..68e44162b 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -1372,7 +1372,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { bindHandler(Opcode.FAST_CALL44); bindHandler(Opcode.FAST_CALL45); bindHandler(Opcode.FAST_CALL46); - bindHandler(Opcode.FAST_CALL47); masm.emit_intentional_crash(); //masm.emit_debugger_breakpoint(); var dispatchLabel = X86_64Label.new(); From 66c34c77f6ddc72ea5a10aecfbb837ac30deca3d Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 2 Apr 2026 21:55:19 -0400 Subject: [PATCH 26/91] Remove more FAST_CALLs contradicting stack switching --- src/engine/BytecodeIterator.v3 | 7 -- src/engine/CodeValidator.v3 | 9 --- src/engine/Opcodes.v3 | 103 ++++++++++--------------- src/engine/v3/V3Interpreter.v3 | 4 +- src/engine/x86-64/X86_64Interpreter.v3 | 7 -- 5 files changed, 43 insertions(+), 87 deletions(-) diff --git a/src/engine/BytecodeIterator.v3 b/src/engine/BytecodeIterator.v3 index 6048b21e6..c341bb881 100644 --- a/src/engine/BytecodeIterator.v3 +++ b/src/engine/BytecodeIterator.v3 @@ -826,13 +826,6 @@ class BytecodeIterator { FAST_CALL37 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); FAST_CALL38 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); FAST_CALL39 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); - FAST_CALL40 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); - FAST_CALL41 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); - FAST_CALL42 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); - FAST_CALL43 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); - FAST_CALL44 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); - FAST_CALL45 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); - FAST_CALL46 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); } } def trace(out: StringBuilder, module: Module, tracer: InstrTracer) { diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index a40970cab..bda019bfd 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -460,8 +460,6 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e } } - // code should have FAST_CALL replaced after CALL - FAST_CALL0 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); FAST_CALL1 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); FAST_CALL2 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); @@ -502,13 +500,6 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e FAST_CALL37 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); FAST_CALL38 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); FAST_CALL39 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL40 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL41 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL42 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL43 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL44 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL45 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL46 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); CALL_INDIRECT => { var sig = parser.readSigRef(); var table = parser.readTableRef(); diff --git a/src/engine/Opcodes.v3 b/src/engine/Opcodes.v3 index ccb857342..2e785e04c 100644 --- a/src/engine/Opcodes.v3 +++ b/src/engine/Opcodes.v3 @@ -611,53 +611,46 @@ enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: SWITCH (0x00, 0xE6, "switch", imm.CONT_TAG, null) // fast call instructions - FAST_CALL0 (0x00, 0x27, "fast_call0", imm.NONE, null), - FAST_CALL1 (0x00, 0xC5, "fast_call1", imm.NONE, null), - FAST_CALL2 (0x00, 0xC6, "fast_call2", imm.NONE, null), - FAST_CALL3 (0x00, 0xC7, "fast_call3", imm.NONE, null), - FAST_CALL4 (0x00, 0xC8, "fast_call4", imm.NONE, null), - FAST_CALL5 (0x00, 0xC9, "fast_call5", imm.NONE, null), - FAST_CALL6 (0x00, 0xCA, "fast_call6", imm.NONE, null), - FAST_CALL7 (0x00, 0xCB, "fast_call7", imm.NONE, null), - FAST_CALL8 (0x00, 0xCC, "fast_call8", imm.NONE, null), - FAST_CALL9 (0x00, 0xCD, "fast_call9", imm.NONE, null), - FAST_CALL10 (0x00, 0xCE, "fast_call10", imm.NONE, null), - FAST_CALL11 (0x00, 0xCF, "fast_call11", imm.NONE, null), - FAST_CALL12 (0x00, 0xD7, "fast_call12", imm.NONE, null), - FAST_CALL13 (0x00, 0xD8, "fast_call13", imm.NONE, null), - FAST_CALL14 (0x00, 0xD9, "fast_call14", imm.NONE, null), - FAST_CALL15 (0x00, 0xDA, "fast_call15", imm.NONE, null), - FAST_CALL16 (0x00, 0xDB, "fast_call16", imm.NONE, null), - FAST_CALL17 (0x00, 0xDC, "fast_call17", imm.NONE, null), - FAST_CALL18 (0x00, 0xDD, "fast_call18", imm.NONE, null), - FAST_CALL19 (0x00, 0xDE, "fast_call19", imm.NONE, null), - FAST_CALL20 (0x00, 0xDF, "fast_call20", imm.NONE, null), - FAST_CALL21 (0x00, 0xE0, "fast_call21", imm.NONE, null), - FAST_CALL22 (0x00, 0xE1, "fast_call22", imm.NONE, null), - FAST_CALL23 (0x00, 0xE2, "fast_call23", imm.NONE, null), - FAST_CALL24 (0x00, 0xE3, "fast_call24", imm.NONE, null), - FAST_CALL25 (0x00, 0xE4, "fast_call25", imm.NONE, null), - FAST_CALL26 (0x00, 0xE5, "fast_call26", imm.NONE, null), - FAST_CALL27 (0x00, 0xE6, "fast_call27", imm.NONE, null), - FAST_CALL28 (0x00, 0xE7, "fast_call28", imm.NONE, null), - FAST_CALL29 (0x00, 0xE8, "fast_call29", imm.NONE, null), - FAST_CALL30 (0x00, 0xE9, "fast_call30", imm.NONE, null), - FAST_CALL31 (0x00, 0xEA, "fast_call31", imm.NONE, null), - FAST_CALL32 (0x00, 0xEB, "fast_call32", imm.NONE, null), - FAST_CALL33 (0x00, 0xEC, "fast_call33", imm.NONE, null), - FAST_CALL34 (0x00, 0xED, "fast_call34", imm.NONE, null), - FAST_CALL35 (0x00, 0xEE, "fast_call35", imm.NONE, null), - FAST_CALL36 (0x00, 0xEF, "fast_call36", imm.NONE, null), - FAST_CALL37 (0x00, 0xF2, "fast_call37", imm.NONE, null), - FAST_CALL38 (0x00, 0xF3, "fast_call38", imm.NONE, null), - FAST_CALL39 (0x00, 0xF4, "fast_call39", imm.NONE, null), - FAST_CALL40 (0x00, 0xF5, "fast_call40", imm.NONE, null), - FAST_CALL41 (0x00, 0xF6, "fast_call41", imm.NONE, null), - FAST_CALL42 (0x00, 0xF7, "fast_call42", imm.NONE, null), - FAST_CALL43 (0x00, 0xF8, "fast_call43", imm.NONE, null), - FAST_CALL44 (0x00, 0xF9, "fast_call44", imm.NONE, null), - FAST_CALL45 (0x00, 0xFA, "fast_call45", imm.NONE, null), - FAST_CALL46 (0x00, 0x17, "fast_call46", imm.FUNC, null) + FAST_CALL0 (0x00, 0x27, "fast_call0", imm.FUNC, null), + FAST_CALL1 (0x00, 0xC5, "fast_call1", imm.FUNC, null), + FAST_CALL2 (0x00, 0xC6, "fast_call2", imm.FUNC, null), + FAST_CALL3 (0x00, 0xC7, "fast_call3", imm.FUNC, null), + FAST_CALL4 (0x00, 0xC8, "fast_call4", imm.FUNC, null), + FAST_CALL5 (0x00, 0xC9, "fast_call5", imm.FUNC, null), + FAST_CALL6 (0x00, 0xCA, "fast_call6", imm.FUNC, null), + FAST_CALL7 (0x00, 0xCB, "fast_call7", imm.FUNC, null), + FAST_CALL8 (0x00, 0xCC, "fast_call8", imm.FUNC, null), + FAST_CALL9 (0x00, 0xCD, "fast_call9", imm.FUNC, null), + FAST_CALL10 (0x00, 0xCE, "fast_call10", imm.FUNC, null), + FAST_CALL11 (0x00, 0xCF, "fast_call11", imm.FUNC, null), + FAST_CALL12 (0x00, 0xD7, "fast_call12", imm.FUNC, null), + FAST_CALL13 (0x00, 0xD8, "fast_call13", imm.FUNC, null), + FAST_CALL14 (0x00, 0xD9, "fast_call14", imm.FUNC, null), + FAST_CALL15 (0x00, 0xDA, "fast_call15", imm.FUNC, null), + FAST_CALL16 (0x00, 0xDB, "fast_call16", imm.FUNC, null), + FAST_CALL17 (0x00, 0xDC, "fast_call17", imm.FUNC, null), + FAST_CALL18 (0x00, 0xDD, "fast_call18", imm.FUNC, null), + FAST_CALL19 (0x00, 0xDE, "fast_call19", imm.FUNC, null), + FAST_CALL20 (0x00, 0xDF, "fast_call20", imm.FUNC, null), + FAST_CALL21 (0x00, 0xE7, "fast_call21", imm.FUNC, null), + FAST_CALL22 (0x00, 0xE8, "fast_call22", imm.FUNC, null), + FAST_CALL23 (0x00, 0xE9, "fast_call23", imm.FUNC, null), + FAST_CALL24 (0x00, 0xEA, "fast_call24", imm.FUNC, null), + FAST_CALL25 (0x00, 0xEB, "fast_call25", imm.FUNC, null), + FAST_CALL26 (0x00, 0xEC, "fast_call26", imm.FUNC, null), + FAST_CALL27 (0x00, 0xED, "fast_call27", imm.FUNC, null), + FAST_CALL28 (0x00, 0xEE, "fast_call28", imm.FUNC, null), + FAST_CALL29 (0x00, 0xEF, "fast_call29", imm.FUNC, null), + FAST_CALL30 (0x00, 0xF2, "fast_call30", imm.FUNC, null), + FAST_CALL31 (0x00, 0xF3, "fast_call31", imm.FUNC, null), + FAST_CALL32 (0x00, 0xF4, "fast_call32", imm.FUNC, null), + FAST_CALL33 (0x00, 0xF5, "fast_call33", imm.FUNC, null), + FAST_CALL34 (0x00, 0xF6, "fast_call34", imm.FUNC, null), + FAST_CALL35 (0x00, 0xF7, "fast_call35", imm.FUNC, null), + FAST_CALL36 (0x00, 0xF8, "fast_call36", imm.FUNC, null), + FAST_CALL37 (0x00, 0xF9, "fast_call37", imm.FUNC, null), + FAST_CALL38 (0x00, 0xFA, "fast_call38", imm.FUNC, null), + FAST_CALL39 (0x00, 0x17, "fast_call39", imm.FUNC, null), } @@ -848,7 +841,7 @@ component Opcodes { def code_pages = [page_FB, page_FC, page_FD, page_FE]; def var longestName: int; def var num_subpages: int; - def FAST_CALL_OPCODES = 47; + def FAST_CALL_OPCODES = 40; def var fast_calls: Array; private var nameMap: HashMap; @@ -1222,13 +1215,6 @@ component Opcodes { 37 => op = Opcode.FAST_CALL37; 38 => op = Opcode.FAST_CALL38; 39 => op = Opcode.FAST_CALL39; - 40 => op = Opcode.FAST_CALL40; - 41 => op = Opcode.FAST_CALL41; - 42 => op = Opcode.FAST_CALL42; - 43 => op = Opcode.FAST_CALL43; - 44 => op = Opcode.FAST_CALL44; - 45 => op = Opcode.FAST_CALL45; - 46 => op = Opcode.FAST_CALL46; _ => System.error("indexToFastCall", "out of range"); } return op; @@ -1276,13 +1262,6 @@ component Opcodes { FAST_CALL37 => idx = 37; FAST_CALL38 => idx = 38; FAST_CALL39 => idx = 39; - FAST_CALL40 => idx = 40; - FAST_CALL41 => idx = 41; - FAST_CALL42 => idx = 42; - FAST_CALL43 => idx = 43; - FAST_CALL44 => idx = 44; - FAST_CALL45 => idx = 45; - FAST_CALL46 => idx = 46; _ => System.error("fastCallToIndex", "not a FAST_CALL instruction"); } return idx; diff --git a/src/engine/v3/V3Interpreter.v3 b/src/engine/v3/V3Interpreter.v3 index 669b80bbe..b5ae1b0cd 100644 --- a/src/engine/v3/V3Interpreter.v3 +++ b/src/engine/v3/V3Interpreter.v3 @@ -371,7 +371,7 @@ class V3Interpreter extends WasmStack { RETURN => { doReturn(frame.fp, frame.func.sig); } - CALL, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39, FAST_CALL40, FAST_CALL41, FAST_CALL42, FAST_CALL43, FAST_CALL44, FAST_CALL45, FAST_CALL46 => { + CALL, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39 => { var func_index = codeptr.read_uleb32(); var f = frame.func.instance.functions[func_index]; return doCallFunction(f); @@ -1640,7 +1640,7 @@ class V3Interpreter extends WasmStack { // XXX: use read_opcode_and_skip() var opcode = codeptr.read_opcode_but_skip_probe(frame.func.decl); match (opcode) { - CALL, CALL_REF, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39, FAST_CALL40, FAST_CALL41, FAST_CALL42, FAST_CALL43, FAST_CALL44, FAST_CALL45, FAST_CALL46 => { + CALL, CALL_REF, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39 => { codeptr.skip_leb(); frame.pc = codeptr.pos; } diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index 68e44162b..abd6ee6af 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -1365,13 +1365,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { bindHandler(Opcode.FAST_CALL37); bindHandler(Opcode.FAST_CALL38); bindHandler(Opcode.FAST_CALL39); - bindHandler(Opcode.FAST_CALL40); - bindHandler(Opcode.FAST_CALL41); - bindHandler(Opcode.FAST_CALL42); - bindHandler(Opcode.FAST_CALL43); - bindHandler(Opcode.FAST_CALL44); - bindHandler(Opcode.FAST_CALL45); - bindHandler(Opcode.FAST_CALL46); masm.emit_intentional_crash(); //masm.emit_debugger_breakpoint(); var dispatchLabel = X86_64Label.new(); From cd93c2b7585dcf4412f40aaef5703b71af1ec487 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Fri, 3 Apr 2026 16:42:38 -0400 Subject: [PATCH 27/91] Move fast_target_code and fast_call_idx (conflict in internal offset!), also make more compatible with spectests --- src/engine/CodeValidator.v3 | 141 ++++++++++++++++++------------------ src/engine/Module.v3 | 5 +- src/engine/Tuning.v3 | 2 +- 3 files changed, 75 insertions(+), 73 deletions(-) diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index bda019bfd..d0d050019 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -422,84 +422,85 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e checkSignature(func.sig); // fast call: if function is exported with fast name, replace the bytecode with FAST_CALL - if (FastIntTuning.useFastFunctions) for (i < module.exports.length) { - def ex = module.exports[i]; - if (ex.1 == func && Strings.startsWith(ex.0, "fast:")) { - if (Trace.validation) Trace.OUT.puts(" function declared as fast: "); + if (FastIntTuning.useFastFunctions) { + for (i < module.exports.length) { + def ex = module.exports[i]; + if (ex.1 == func && Strings.startsWith(ex.0, "fast:")) { + if (Trace.validation) Trace.OUT.puts(" function declared as fast: "); - var fast_idx = -1; - def fast_funcs = module.fast_funcs; - // look for existing FAST_CALL instruction allocated for this function - for (i < fast_funcs.length) { - if (func == fast_funcs[i]) { - fast_idx = i; - if (Trace.validation) Trace.OUT.put1("allocated as FAST_CALL%d, ", fast_idx); - break; + var fast_idx = -1; + def fast_funcs = module.fast_funcs; + // look for existing FAST_CALL instruction allocated for this function + for (i < fast_funcs.length) { + if (func == fast_funcs[i]) { + fast_idx = i; + if (Trace.validation) Trace.OUT.put1("allocated as FAST_CALL%d, ", fast_idx); + break; + } } - } - // not found? allocate FAST_CALL instruction, if there's space - if (fast_idx < 0) { - if (fast_funcs.length < 48) { - fast_idx = fast_funcs.length; - func.fast_call_idx = fast_idx; - if (Trace.validation) Trace.OUT.put1("not found, allocating FAST_CALL%d, ", fast_idx); - fast_funcs.put(func); + // not found? allocate FAST_CALL instruction, if there's space + if (fast_idx < 0) { + if (fast_funcs.length < 40) { + fast_idx = fast_funcs.length; + func.fast_call_idx = fast_idx; + if (Trace.validation) Trace.OUT.put1("not found, allocating FAST_CALL%d, ", fast_idx); + fast_funcs.put(func); + } else { + if (Trace.validation) Trace.OUT.puts("not found, FAST_CALL table is full, "); + } + } + // replace the bytecode, if it's found or allocated + if (fast_idx >= 0) { + //if (Trace.validation) Trace.OUT.put2("replaceCall(opcode_pos, fast_idx)\n", opcode_pos, fast_idx); + if (Trace.validation) Trace.OUT.puts("replacing call\n"); + this.func.replaceCall(opcode_pos, fast_idx); } else { - if (Trace.validation) Trace.OUT.puts("not found, FAST_CALL table is full, "); + if (Trace.validation) Trace.OUT.puts("not replacing\n"); } } - // replace the bytecode, if it's found or allocated - if (fast_idx >= 0) { - //if (Trace.validation) Trace.OUT.put2("replaceCall(opcode_pos, fast_idx)\n", opcode_pos, fast_idx); - if (Trace.validation) Trace.OUT.puts("replacing call\n"); - this.func.replaceCall(opcode_pos, fast_idx); - } else { - if (Trace.validation) Trace.OUT.puts("not replacing\n"); - } } } - } - FAST_CALL0 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL1 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL2 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL3 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL4 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL5 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL6 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL7 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL8 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL9 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL10 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL11 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL12 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL13 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL14 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL15 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL16 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL17 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL18 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL19 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL20 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL21 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL22 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL23 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL24 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL25 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL26 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL27 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL28 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL29 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL30 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL31 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL32 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL33 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL34 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL35 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL36 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL37 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL38 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL39 => System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL0 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL1 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL2 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL3 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL4 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL5 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL6 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL7 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL8 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL9 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL10 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL11 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL12 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL13 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL14 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL15 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL16 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL17 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL18 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL19 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL20 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL21 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL22 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL23 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL24 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL25 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL26 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL27 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL28 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL29 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL30 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL31 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL32 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL33 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL34 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL35 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL36 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL37 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL38 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); + FAST_CALL39 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); CALL_INDIRECT => { var sig = parser.readSigRef(); var table = parser.readTableRef(); diff --git a/src/engine/Module.v3 b/src/engine/Module.v3 index ecdabfcdf..a26d75e74 100644 --- a/src/engine/Module.v3 +++ b/src/engine/Module.v3 @@ -142,10 +142,10 @@ class FuncDecl(sig_index: int) extends Decl { var cbd_sidetable: Array; // CBD u8 sidetable var frame_var_tags: Array; // value tags for frame variables var target_code: TargetCode; - var fast_target_code: TargetCode; - var fast_call_idx: int = -1; var tierup_trigger: int = int.max; var handlers = FuncHandlerInfo.new(); + var fast_target_code: TargetCode; + var fast_call_idx: int = -1; def render(names: NameSection, buf: StringBuilder) -> StringBuilder { var name = if (names != null, names.getFuncName(func_index)); @@ -217,6 +217,7 @@ class FuncDecl(sig_index: int) extends Decl { Trace.OUT.put3("(func=%q, tag=%d, throw_pc=%d)", this.render(instance.module.names, _), tag.decl.tag_index, throw_pc).ln(); } + while (i < handlers.length) { // XXX: speed this up with a binary search var e = handlers[i]; if (Trace.exception) Trace.OUT.put3(" entry[%d...%d] tag=%d", e.start, e.end, e.tag).ln(); diff --git a/src/engine/Tuning.v3 b/src/engine/Tuning.v3 index 4fa9fa903..df1061a0b 100644 --- a/src/engine/Tuning.v3 +++ b/src/engine/Tuning.v3 @@ -42,7 +42,7 @@ component FastIntTuning { def inlineGlobalAccess = true; // enable inline access of (primitive) globals def stealFlagBitForMemory64 = true; // use a bit in the memarg flags for memory64 def whammProbeTrampolineNumPages = 1024; - def useFastFunctions = true; // treat functions exported with `fast:` in the name as fast functions + def useFastFunctions = false; // treat functions exported with `fast:` in the name as fast functions } // Tuning settings for the single-pass compiler that have no effect on correctness. From 8b0249ac8bfa20189a9dc8740b62a92f454eaf35 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Sun, 5 Apr 2026 17:47:31 -0400 Subject: [PATCH 28/91] fixup! save/restore caller IVars in SPC and across frame reconstruction --- src/engine/compiler/SinglePassCompiler.v3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index f93c0b71a..43855c19b 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -2264,7 +2264,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var wasm_func_reg = allocTmp(ValueKind.REF); var inl_inst_reg: Reg, inl_mem0_reg: Reg; - if (whamm_config.is_inlined) { // TODO investigate, check individual configs? + if (whamm_config.is_inlined) { // XXX check individual configs? inl_inst_reg = allocTmp(ValueKind.REF); inl_mem0_reg = allocTmp(ValueKind.REF); masm.emit_mov_r_m(ValueKind.REF, inl_inst_reg, frame.inlined_instance_slot); From e8d0b8e430d29ecbf562056431100fc21f0f6d4c Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Sun, 5 Apr 2026 17:52:09 -0400 Subject: [PATCH 29/91] fixup! Add CallProperty to distinguish between tail call and fast call --- src/engine/compiler/SinglePassCompiler.v3 | 40 ++--------------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 43855c19b..37dde7258 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -887,9 +887,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var results_count = u32.view(sig.results.length); var orig_sp = state.sp; - // Arguments are already on stack - // Stack: [..., arg0, arg1, ..., argN] <- sp - // We want callee's local 0 = arg0, so: var new_local_base_sp: u31 = u31.view(orig_sp - params_count); var new_ctl_base_sp = u31.view(state.ctl_stack.top); @@ -924,7 +921,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl pushSpcFrame(callee_frame); // Emit function entry probe, if any. - // XXX expensive because frame materialization required if (whamm == null && !FeatureDisable.entryProbes && func.entry_probed) { var probe = Instrumentation.getLocalProbe(module, callee_func.func_index, 0); withReconstructedInlinedFrames(fun => @@ -955,32 +951,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } if (Trace.compiler) Trace.OUT.puts(" End inlined function body").ln(); - // Check if the inlined function is unreachable (e.g., ended with UNREACHABLE, RETURN, THROW) - var inlined_reachable = state.ctl_stack.peek().reachable; - - // Restore caller context by popping frame - popSpcFrame(); // Automatically restores cached fields - - // Note: Control stack cleanup (popping implicit BLOCK) is handled by visit_END - - // If inlined function is unreachable, no results to clean up - if (!inlined_reachable) { - if (Trace.compiler) { - Trace.OUT.puts(" Inlined function unreachable, skipping result cleanup").ln(); - Trace.OUT.put3(" state.sp=%d, new_local_base_sp=%d, callee_slots=%d", - state.sp, new_local_base_sp, state.sp - new_local_base_sp).ln(); - } - // Drop all callee state (params + locals, no results) - var callee_slots = state.sp - new_local_base_sp; - if (callee_slots > 0) dropN(u32.view(callee_slots)); - if (Trace.compiler) Trace.OUT.put1(" After dropN: state.sp=%d", state.sp).ln(); - setUnreachable(); - return; - } - - if (Trace.compiler) { - Trace.OUT.put1(" Inlined call complete, sp=%d", state.sp).ln(); - } + // Restore caller spc context + popSpcFrame(); } def emitCallToReg(sig: SigDecl, func_reg: Reg, vsp_reg: Reg, tmp: Reg, checkHostCall: bool, prop: CallProperty) { var retpt = masm.newLabel(it.pc), wasmcall_label = masm.newLabel(it.pc); @@ -2169,15 +2141,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Return includes epilogue def emitReturn(ctl: SpcControl) { // All explicit RETURN instructions branch here. - if (ret_label != null) { - masm.bindLabel(ret_label); - ret_label = null; - } - - + masm.bindLabel(ret_label); var results = sig.results; - // fix values? if (masm.valuerep.tagged) { // update mismatched value tags var params = sig.params; From b85fcd13746eb23ba647a094a7dbf2e72c5aa84c Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Sun, 5 Apr 2026 18:36:08 -0400 Subject: [PATCH 30/91] Add options for fast functions --- src/engine/EngineOptions.v3 | 2 ++ src/engine/Tuning.v3 | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/EngineOptions.v3 b/src/engine/EngineOptions.v3 index 1c5288dd6..6436aa6e5 100644 --- a/src/engine/EngineOptions.v3 +++ b/src/engine/EngineOptions.v3 @@ -7,6 +7,8 @@ component EngineOptions { var extensions: Extension.set = Extensions.getDefaults(); def DEFAULT_STACK_SIZE = 512u * 1024u; def STACK_SIZE = group.newSizeOption("stack-size", DEFAULT_STACK_SIZE, "Initial stack size in bytes for Wasm execution stacks."); + def FAST_FUNCTIONS = group.newBoolOption("fast-functions", false, "Treat functions exported with `fast:` in the name as fast functions.") + .onSet(fun v => void(FastIntTuning.useFastFunctions = v)); def X_ = OptionsRegistry.addParseFunc(parse); def parse(arg: string, err: ErrorGen) -> bool { diff --git a/src/engine/Tuning.v3 b/src/engine/Tuning.v3 index df1061a0b..bd38b6095 100644 --- a/src/engine/Tuning.v3 +++ b/src/engine/Tuning.v3 @@ -42,7 +42,7 @@ component FastIntTuning { def inlineGlobalAccess = true; // enable inline access of (primitive) globals def stealFlagBitForMemory64 = true; // use a bit in the memarg flags for memory64 def whammProbeTrampolineNumPages = 1024; - def useFastFunctions = false; // treat functions exported with `fast:` in the name as fast functions + var useFastFunctions = false; // treat functions exported with `fast:` in the name as fast functions } // Tuning settings for the single-pass compiler that have no effect on correctness. From 7d68a0d62d3e1640777af5fa38fdc4a8c3c171f7 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Sun, 5 Apr 2026 18:55:39 -0400 Subject: [PATCH 31/91] Fast call tests --- test/all.sh | 16 ++++ test/fastcall/test.sh | 88 ++++++++++++++++++ test/fastcall/test00_nop.wasm | Bin 0 -> 57 bytes test/fastcall/test00_nop.wasm.exit | 1 + test/fastcall/test00_nop.wasm.flags | 1 + test/fastcall/test01_const.wasm | Bin 0 -> 55 bytes test/fastcall/test01_const.wasm.exit | 1 + test/fastcall/test01_const.wasm.flags | 1 + test/fastcall/test02_param.wasm | Bin 0 -> 71 bytes test/fastcall/test02_param.wasm.exit | 1 + test/fastcall/test02_param.wasm.flags | 1 + test/fastcall/test03_add.wasm | Bin 0 -> 70 bytes test/fastcall/test03_add.wasm.exit | 1 + test/fastcall/test03_add.wasm.flags | 1 + test/fastcall/test04_local.wasm | Bin 0 -> 72 bytes test/fastcall/test04_local.wasm.exit | 1 + test/fastcall/test04_local.wasm.flags | 1 + test/fastcall/test05_multiple_calls.wasm | Bin 0 -> 74 bytes test/fastcall/test05_multiple_calls.wasm.exit | 1 + .../fastcall/test05_multiple_calls.wasm.flags | 1 + test/fastcall/test06_if_else.wasm | Bin 0 -> 78 bytes test/fastcall/test06_if_else.wasm.exit | 1 + test/fastcall/test06_if_else.wasm.flags | 1 + test/fastcall/test07_loop.wasm | Bin 0 -> 99 bytes test/fastcall/test07_loop.wasm.exit | 1 + test/fastcall/test07_loop.wasm.flags | 1 + test/fastcall/test08_two_fast_funcs.wasm | Bin 0 -> 97 bytes test/fastcall/test08_two_fast_funcs.wasm.exit | 1 + .../fastcall/test08_two_fast_funcs.wasm.flags | 1 + test/fastcall/test09_fast_calls_regular.wasm | Bin 0 -> 73 bytes .../test09_fast_calls_regular.wasm.exit | 1 + .../test09_fast_calls_regular.wasm.flags | 1 + test/fastcall/test10_global.wasm | Bin 0 -> 85 bytes test/fastcall/test10_global.wasm.exit | 1 + test/fastcall/test10_global.wasm.flags | 1 + test/fastcall/test11_memory.wasm | Bin 0 -> 90 bytes test/fastcall/test11_memory.wasm.exit | 1 + test/fastcall/test11_memory.wasm.flags | 1 + test/fastcall/test12_fast_calls_fast.wasm | Bin 0 -> 113 bytes .../fastcall/test12_fast_calls_fast.wasm.exit | 1 + .../test12_fast_calls_fast.wasm.flags | 1 + test/fastcall/test13_i64.wasm | Bin 0 -> 81 bytes test/fastcall/test13_i64.wasm.exit | 1 + test/fastcall/test13_i64.wasm.flags | 1 + 44 files changed, 132 insertions(+) create mode 100755 test/fastcall/test.sh create mode 100644 test/fastcall/test00_nop.wasm create mode 100644 test/fastcall/test00_nop.wasm.exit create mode 100644 test/fastcall/test00_nop.wasm.flags create mode 100644 test/fastcall/test01_const.wasm create mode 100644 test/fastcall/test01_const.wasm.exit create mode 100644 test/fastcall/test01_const.wasm.flags create mode 100644 test/fastcall/test02_param.wasm create mode 100644 test/fastcall/test02_param.wasm.exit create mode 100644 test/fastcall/test02_param.wasm.flags create mode 100644 test/fastcall/test03_add.wasm create mode 100644 test/fastcall/test03_add.wasm.exit create mode 100644 test/fastcall/test03_add.wasm.flags create mode 100644 test/fastcall/test04_local.wasm create mode 100644 test/fastcall/test04_local.wasm.exit create mode 100644 test/fastcall/test04_local.wasm.flags create mode 100644 test/fastcall/test05_multiple_calls.wasm create mode 100644 test/fastcall/test05_multiple_calls.wasm.exit create mode 100644 test/fastcall/test05_multiple_calls.wasm.flags create mode 100644 test/fastcall/test06_if_else.wasm create mode 100644 test/fastcall/test06_if_else.wasm.exit create mode 100644 test/fastcall/test06_if_else.wasm.flags create mode 100644 test/fastcall/test07_loop.wasm create mode 100644 test/fastcall/test07_loop.wasm.exit create mode 100644 test/fastcall/test07_loop.wasm.flags create mode 100644 test/fastcall/test08_two_fast_funcs.wasm create mode 100644 test/fastcall/test08_two_fast_funcs.wasm.exit create mode 100644 test/fastcall/test08_two_fast_funcs.wasm.flags create mode 100644 test/fastcall/test09_fast_calls_regular.wasm create mode 100644 test/fastcall/test09_fast_calls_regular.wasm.exit create mode 100644 test/fastcall/test09_fast_calls_regular.wasm.flags create mode 100644 test/fastcall/test10_global.wasm create mode 100644 test/fastcall/test10_global.wasm.exit create mode 100644 test/fastcall/test10_global.wasm.flags create mode 100644 test/fastcall/test11_memory.wasm create mode 100644 test/fastcall/test11_memory.wasm.exit create mode 100644 test/fastcall/test11_memory.wasm.flags create mode 100644 test/fastcall/test12_fast_calls_fast.wasm create mode 100644 test/fastcall/test12_fast_calls_fast.wasm.exit create mode 100644 test/fastcall/test12_fast_calls_fast.wasm.flags create mode 100644 test/fastcall/test13_i64.wasm create mode 100644 test/fastcall/test13_i64.wasm.exit create mode 100644 test/fastcall/test13_i64.wasm.flags diff --git a/test/all.sh b/test/all.sh index b898b48f0..a85d1201d 100755 --- a/test/all.sh +++ b/test/all.sh @@ -138,6 +138,22 @@ for target in $TEST_TARGETS; do fi done +# Fast call tests +for target in $TEST_TARGETS; do + export TEST_TARGET=$target + if [ "$target" != "x86-64-linux" ]; then + skip fastcall "no fast interpreter support" + continue + fi + if [[ $DEFAULT_MODES = 1 ]]; then + $SCRIPT_LOC/fastcall/test.sh || exit_if_failure $? + elif [[ "$TEST_MODE" = "jit" || "$TEST_MODE" = "lazy" || "$TEST_MODE" = "dyn" || "$TEST_MODE" = "spc" ]]; then + skip fastcall "requires non-JIT mode" + else + $SCRIPT_LOC/fastcall/test.sh || exit_if_failure $? + fi +done + # Self-hosted (unit) tests for target in $TEST_TARGETS; do export TEST_TARGET=$target diff --git a/test/fastcall/test.sh b/test/fastcall/test.sh new file mode 100755 index 000000000..712e6a1b2 --- /dev/null +++ b/test/fastcall/test.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do + HERE="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$HERE/$SOURCE" +done +HERE="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" + +. $HERE/../common.sh fastcall + +make_wizeng || exit $? + +target=$TEST_TARGET + +print_testing + +cd $HERE +if [ "$#" = 0 ]; then + TESTS=$(ls *.wasm) +else + TESTS="$@" +fi + +RAW=${RAW:=0} + +function run_test() { + local test=$1 + local flags="" + local args="" + + echo "##+$test" + + if [ -f $test.args ]; then + args=$(cat $test.args) + fi + if [ -f $test.flags ]; then + flags=$(cat $test.flags) + fi + + local P=$T/$test + + if [ -f $test.in ]; then + $WIZENG_CMD --colors=false $flags $test -- $args < $test.in > $P.out 2> $P.err + else + $WIZENG_CMD --colors=false $flags $test -- $args > $P.out 2> $P.err + fi + echo $? > $P.exit + + for check in "out" "err" "exit"; do + if [ -f $test.$check ]; then + diff $test.$check $P.$check | tee $P.$check.diff + DIFF=${PIPESTATUS[0]} + if [ "$DIFF" != 0 ]; then + if [ -f failures.$target ]; then + grep $test failures.$target + if [ $? = 0 ]; then + continue # test was found in expected failures + fi + fi + if [ -f failures.$target.$TEST_MODE ]; then + grep $test failures.$target.$TEST_MODE + if [ $? = 0 ]; then + continue # test was found in expected failures + fi + fi + echo "##-fail: $P.$check.diff" + return 1 + fi + fi + done + + echo "##-ok" +} + +function run_tests() { + printf "##>%d\n" $# + for t in $@; do + run_test $t + done +} + +if [ "$RAW" = 0 ]; then + run_tests $TESTS | $PROGRESS +else + run_tests $TESTS +fi diff --git a/test/fastcall/test00_nop.wasm b/test/fastcall/test00_nop.wasm new file mode 100644 index 0000000000000000000000000000000000000000..940e482486d3fdae6079bc61a59a0cff7045cb7c GIT binary patch literal 57 zcmZQbEY4+QU|?Y6U`k+MNMK;BXJ%$%U}P6&;z&y@F0snXFJNF`$xY16V_@XsW@2LC MW@8XwaAe>H0QZ3iAOHXW literal 0 HcmV?d00001 diff --git a/test/fastcall/test00_nop.wasm.exit b/test/fastcall/test00_nop.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test00_nop.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test00_nop.wasm.flags b/test/fastcall/test00_nop.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test00_nop.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test01_const.wasm b/test/fastcall/test01_const.wasm new file mode 100644 index 0000000000000000000000000000000000000000..f883af1b3ddcf6da8f377bed30a646e271e4d0fb GIT binary patch literal 55 zcmZQbEY4+QU|?WmWlUgTtY>CsVqjnwWMWH8EH1H1V_;y(P0Y+=VC3RsVqtL9;$~+M I08;MU0Nd6FvH$=8 literal 0 HcmV?d00001 diff --git a/test/fastcall/test01_const.wasm.exit b/test/fastcall/test01_const.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test01_const.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test01_const.wasm.flags b/test/fastcall/test01_const.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test01_const.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test02_param.wasm b/test/fastcall/test02_param.wasm new file mode 100644 index 0000000000000000000000000000000000000000..2b91d93afaeb285ccde57103366c361520b26747 GIT binary patch literal 71 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mW@2Dumtf*eODrz2%1lYkE6FUWWME*)P0Y*# WsuW^kVNhV;=4Nnw%pd?F+_?eYG!4Z7 literal 0 HcmV?d00001 diff --git a/test/fastcall/test02_param.wasm.exit b/test/fastcall/test02_param.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test02_param.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test02_param.wasm.flags b/test/fastcall/test02_param.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test02_param.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test03_add.wasm b/test/fastcall/test03_add.wasm new file mode 100644 index 0000000000000000000000000000000000000000..760c661fdd678640ec87bd6a50982d227b292f11 GIT binary patch literal 70 zcmV~$F$#b%5Cp*8OCaJkg4pLBcB%4>90WljHnG32I|G}80I1T$o!&qXLBO=ja@qV& Y>m7*0?iXASNyx~2R8c~S8%nDB1FEwN6#xJL literal 0 HcmV?d00001 diff --git a/test/fastcall/test03_add.wasm.exit b/test/fastcall/test03_add.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test03_add.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test03_add.wasm.flags b/test/fastcall/test03_add.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test03_add.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test04_local.wasm b/test/fastcall/test04_local.wasm new file mode 100644 index 0000000000000000000000000000000000000000..4777a2d90f220cb4710eeed9c617fe0609053d48 GIT binary patch literal 72 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mW@2Du7i3~fODrz2N@HMP$xY1611gbX;$vj2 aS72~t%u-@hV9ep>WN>5=U~rUl=LP_zZVLAR literal 0 HcmV?d00001 diff --git a/test/fastcall/test04_local.wasm.exit b/test/fastcall/test04_local.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test04_local.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test04_local.wasm.flags b/test/fastcall/test04_local.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test04_local.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test05_multiple_calls.wasm b/test/fastcall/test05_multiple_calls.wasm new file mode 100644 index 0000000000000000000000000000000000000000..0fc98eeb78f9dc77d6875304d379a2d0496a20cf GIT binary patch literal 74 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mW@2Du7h~d1ODrz2O35!x%1LElV98C)%mblaA$4H*Cc literal 0 HcmV?d00001 diff --git a/test/fastcall/test10_global.wasm.exit b/test/fastcall/test10_global.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test10_global.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test10_global.wasm.flags b/test/fastcall/test10_global.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test10_global.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test11_memory.wasm b/test/fastcall/test11_memory.wasm new file mode 100644 index 0000000000000000000000000000000000000000..57cb1a69468de747fa348d255be27bac759bd40a GIT binary patch literal 90 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mW@2DuWoBexWS3&%PfIK=u_`XfFG`Ki$xlpS nU|`8j%*+F7kYnOwaAZ(mFk=Ez8cYn_ybO*zA20}jNq24l&xR2F literal 0 HcmV?d00001 diff --git a/test/fastcall/test11_memory.wasm.exit b/test/fastcall/test11_memory.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test11_memory.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test11_memory.wasm.flags b/test/fastcall/test11_memory.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test11_memory.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test12_fast_calls_fast.wasm b/test/fastcall/test12_fast_calls_fast.wasm new file mode 100644 index 0000000000000000000000000000000000000000..dac1a1c750c7a5508449575b3c98b1f09fe1011a GIT binary patch literal 113 zcmXAdF$#n*6hvq81A=J+TiI#9C$LMk$IuiTP>kZn)VaD@%&Pni z7SRH#<}D`pbdBlE{`Uo5&&qK+!t|U8)X^_HR69t6zOorpZPC+Wt?k5VOV@qO4U`8K A?*IS* literal 0 HcmV?d00001 diff --git a/test/fastcall/test12_fast_calls_fast.wasm.exit b/test/fastcall/test12_fast_calls_fast.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test12_fast_calls_fast.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test12_fast_calls_fast.wasm.flags b/test/fastcall/test12_fast_calls_fast.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test12_fast_calls_fast.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test13_i64.wasm b/test/fastcall/test13_i64.wasm new file mode 100644 index 0000000000000000000000000000000000000000..8eda94daabf85d032e4a4326c248e6d34d0b2a4d GIT binary patch literal 81 zcmZQbEY4+QU|?Y6W=deHt7EK7U|_6gW@chwWEW-PN=qy*vC1vYF*9LcV98C)%wu5W il4D|LP+(ACtm778a5~Up3&H{nP7MpDEbWyI;syY7cM;G4 literal 0 HcmV?d00001 diff --git a/test/fastcall/test13_i64.wasm.exit b/test/fastcall/test13_i64.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test13_i64.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test13_i64.wasm.flags b/test/fastcall/test13_i64.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test13_i64.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true From b62026c20e71a38d0bc0965a4ba1ad4e8a94100c Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Sun, 5 Apr 2026 19:56:27 -0400 Subject: [PATCH 32/91] Fix regular inlining --- src/engine/compiler/SinglePassCompiler.v3 | 59 +++++++++++------------ 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 37dde7258..089524c5c 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -780,37 +780,34 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl setUnreachable(); } def visit_END() { - if (needsEpilogue()) { - var ctl_top = state.ctl_stack.peek(); - if (ctl_top.opcode == Opcode.LOOP.code) { - state.ctl_stack.pop(); - if (!ctl_top.reachable) setUnreachable(); - } else if (ctl_top.opcode == Opcode.IF.code) { - // simulate empty if-true block - state.emitFallthru(resolver); - masm.emit_br(ctl_top.label); - masm.bindLabel(ctl_top.else_label); - state.doElse(); - ctl_top.opcode = Opcode.ELSE.code; - state.emitFallthru(resolver); - masm.bindLabel(ctl_top.label); - state.resetToMerge(ctl_top); - state.ctl_stack.pop(); - } else if (ctl_top.opcode == Opcode.BLOCK.code || ctl_top.opcode == Opcode.ELSE.code) { - state.emitFallthru(resolver); - masm.bindLabel(ctl_top.label); - state.resetToMerge(ctl_top); - state.ctl_stack.pop(); - // case for END for fallthrough at end of function? - } else if (ctl_top.opcode == Opcode.RETURN.code) { - state.emitFallthru(resolver); - masm.bindLabel(ctl_top.label); - state.resetToMerge(ctl_top); - emitProbe(); - if (ctl_top.merge_count > 1) emitReturn(ctl_top); - state.ctl_stack.pop(); - } - + var ctl_top = state.ctl_stack.peek(); + if (ctl_top.opcode == Opcode.LOOP.code) { + state.ctl_stack.pop(); + if (!ctl_top.reachable) setUnreachable(); + } else if (ctl_top.opcode == Opcode.IF.code) { + // simulate empty if-true block + state.emitFallthru(resolver); + masm.emit_br(ctl_top.label); + masm.bindLabel(ctl_top.else_label); + state.doElse(); + ctl_top.opcode = Opcode.ELSE.code; + state.emitFallthru(resolver); + masm.bindLabel(ctl_top.label); + state.resetToMerge(ctl_top); + state.ctl_stack.pop(); + } else if (ctl_top.opcode == Opcode.BLOCK.code || ctl_top.opcode == Opcode.ELSE.code) { + state.emitFallthru(resolver); + masm.bindLabel(ctl_top.label); + state.resetToMerge(ctl_top); + state.ctl_stack.pop(); + // case for END for fallthrough at end of function? + } else if (ctl_top.opcode == Opcode.RETURN.code) { + state.emitFallthru(resolver); + masm.bindLabel(ctl_top.label); + state.resetToMerge(ctl_top); + emitProbe(); + if (ctl_top.merge_count > 1) emitReturn(ctl_top); + state.ctl_stack.pop(); } emitProbe(); } From cb75fc645be94b5ee631f935cd77aa16a2dd7df2 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Sun, 5 Apr 2026 20:02:17 -0400 Subject: [PATCH 33/91] Add .wat from tests and more fastcall tests --- test/fastcall/test00_nop.wat | 7 + test/fastcall/test01_const.wat | 9 ++ test/fastcall/test02_param.wat | 10 ++ test/fastcall/test03_add.wat | 13 ++ test/fastcall/test04_local.wat | 16 +++ test/fastcall/test05_multiple_calls.wat | 14 ++ test/fastcall/test06_if_else.wat | 19 +++ test/fastcall/test07_loop.wat | 31 +++++ test/fastcall/test08_two_fast_funcs.wat | 21 +++ test/fastcall/test09_fast_calls_regular.wat | 15 ++ test/fastcall/test10_global.wat | 16 +++ test/fastcall/test11_memory.wat | 15 ++ test/fastcall/test12_fast_calls_fast.wat | 19 +++ test/fastcall/test13_i64.wat | 13 ++ test/fastcall/test14_f32.wasm | Bin 0 -> 90 bytes test/fastcall/test14_f32.wasm.exit | 1 + test/fastcall/test14_f32.wasm.flags | 1 + test/fastcall/test14_f32.wat | 17 +++ test/fastcall/test15_f64.wasm | Bin 0 -> 106 bytes test/fastcall/test15_f64.wasm.exit | 1 + test/fastcall/test15_f64.wasm.flags | 1 + test/fastcall/test15_f64.wat | 17 +++ test/fastcall/test16_multi_return.wasm | Bin 0 -> 83 bytes test/fastcall/test16_multi_return.wasm.exit | 1 + test/fastcall/test16_multi_return.wasm.flags | 1 + test/fastcall/test16_multi_return.wat | 20 +++ test/fastcall/test17_trap.wasm | Bin 0 -> 59 bytes test/fastcall/test17_trap.wasm.exit | 1 + test/fastcall/test17_trap.wasm.flags | 1 + test/fastcall/test17_trap.wat | 8 ++ test/fastcall/test18_caller_loop.wasm | Bin 0 -> 94 bytes test/fastcall/test18_caller_loop.wasm.exit | 1 + test/fastcall/test18_caller_loop.wasm.flags | 1 + test/fastcall/test18_caller_loop.wat | 27 ++++ test/fastcall/test19_dual_export.wasm | Bin 0 -> 79 bytes test/fastcall/test19_dual_export.wasm.exit | 1 + test/fastcall/test19_dual_export.wasm.flags | 1 + test/fastcall/test19_dual_export.wat | 13 ++ test/fastcall/test20_many_fast_funcs.wasm | Bin 0 -> 1201 bytes .../fastcall/test20_many_fast_funcs.wasm.exit | 1 + .../test20_many_fast_funcs.wasm.flags | 1 + test/fastcall/test20_many_fast_funcs.wat | 128 ++++++++++++++++++ test/fastcall/test21_inline_simple.wasm | Bin 0 -> 73 bytes test/fastcall/test21_inline_simple.wasm.exit | 1 + test/fastcall/test21_inline_simple.wasm.flags | 1 + test/fastcall/test21_inline_simple.wat | 16 +++ test/fastcall/test22_inline_control.wasm | Bin 0 -> 122 bytes test/fastcall/test22_inline_control.wasm.exit | 1 + .../fastcall/test22_inline_control.wasm.flags | 1 + test/fastcall/test22_inline_control.wat | 42 ++++++ test/fastcall/test23_inline_with_locals.wasm | Bin 0 -> 90 bytes .../test23_inline_with_locals.wasm.exit | 1 + .../test23_inline_with_locals.wasm.flags | 1 + test/fastcall/test23_inline_with_locals.wat | 26 ++++ test/fastcall/test24_inline_depth2.wasm | Bin 0 -> 83 bytes test/fastcall/test24_inline_depth2.wasm.exit | 1 + test/fastcall/test24_inline_depth2.wasm.flags | 1 + test/fastcall/test24_inline_depth2.wat | 20 +++ test/fastcall/test25_outcall_depth0.wasm | Bin 0 -> 73 bytes test/fastcall/test25_outcall_depth0.wasm.exit | 1 + .../fastcall/test25_outcall_depth0.wasm.flags | 1 + test/fastcall/test25_outcall_depth0.wat | 16 +++ test/fastcall/test26_outcall_depth1.wasm | Bin 0 -> 81 bytes test/fastcall/test26_outcall_depth1.wasm.exit | 1 + .../fastcall/test26_outcall_depth1.wasm.flags | 1 + test/fastcall/test26_outcall_depth1.wat | 20 +++ 66 files changed, 614 insertions(+) create mode 100644 test/fastcall/test00_nop.wat create mode 100644 test/fastcall/test01_const.wat create mode 100644 test/fastcall/test02_param.wat create mode 100644 test/fastcall/test03_add.wat create mode 100644 test/fastcall/test04_local.wat create mode 100644 test/fastcall/test05_multiple_calls.wat create mode 100644 test/fastcall/test06_if_else.wat create mode 100644 test/fastcall/test07_loop.wat create mode 100644 test/fastcall/test08_two_fast_funcs.wat create mode 100644 test/fastcall/test09_fast_calls_regular.wat create mode 100644 test/fastcall/test10_global.wat create mode 100644 test/fastcall/test11_memory.wat create mode 100644 test/fastcall/test12_fast_calls_fast.wat create mode 100644 test/fastcall/test13_i64.wat create mode 100644 test/fastcall/test14_f32.wasm create mode 100644 test/fastcall/test14_f32.wasm.exit create mode 100644 test/fastcall/test14_f32.wasm.flags create mode 100644 test/fastcall/test14_f32.wat create mode 100644 test/fastcall/test15_f64.wasm create mode 100644 test/fastcall/test15_f64.wasm.exit create mode 100644 test/fastcall/test15_f64.wasm.flags create mode 100644 test/fastcall/test15_f64.wat create mode 100644 test/fastcall/test16_multi_return.wasm create mode 100644 test/fastcall/test16_multi_return.wasm.exit create mode 100644 test/fastcall/test16_multi_return.wasm.flags create mode 100644 test/fastcall/test16_multi_return.wat create mode 100644 test/fastcall/test17_trap.wasm create mode 100644 test/fastcall/test17_trap.wasm.exit create mode 100644 test/fastcall/test17_trap.wasm.flags create mode 100644 test/fastcall/test17_trap.wat create mode 100644 test/fastcall/test18_caller_loop.wasm create mode 100644 test/fastcall/test18_caller_loop.wasm.exit create mode 100644 test/fastcall/test18_caller_loop.wasm.flags create mode 100644 test/fastcall/test18_caller_loop.wat create mode 100644 test/fastcall/test19_dual_export.wasm create mode 100644 test/fastcall/test19_dual_export.wasm.exit create mode 100644 test/fastcall/test19_dual_export.wasm.flags create mode 100644 test/fastcall/test19_dual_export.wat create mode 100644 test/fastcall/test20_many_fast_funcs.wasm create mode 100644 test/fastcall/test20_many_fast_funcs.wasm.exit create mode 100644 test/fastcall/test20_many_fast_funcs.wasm.flags create mode 100644 test/fastcall/test20_many_fast_funcs.wat create mode 100644 test/fastcall/test21_inline_simple.wasm create mode 100644 test/fastcall/test21_inline_simple.wasm.exit create mode 100644 test/fastcall/test21_inline_simple.wasm.flags create mode 100644 test/fastcall/test21_inline_simple.wat create mode 100644 test/fastcall/test22_inline_control.wasm create mode 100644 test/fastcall/test22_inline_control.wasm.exit create mode 100644 test/fastcall/test22_inline_control.wasm.flags create mode 100644 test/fastcall/test22_inline_control.wat create mode 100644 test/fastcall/test23_inline_with_locals.wasm create mode 100644 test/fastcall/test23_inline_with_locals.wasm.exit create mode 100644 test/fastcall/test23_inline_with_locals.wasm.flags create mode 100644 test/fastcall/test23_inline_with_locals.wat create mode 100644 test/fastcall/test24_inline_depth2.wasm create mode 100644 test/fastcall/test24_inline_depth2.wasm.exit create mode 100644 test/fastcall/test24_inline_depth2.wasm.flags create mode 100644 test/fastcall/test24_inline_depth2.wat create mode 100644 test/fastcall/test25_outcall_depth0.wasm create mode 100644 test/fastcall/test25_outcall_depth0.wasm.exit create mode 100644 test/fastcall/test25_outcall_depth0.wasm.flags create mode 100644 test/fastcall/test25_outcall_depth0.wat create mode 100644 test/fastcall/test26_outcall_depth1.wasm create mode 100644 test/fastcall/test26_outcall_depth1.wasm.exit create mode 100644 test/fastcall/test26_outcall_depth1.wasm.flags create mode 100644 test/fastcall/test26_outcall_depth1.wat diff --git a/test/fastcall/test00_nop.wat b/test/fastcall/test00_nop.wat new file mode 100644 index 000000000..b9e302c55 --- /dev/null +++ b/test/fastcall/test00_nop.wat @@ -0,0 +1,7 @@ +;; Simplest possible fast call: function does nothing. +(module + (func $nop (export "fast:nop")) + (func (export "main") (result i32) + call $nop + i32.const 0) +) diff --git a/test/fastcall/test01_const.wat b/test/fastcall/test01_const.wat new file mode 100644 index 000000000..12013726f --- /dev/null +++ b/test/fastcall/test01_const.wat @@ -0,0 +1,9 @@ +;; Simplest case: fast function returns a constant. +(module + (func $f (export "fast:f") (result i32) + i32.const 42) + (func (export "main") (result i32) + call $f + i32.const 42 + i32.ne) +) diff --git a/test/fastcall/test02_param.wat b/test/fastcall/test02_param.wat new file mode 100644 index 000000000..e7c77a269 --- /dev/null +++ b/test/fastcall/test02_param.wat @@ -0,0 +1,10 @@ +;; Fast function takes a parameter and returns it unchanged. +(module + (func $identity (export "fast:identity") (param i32) (result i32) + local.get 0) + (func (export "main") (result i32) + i32.const 99 + call $identity + i32.const 99 + i32.ne) +) diff --git a/test/fastcall/test03_add.wat b/test/fastcall/test03_add.wat new file mode 100644 index 000000000..136dde849 --- /dev/null +++ b/test/fastcall/test03_add.wat @@ -0,0 +1,13 @@ +;; Fast function adds two i32 parameters. +(module + (func $add (export "fast:add") (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.add) + (func (export "main") (result i32) + i32.const 3 + i32.const 4 + call $add + i32.const 7 + i32.ne) +) diff --git a/test/fastcall/test04_local.wat b/test/fastcall/test04_local.wat new file mode 100644 index 000000000..a6aa429e8 --- /dev/null +++ b/test/fastcall/test04_local.wat @@ -0,0 +1,16 @@ +;; Fast function uses a local variable: computes (n+1)*(n+1). +(module + (func $f (export "fast:f") (param $n i32) (result i32) + (local $tmp i32) + local.get $n + i32.const 1 + i32.add + local.tee $tmp + local.get $tmp + i32.mul) + (func (export "main") (result i32) + i32.const 4 ;; f(4) = 5*5 = 25 + call $f + i32.const 25 + i32.ne) +) diff --git a/test/fastcall/test05_multiple_calls.wat b/test/fastcall/test05_multiple_calls.wat new file mode 100644 index 000000000..5d2f282bd --- /dev/null +++ b/test/fastcall/test05_multiple_calls.wat @@ -0,0 +1,14 @@ +;; Same fast function called multiple times in sequence. +(module + (func $double (export "fast:double") (param i32) (result i32) + local.get 0 + local.get 0 + i32.add) + (func (export "main") (result i32) + i32.const 5 + call $double ;; 10 + call $double ;; 20 + call $double ;; 40 + i32.const 40 + i32.ne) +) diff --git a/test/fastcall/test06_if_else.wat b/test/fastcall/test06_if_else.wat new file mode 100644 index 000000000..9ef717b6d --- /dev/null +++ b/test/fastcall/test06_if_else.wat @@ -0,0 +1,19 @@ +;; Fast function with if/else: absolute value. +(module + (func $abs (export "fast:abs") (param $n i32) (result i32) + local.get $n + i32.const 0 + i32.lt_s + if (result i32) + i32.const 0 + local.get $n + i32.sub + else + local.get $n + end) + (func (export "main") (result i32) + i32.const -7 + call $abs + i32.const 7 + i32.ne) +) diff --git a/test/fastcall/test07_loop.wat b/test/fastcall/test07_loop.wat new file mode 100644 index 000000000..538ec827a --- /dev/null +++ b/test/fastcall/test07_loop.wat @@ -0,0 +1,31 @@ +;; Fast function with a loop: sum 1..n. +(module + (func $sum (export "fast:sum") (param $n i32) (result i32) + (local $i i32) + (local $acc i32) + i32.const 1 + local.set $i + block $break + loop $cont + local.get $i + local.get $n + i32.gt_s + br_if $break + local.get $acc + local.get $i + i32.add + local.set $acc + local.get $i + i32.const 1 + i32.add + local.set $i + br $cont + end + end + local.get $acc) + (func (export "main") (result i32) + i32.const 10 ;; 1+2+...+10 = 55 + call $sum + i32.const 55 + i32.ne) +) diff --git a/test/fastcall/test08_two_fast_funcs.wat b/test/fastcall/test08_two_fast_funcs.wat new file mode 100644 index 000000000..3a0addfe5 --- /dev/null +++ b/test/fastcall/test08_two_fast_funcs.wat @@ -0,0 +1,21 @@ +;; Two distinct fast functions called in the same program. +(module + (func $mul (export "fast:mul") (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.mul) + (func $add (export "fast:add") (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.add) + (func (export "main") (result i32) + i32.const 3 + i32.const 4 + call $mul ;; 12 + i32.const 5 + i32.const 6 + call $add ;; 11 + i32.add ;; 23 + i32.const 23 + i32.ne) +) diff --git a/test/fastcall/test09_fast_calls_regular.wat b/test/fastcall/test09_fast_calls_regular.wat new file mode 100644 index 000000000..706f18ef6 --- /dev/null +++ b/test/fastcall/test09_fast_calls_regular.wat @@ -0,0 +1,15 @@ +;; Fast function calls a regular (non-fast) helper function. +(module + (func $helper (param i32) (result i32) + local.get 0 + i32.const 2 + i32.mul) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $helper) + (func (export "main") (result i32) + i32.const 6 + call $f ;; 12 + i32.const 12 + i32.ne) +) diff --git a/test/fastcall/test10_global.wat b/test/fastcall/test10_global.wat new file mode 100644 index 000000000..a78bef5b3 --- /dev/null +++ b/test/fastcall/test10_global.wat @@ -0,0 +1,16 @@ +;; Fast function reads and writes a global variable. +(module + (global $g (mut i32) (i32.const 0)) + (func $increment (export "fast:increment") + global.get $g + i32.const 1 + i32.add + global.set $g) + (func (export "main") (result i32) + call $increment + call $increment + call $increment + global.get $g + i32.const 3 + i32.ne) +) diff --git a/test/fastcall/test11_memory.wat b/test/fastcall/test11_memory.wat new file mode 100644 index 000000000..15d381eb0 --- /dev/null +++ b/test/fastcall/test11_memory.wat @@ -0,0 +1,15 @@ +;; Fast function stores to and loads from linear memory. +(module + (memory 1) + (func $store_load (export "fast:store_load") (param $val i32) (result i32) + i32.const 0 + local.get $val + i32.store + i32.const 0 + i32.load) + (func (export "main") (result i32) + i32.const 12345 + call $store_load + i32.const 12345 + i32.ne) +) diff --git a/test/fastcall/test12_fast_calls_fast.wat b/test/fastcall/test12_fast_calls_fast.wat new file mode 100644 index 000000000..e0a4bee25 --- /dev/null +++ b/test/fastcall/test12_fast_calls_fast.wat @@ -0,0 +1,19 @@ +;; Fast function calls another fast function: sum of squares. +(module + (func $square (export "fast:square") (param i32) (result i32) + local.get 0 + local.get 0 + i32.mul) + (func $sum_of_squares (export "fast:sum_of_squares") (param i32 i32) (result i32) + local.get 0 + call $square + local.get 1 + call $square + i32.add) + (func (export "main") (result i32) + i32.const 3 + i32.const 4 + call $sum_of_squares ;; 9 + 16 = 25 + i32.const 25 + i32.ne) +) diff --git a/test/fastcall/test13_i64.wat b/test/fastcall/test13_i64.wat new file mode 100644 index 000000000..bc8b2189a --- /dev/null +++ b/test/fastcall/test13_i64.wat @@ -0,0 +1,13 @@ +;; Fast function operating on i64 values. +(module + (func $mul64 (export "fast:mul64") (param i64 i64) (result i64) + local.get 0 + local.get 1 + i64.mul) + (func (export "main") (result i32) + i64.const 1000000 + i64.const 1000000 + call $mul64 ;; 1_000_000_000_000 + i64.const 1000000000000 + i64.ne) +) diff --git a/test/fastcall/test14_f32.wasm b/test/fastcall/test14_f32.wasm new file mode 100644 index 0000000000000000000000000000000000000000..b949d9aed341f1138628ba75b0c822e33c13cc52 GIT binary patch literal 90 zcmZQbEY4+QU|?Y6VM<`Gt*vFOO<-WGXJ%$%U}P6%;z~;_F0o3>O*A%QU|`8j%*Kc1!5OIA0Z2H2hz5HBkiY|n7;XUIBMO*AuMU|`8j%*zE84kn% literal 0 HcmV?d00001 diff --git a/test/fastcall/test16_multi_return.wasm.exit b/test/fastcall/test16_multi_return.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test16_multi_return.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test16_multi_return.wasm.flags b/test/fastcall/test16_multi_return.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test16_multi_return.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test16_multi_return.wat b/test/fastcall/test16_multi_return.wat new file mode 100644 index 000000000..871150cf6 --- /dev/null +++ b/test/fastcall/test16_multi_return.wat @@ -0,0 +1,20 @@ +;; Fast function returning multiple values (i32, i32). +(module + (func $divmod (export "fast:divmod") (param i32 i32) (result i32 i32) + ;; returns (a / b, a % b) + local.get 0 + local.get 1 + i32.div_u + local.get 0 + local.get 1 + i32.rem_u) + (func (export "main") (result i32) + i32.const 17 + i32.const 5 + call $divmod ;; quotient=3, remainder=2 + i32.const 2 + i32.ne ;; check remainder + i32.const 3 + i32.ne ;; check quotient (still on stack) + i32.or) +) diff --git a/test/fastcall/test17_trap.wasm b/test/fastcall/test17_trap.wasm new file mode 100644 index 0000000000000000000000000000000000000000..8f02943e2471cecfc36ef542d05a13aa67414374 GIT binary patch literal 59 zcmV~$D-wV(3_!t`gyB~Ng45u*NrUK2MW`sAtFw#u5I|tIT;+;1sEJf-MIl?%MOnK literal 0 HcmV?d00001 diff --git a/test/fastcall/test19_dual_export.wasm.exit b/test/fastcall/test19_dual_export.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test19_dual_export.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test19_dual_export.wasm.flags b/test/fastcall/test19_dual_export.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test19_dual_export.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test19_dual_export.wat b/test/fastcall/test19_dual_export.wat new file mode 100644 index 000000000..f41a8c63d --- /dev/null +++ b/test/fastcall/test19_dual_export.wat @@ -0,0 +1,13 @@ +;; Same function exported under both a fast: name and a plain name. +;; The plain export should still work correctly alongside the fast path. +(module + (func $f (export "fast:triple") (export "triple") (param i32) (result i32) + local.get 0 + i32.const 3 + i32.mul) + (func (export "main") (result i32) + i32.const 7 + call $f ;; via fast: path + i32.const 21 + i32.ne) +) diff --git a/test/fastcall/test20_many_fast_funcs.wasm b/test/fastcall/test20_many_fast_funcs.wasm new file mode 100644 index 0000000000000000000000000000000000000000..940d4b18caa11b2f25318a41c981ddbb9fc22470 GIT binary patch literal 1201 zcma*lIc~yG6oujQY`|bMn0cP3kP6$3>8P>|Xpn+L8q#|M*-o;stRRS-)8{t-r`J5` z>f&^}8UV(%jwUwo5hk{u7x$Ncjd8y1g>ydLK3>jCfC^x!5Ed1|rdCK$Yb2=+Qq&d> zwL_ZPBa{C7BUr)}19)PHtQa9Du8m=)V-1 literal 0 HcmV?d00001 diff --git a/test/fastcall/test22_inline_control.wasm.exit b/test/fastcall/test22_inline_control.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test22_inline_control.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test22_inline_control.wasm.flags b/test/fastcall/test22_inline_control.wasm.flags new file mode 100644 index 000000000..15e24ecd1 --- /dev/null +++ b/test/fastcall/test22_inline_control.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=1 diff --git a/test/fastcall/test22_inline_control.wat b/test/fastcall/test22_inline_control.wat new file mode 100644 index 000000000..020974e53 --- /dev/null +++ b/test/fastcall/test22_inline_control.wat @@ -0,0 +1,42 @@ +;; Inlined callee inside a fast handler uses if/else with early return. +;; Tests that inlined control flow and returns are properly bounded. +(module + (func $clamp (param $x i32) (param $lo i32) (param $hi i32) (result i32) + local.get $x + local.get $lo + i32.lt_s + if + local.get $lo + return + end + local.get $x + local.get $hi + i32.gt_s + if + local.get $hi + return + end + local.get $x) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + i32.const 0 + i32.const 100 + call $clamp) + (func (export "main") (result i32) + i32.const 50 + call $f + i32.const 50 + i32.ne + + i32.const -5 + call $f + i32.const 0 + i32.ne + i32.or + + i32.const 200 + call $f + i32.const 100 + i32.ne + i32.or) +) diff --git a/test/fastcall/test23_inline_with_locals.wasm b/test/fastcall/test23_inline_with_locals.wasm new file mode 100644 index 0000000000000000000000000000000000000000..85eb686184b75320436431ddaaada09a06884706 GIT binary patch literal 90 zcmWN_F%CdL5CzcxXE%sxh)OqFN6>BM8oP~zprN0uQ@)4tTm(RsEbjCSdWhklx|eDz k&%113yvlw<+BpoQ8w}?pCPw3VX!G0HK@};a*fEW(euvHs$^ZZW literal 0 HcmV?d00001 diff --git a/test/fastcall/test23_inline_with_locals.wasm.exit b/test/fastcall/test23_inline_with_locals.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test23_inline_with_locals.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test23_inline_with_locals.wasm.flags b/test/fastcall/test23_inline_with_locals.wasm.flags new file mode 100644 index 000000000..15e24ecd1 --- /dev/null +++ b/test/fastcall/test23_inline_with_locals.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=1 diff --git a/test/fastcall/test23_inline_with_locals.wat b/test/fastcall/test23_inline_with_locals.wat new file mode 100644 index 000000000..48bec2e46 --- /dev/null +++ b/test/fastcall/test23_inline_with_locals.wat @@ -0,0 +1,26 @@ +;; Inlined callee inside a fast handler allocates its own locals. +;; Tests that local slot allocation works across the fast-frame / inlined-frame boundary. +(module + (func $quadratic (param $a i32) (param $b i32) (result i32) + ;; returns a*a + b*b using a local for a*a + (local $aa i32) + local.get $a + local.get $a + i32.mul + local.set $aa + local.get $aa + local.get $b + local.get $b + i32.mul + i32.add) + (func $f (export "fast:f") (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $quadratic) + (func (export "main") (result i32) + i32.const 3 + i32.const 4 + call $f ;; 9 + 16 = 25 + i32.const 25 + i32.ne) +) diff --git a/test/fastcall/test24_inline_depth2.wasm b/test/fastcall/test24_inline_depth2.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a0c9cd80161beef0dfeb005ad5f41a1c68001dff GIT binary patch literal 83 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mWdVt>3o@~#B^H-hr7KL eFgP-1adQA^0U+dN12Gu6IT;+e1ehFo+_?eu5DH=d literal 0 HcmV?d00001 diff --git a/test/fastcall/test24_inline_depth2.wasm.exit b/test/fastcall/test24_inline_depth2.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test24_inline_depth2.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test24_inline_depth2.wasm.flags b/test/fastcall/test24_inline_depth2.wasm.flags new file mode 100644 index 000000000..d87b35653 --- /dev/null +++ b/test/fastcall/test24_inline_depth2.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=2 diff --git a/test/fastcall/test24_inline_depth2.wat b/test/fastcall/test24_inline_depth2.wat new file mode 100644 index 000000000..8748ce03c --- /dev/null +++ b/test/fastcall/test24_inline_depth2.wat @@ -0,0 +1,20 @@ +;; Fast handler with inline-max-depth=2: A->B->C all inlined into the handler. +;; Tests that a chain of two inlined calls works inside a fast-compiled function. +(module + (func $add1 (param i32) (result i32) + local.get 0 + i32.const 1 + i32.add) + (func $add2 (param i32) (result i32) + local.get 0 + call $add1 + call $add1) ;; +2 total; both $add1 calls inlined at depth 2 + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $add2) ;; $add2 inlined at depth 1 + (func (export "main") (result i32) + i32.const 10 + call $f ;; 10+2 = 12 + i32.const 12 + i32.ne) +) diff --git a/test/fastcall/test25_outcall_depth0.wasm b/test/fastcall/test25_outcall_depth0.wasm new file mode 100644 index 0000000000000000000000000000000000000000..1600d1b813ec35d5a14a88080780bd21e10be338 GIT binary patch literal 73 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mVFn7Y3o@~#B^H-hr73o@~#B^H-hr7 Date: Tue, 7 Apr 2026 20:10:30 -0400 Subject: [PATCH 34/91] Fix multi_return test (div incorrect) --- test/fastcall/test16_multi_return.wasm | Bin 83 -> 89 bytes test/fastcall/test16_multi_return.wat | 12 +++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/test/fastcall/test16_multi_return.wasm b/test/fastcall/test16_multi_return.wasm index 2f944a5d2468586576f115b3919909f7f827d859..025190c6018b82010debdabd5631a826d70ef27e 100644 GIT binary patch delta 42 ucmWHJoM57=!o+z@WgG2O Date: Tue, 7 Apr 2026 23:19:03 -0400 Subject: [PATCH 35/91] Add stackframe test --- test/fastcall/test27_outcall_stackframe.wasm | Bin 0 -> 69 bytes .../fastcall/test27_outcall_stackframe.wasm.exit | 1 + .../test27_outcall_stackframe.wasm.flags | 1 + test/fastcall/test27_outcall_stackframe.wasm.out | 5 +++++ test/fastcall/test27_outcall_stackframe.wat | 15 +++++++++++++++ 5 files changed, 22 insertions(+) create mode 100644 test/fastcall/test27_outcall_stackframe.wasm create mode 100644 test/fastcall/test27_outcall_stackframe.wasm.exit create mode 100644 test/fastcall/test27_outcall_stackframe.wasm.flags create mode 100644 test/fastcall/test27_outcall_stackframe.wasm.out create mode 100644 test/fastcall/test27_outcall_stackframe.wat diff --git a/test/fastcall/test27_outcall_stackframe.wasm b/test/fastcall/test27_outcall_stackframe.wasm new file mode 100644 index 0000000000000000000000000000000000000000..4e7b653cb2ce4accc410fa191b5b521ce0f4993c GIT binary patch literal 69 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mVFn7Y3o@~#B^H-hr7 +40 + +3 + +1 + !trap[UNREACHABLE] diff --git a/test/fastcall/test27_outcall_stackframe.wat b/test/fastcall/test27_outcall_stackframe.wat new file mode 100644 index 000000000..b4eaa64ef --- /dev/null +++ b/test/fastcall/test27_outcall_stackframe.wat @@ -0,0 +1,15 @@ +;; Fast handler makes an out-call (no inlining) to a function that traps. +;; Verifies that the fast function's frame is properly reconstructed on the +;; native stack so it appears in the trap stack trace. +(module + (func $trap (param i32) (result i32) + unreachable) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $trap) + (func (export "main") (result i32) + i32.const 7 + call $f + drop + i32.const 0) +) From 6e79fee9bf6ac70f8bcf3ccb5ac599320b1ceac8 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 7 Apr 2026 23:34:36 -0400 Subject: [PATCH 36/91] Save interpreter r_ip into the frame (to protect against div) --- src/engine/compiler/SinglePassCompiler.v3 | 12 ++++++++++-- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 4 +++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 089524c5c..c7cb7a5e2 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -376,7 +376,14 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_m_l(frame.inlined_instance_slot, 0); } } else { - masm.emit_addw_r_i(X86_64MasmRegs.INT_EXEC_ENV.ip, uleb_size(func.func_index)); + // Advance IP past the fast-call opcode and spill it + def r_ip = X86_64MasmRegs.INT_EXEC_ENV.ip; + def ip_slot = X86_64MasmRegs.INT_EXEC_ENV.ip_slot; + masm.emit_addw_r_i(r_ip, uleb_size(func.func_index)); + masm.emit_mov_m_r(ValueKind.REF, ip_slot, r_ip); + // XXX why do we have to spill? because div will clobber rax + // In a single pass, we don't know at this point if a div will be used + // add as a property picked up during validation? } // Compute VFP = VSP - sig.params.length * SLOT_SIZE @@ -2798,7 +2805,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl return !isInlined() || ctl_base_sp == 0; } def inlineDepth() -> int { - return state.frame_stack.top - 1; + // subtract extra 1 in the fastcall case + return if(fast, state.frame_stack.top - 2, state.frame_stack.top - 1); } def snapshotFrames() -> Array { var frames = Array.new(state.frame_stack.top); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 7978058f5..4468c30e3 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -85,7 +85,9 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.trap_stubs = TRAPS_STUB; } def emitFastDispatch() { - mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, + // XXX Restore IP from the interpreter frame slot + asm.movq_r_m(r_ip, m_ip); + mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } private def saveIVar(r: X86_64Gpr) { From 545db5ed54a24c3f3ca54ff9074d10be8458a194 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 8 Apr 2026 11:44:17 -0400 Subject: [PATCH 37/91] Fix test expectation --- test/fastcall/test27_outcall_stackframe.wasm.out | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fastcall/test27_outcall_stackframe.wasm.out b/test/fastcall/test27_outcall_stackframe.wasm.out index ae9680693..d8e083192 100644 --- a/test/fastcall/test27_outcall_stackframe.wasm.out +++ b/test/fastcall/test27_outcall_stackframe.wasm.out @@ -1,5 +1,5 @@ fast function fast:f - +40 + +3 +3 +1 !trap[UNREACHABLE] From b913d521e76597da2d2fa3c22318f27b9e1d24cc Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 8 Apr 2026 12:19:30 -0400 Subject: [PATCH 38/91] Validate interpreter's pc in a fast function's outcall --- src/engine/compiler/SinglePassCompiler.v3 | 11 +++++++++-- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 6 ++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index c7cb7a5e2..7375dab68 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -121,6 +121,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var skip_to_end: bool; var whamm_config: WhammInlineConfig; var frames_reconstructed = false; + var fast_operand_size: int; // XXX: hack var handler_dest_info = Vector.new(); @@ -150,6 +151,11 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var before_code_bytes = masm.curCodeBytes(); var before_data_bytes = masm.curDataBytes(); + if (fast) { + fast_operand_size = uleb_size(func.func_index); + if (Trace.compiler) Trace.OUT.put1("fast operand size: %d\n", fast_operand_size); + } + // Reset internal state. regAlloc.clear(); trap_labels.resize(0); @@ -379,7 +385,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Advance IP past the fast-call opcode and spill it def r_ip = X86_64MasmRegs.INT_EXEC_ENV.ip; def ip_slot = X86_64MasmRegs.INT_EXEC_ENV.ip_slot; - masm.emit_addw_r_i(r_ip, uleb_size(func.func_index)); + masm.emit_addw_r_i(r_ip, fast_operand_size); masm.emit_mov_m_r(ValueKind.REF, ip_slot, r_ip); // XXX why do we have to spill? because div will clobber rax // In a single pass, we don't know at this point if a div will be used @@ -2207,12 +2213,13 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def saveCallerIVars(); def restoreDispatchTableReg(); def restoreCallerIVars(); + def computePc(delta: int); // Emit code to materialize stack frames for each inlined function. def emitReconstructStackFrames(frames: Array) -> int { Metrics.spc_static_reconst.val++; masm.emit_inc_metric(Metrics.spc_dynamic_reconst); if (fast) { - // pc already saved + computePc(-(fast_operand_size + 1)); saveCallerIVars(); } else { def real_frame = frames[0]; diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 4468c30e3..776177ba8 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -48,6 +48,7 @@ def m_eip = R.RSP.plus(X86_64InterpreterFrame.eip.offset); def m_func_decl = R.RSP.plus(X86_64InterpreterFrame.func_decl.offset); def m_instance = R.RSP.plus(X86_64InterpreterFrame.instance.offset); def m_curpc = R.RSP.plus(X86_64InterpreterFrame.curpc.offset); +def m_code = R.RSP.plus(X86_64InterpreterFrame.code.offset); def ivar_MEM0_BASE = (r_mem0_base, m_mem0_base); def ivar_VFP = (r_vfp, m_vfp); @@ -121,6 +122,11 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { restoreReg(r_mem0_base); restoreReg(r_vfp); } + def computePc(delta: int) { + def offsets = masm.getOffsets(); + asm.q.lea(r_curpc, X86_64Addr.new(r_ip, null, 1, delta - offsets.Array_contents)); + asm.q.sub_r_m(r_curpc, m_code); + } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { var b = pop(), a = popReg(); From c2d4d5f85040e49673aab653c507c733c0994564 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 9 Apr 2026 13:41:10 -0400 Subject: [PATCH 39/91] Add more tests --- test/fastcall/test28_trap_mid_function.wasm | Bin 0 -> 81 bytes .../test28_trap_mid_function.wasm.exit | 1 + .../test28_trap_mid_function.wasm.flags | 1 + .../test28_trap_mid_function.wasm.out | 5 +++++ test/fastcall/test28_trap_mid_function.wat | 18 +++++++++++++++ .../test29_inline_then_outcall_trap.wasm | Bin 0 -> 77 bytes .../test29_inline_then_outcall_trap.wasm.exit | 1 + ...test29_inline_then_outcall_trap.wasm.flags | 1 + .../test29_inline_then_outcall_trap.wasm.out | 6 +++++ .../test29_inline_then_outcall_trap.wat | 18 +++++++++++++++ .../test30_inline_depth2_outcall_trap.wasm | Bin 0 -> 85 bytes ...est30_inline_depth2_outcall_trap.wasm.exit | 1 + ...st30_inline_depth2_outcall_trap.wasm.flags | 1 + ...test30_inline_depth2_outcall_trap.wasm.out | 7 ++++++ .../test30_inline_depth2_outcall_trap.wat | 20 +++++++++++++++++ test/fastcall/test31_fast_below_spc_trap.wasm | Bin 0 -> 75 bytes .../test31_fast_below_spc_trap.wasm.exit | 1 + .../test31_fast_below_spc_trap.wasm.flags | 1 + .../test31_fast_below_spc_trap.wasm.out | 6 +++++ test/fastcall/test31_fast_below_spc_trap.wat | 16 +++++++++++++ .../fastcall/test32_inline_then_spc_trap.wasm | Bin 0 -> 83 bytes .../test32_inline_then_spc_trap.wasm.exit | 1 + .../test32_inline_then_spc_trap.wasm.flags | 1 + .../test32_inline_then_spc_trap.wasm.out | 7 ++++++ test/fastcall/test32_inline_then_spc_trap.wat | 19 ++++++++++++++++ test/fastcall/test33_fast_self_trap.wasm | Bin 0 -> 68 bytes test/fastcall/test33_fast_self_trap.wasm.exit | 1 + .../fastcall/test33_fast_self_trap.wasm.flags | 1 + test/fastcall/test33_fast_self_trap.wasm.out | 4 ++++ test/fastcall/test33_fast_self_trap.wat | 15 +++++++++++++ test/fastcall/test34_second_outcall_trap.wasm | Bin 0 -> 83 bytes .../test34_second_outcall_trap.wasm.exit | 1 + .../test34_second_outcall_trap.wasm.flags | 1 + .../test34_second_outcall_trap.wasm.out | 5 +++++ test/fastcall/test34_second_outcall_trap.wat | 21 ++++++++++++++++++ 35 files changed, 181 insertions(+) create mode 100644 test/fastcall/test28_trap_mid_function.wasm create mode 100644 test/fastcall/test28_trap_mid_function.wasm.exit create mode 100644 test/fastcall/test28_trap_mid_function.wasm.flags create mode 100644 test/fastcall/test28_trap_mid_function.wasm.out create mode 100644 test/fastcall/test28_trap_mid_function.wat create mode 100644 test/fastcall/test29_inline_then_outcall_trap.wasm create mode 100644 test/fastcall/test29_inline_then_outcall_trap.wasm.exit create mode 100644 test/fastcall/test29_inline_then_outcall_trap.wasm.flags create mode 100644 test/fastcall/test29_inline_then_outcall_trap.wasm.out create mode 100644 test/fastcall/test29_inline_then_outcall_trap.wat create mode 100644 test/fastcall/test30_inline_depth2_outcall_trap.wasm create mode 100644 test/fastcall/test30_inline_depth2_outcall_trap.wasm.exit create mode 100644 test/fastcall/test30_inline_depth2_outcall_trap.wasm.flags create mode 100644 test/fastcall/test30_inline_depth2_outcall_trap.wasm.out create mode 100644 test/fastcall/test30_inline_depth2_outcall_trap.wat create mode 100644 test/fastcall/test31_fast_below_spc_trap.wasm create mode 100644 test/fastcall/test31_fast_below_spc_trap.wasm.exit create mode 100644 test/fastcall/test31_fast_below_spc_trap.wasm.flags create mode 100644 test/fastcall/test31_fast_below_spc_trap.wasm.out create mode 100644 test/fastcall/test31_fast_below_spc_trap.wat create mode 100644 test/fastcall/test32_inline_then_spc_trap.wasm create mode 100644 test/fastcall/test32_inline_then_spc_trap.wasm.exit create mode 100644 test/fastcall/test32_inline_then_spc_trap.wasm.flags create mode 100644 test/fastcall/test32_inline_then_spc_trap.wasm.out create mode 100644 test/fastcall/test32_inline_then_spc_trap.wat create mode 100644 test/fastcall/test33_fast_self_trap.wasm create mode 100644 test/fastcall/test33_fast_self_trap.wasm.exit create mode 100644 test/fastcall/test33_fast_self_trap.wasm.flags create mode 100644 test/fastcall/test33_fast_self_trap.wasm.out create mode 100644 test/fastcall/test33_fast_self_trap.wat create mode 100644 test/fastcall/test34_second_outcall_trap.wasm create mode 100644 test/fastcall/test34_second_outcall_trap.wasm.exit create mode 100644 test/fastcall/test34_second_outcall_trap.wasm.flags create mode 100644 test/fastcall/test34_second_outcall_trap.wasm.out create mode 100644 test/fastcall/test34_second_outcall_trap.wat diff --git a/test/fastcall/test28_trap_mid_function.wasm b/test/fastcall/test28_trap_mid_function.wasm new file mode 100644 index 0000000000000000000000000000000000000000..e543a6c9e8b3782f2b17cbcb5dcdc96213c40177 GIT binary patch literal 81 zcmWl~ArgQf5CzcxcNtMBSRDiBuyGS8%ow0(->a+TJ=D7s0HYQ$qZR&urcOcen@p|V c&)GoN>op+jp&ki|Bh23!5n)00k$XmX0W_-%)Bpeg literal 0 HcmV?d00001 diff --git a/test/fastcall/test28_trap_mid_function.wasm.exit b/test/fastcall/test28_trap_mid_function.wasm.exit new file mode 100644 index 000000000..ace9d0362 --- /dev/null +++ b/test/fastcall/test28_trap_mid_function.wasm.exit @@ -0,0 +1 @@ +255 diff --git a/test/fastcall/test28_trap_mid_function.wasm.flags b/test/fastcall/test28_trap_mid_function.wasm.flags new file mode 100644 index 000000000..3920956e2 --- /dev/null +++ b/test/fastcall/test28_trap_mid_function.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=0 diff --git a/test/fastcall/test28_trap_mid_function.wasm.out b/test/fastcall/test28_trap_mid_function.wasm.out new file mode 100644 index 000000000..99402ee09 --- /dev/null +++ b/test/fastcall/test28_trap_mid_function.wasm.out @@ -0,0 +1,5 @@ +fast function fast:f + +3 + +5 + +5 + !trap[DIV_BY_ZERO] diff --git a/test/fastcall/test28_trap_mid_function.wat b/test/fastcall/test28_trap_mid_function.wat new file mode 100644 index 000000000..9d7ba4a62 --- /dev/null +++ b/test/fastcall/test28_trap_mid_function.wat @@ -0,0 +1,18 @@ +;; Fast handler makes an out-call to a function that traps mid-body (not at first instruction). +;; The trapping function does some arithmetic before hitting div-by-zero. +;; Verifies that the PC in the stack trace reflects the trap site, not the function start. +(module + (func $div (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.div_u) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + i32.const 0 + call $div) + (func (export "main") (result i32) + i32.const 7 + call $f + drop + i32.const 0) +) diff --git a/test/fastcall/test29_inline_then_outcall_trap.wasm b/test/fastcall/test29_inline_then_outcall_trap.wasm new file mode 100644 index 0000000000000000000000000000000000000000..2291c6c2a688f4fcaa78efcd0b3cf126ca722c5e GIT binary patch literal 77 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mWdVt>3o@~#B^H-hr7 +3 + +3 + +3 + +1 + !trap[UNREACHABLE] diff --git a/test/fastcall/test29_inline_then_outcall_trap.wat b/test/fastcall/test29_inline_then_outcall_trap.wat new file mode 100644 index 000000000..8e216dc57 --- /dev/null +++ b/test/fastcall/test29_inline_then_outcall_trap.wat @@ -0,0 +1,18 @@ +;; Fast handler inlines $mid, which makes an out-call to $leaf that traps. +;; Exercises withReconstructedInlinedFrames: one inlined frame must be reconstructed +;; above the fast handler frame in the stack trace. +(module + (func $leaf (param i32) (result i32) + unreachable) + (func $mid (param i32) (result i32) + local.get 0 + call $leaf) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $mid) + (func (export "main") (result i32) + i32.const 5 + call $f + drop + i32.const 0) +) diff --git a/test/fastcall/test30_inline_depth2_outcall_trap.wasm b/test/fastcall/test30_inline_depth2_outcall_trap.wasm new file mode 100644 index 0000000000000000000000000000000000000000..8f51b6817ea20566545f9f3771741e5c06eb9bf4 GIT binary patch literal 85 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mV+D#ZFtQ6Wv85#zmsq7SFtg+)X67-laH+5| dGca(oF(@zyKq*EDkBOU;!I4>jS;~=t8vyRN35oy! literal 0 HcmV?d00001 diff --git a/test/fastcall/test30_inline_depth2_outcall_trap.wasm.exit b/test/fastcall/test30_inline_depth2_outcall_trap.wasm.exit new file mode 100644 index 000000000..ace9d0362 --- /dev/null +++ b/test/fastcall/test30_inline_depth2_outcall_trap.wasm.exit @@ -0,0 +1 @@ +255 diff --git a/test/fastcall/test30_inline_depth2_outcall_trap.wasm.flags b/test/fastcall/test30_inline_depth2_outcall_trap.wasm.flags new file mode 100644 index 000000000..d87b35653 --- /dev/null +++ b/test/fastcall/test30_inline_depth2_outcall_trap.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=2 diff --git a/test/fastcall/test30_inline_depth2_outcall_trap.wasm.out b/test/fastcall/test30_inline_depth2_outcall_trap.wasm.out new file mode 100644 index 000000000..4b489e512 --- /dev/null +++ b/test/fastcall/test30_inline_depth2_outcall_trap.wasm.out @@ -0,0 +1,7 @@ +fast function fast:f + +3 + +3 + +3 + +3 + +1 + !trap[UNREACHABLE] diff --git a/test/fastcall/test30_inline_depth2_outcall_trap.wat b/test/fastcall/test30_inline_depth2_outcall_trap.wat new file mode 100644 index 000000000..41dbd44c8 --- /dev/null +++ b/test/fastcall/test30_inline_depth2_outcall_trap.wat @@ -0,0 +1,20 @@ +;; Fast handler inlines $mid which inlines $inner, which makes an out-call to $trap. +;; Two inlined frames must be reconstructed above the fast handler frame. +(module + (func $trap (param i32) (result i32) + unreachable) + (func $inner (param i32) (result i32) + local.get 0 + call $trap) + (func $mid (param i32) (result i32) + local.get 0 + call $inner) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $mid) + (func (export "main") (result i32) + i32.const 3 + call $f + drop + i32.const 0) +) diff --git a/test/fastcall/test31_fast_below_spc_trap.wasm b/test/fastcall/test31_fast_below_spc_trap.wasm new file mode 100644 index 0000000000000000000000000000000000000000..be1935d04691bab26ca1abcb1cb33d73b2a69350 GIT binary patch literal 75 zcmV~$ArgQf5J1ttu;R!TtXe#WjhjGW#()JoSNA>Y=mJP|1(`*rOur~1th)=Xj_+ +3 + +3 + +1 + +1 + !trap[UNREACHABLE] diff --git a/test/fastcall/test31_fast_below_spc_trap.wat b/test/fastcall/test31_fast_below_spc_trap.wat new file mode 100644 index 000000000..6892198f7 --- /dev/null +++ b/test/fastcall/test31_fast_below_spc_trap.wat @@ -0,0 +1,16 @@ +;; Fast handler out-calls $g (regular SPC), which then calls $trap. +;; Tests that the fast handler frame appears correctly below an SPC frame in the trace. +(module + (func $trap (result i32) + unreachable) + (func $g (param i32) (result i32) + call $trap) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $g) + (func (export "main") (result i32) + i32.const 4 + call $f + drop + i32.const 0) +) diff --git a/test/fastcall/test32_inline_then_spc_trap.wasm b/test/fastcall/test32_inline_then_spc_trap.wasm new file mode 100644 index 0000000000000000000000000000000000000000..aea302f5c954a807337af572aa1972aeccc14e55 GIT binary patch literal 83 zcmXBFArgQf6h+bd_<*AntR}~0*w~2_XAD}fvvq@~9BR7-XmSVYhq}7OfFy?5#k00| bKQVvT>%mW3Fi4(EimYV)xinH@wxy6h+4>1< literal 0 HcmV?d00001 diff --git a/test/fastcall/test32_inline_then_spc_trap.wasm.exit b/test/fastcall/test32_inline_then_spc_trap.wasm.exit new file mode 100644 index 000000000..ace9d0362 --- /dev/null +++ b/test/fastcall/test32_inline_then_spc_trap.wasm.exit @@ -0,0 +1 @@ +255 diff --git a/test/fastcall/test32_inline_then_spc_trap.wasm.flags b/test/fastcall/test32_inline_then_spc_trap.wasm.flags new file mode 100644 index 000000000..15e24ecd1 --- /dev/null +++ b/test/fastcall/test32_inline_then_spc_trap.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=1 diff --git a/test/fastcall/test32_inline_then_spc_trap.wasm.out b/test/fastcall/test32_inline_then_spc_trap.wasm.out new file mode 100644 index 000000000..76c6217ae --- /dev/null +++ b/test/fastcall/test32_inline_then_spc_trap.wasm.out @@ -0,0 +1,7 @@ +fast function fast:f + +3 + +3 + +3 + +1 + +1 + !trap[UNREACHABLE] diff --git a/test/fastcall/test32_inline_then_spc_trap.wat b/test/fastcall/test32_inline_then_spc_trap.wat new file mode 100644 index 000000000..9b916a9ef --- /dev/null +++ b/test/fastcall/test32_inline_then_spc_trap.wat @@ -0,0 +1,19 @@ +;; Fast handler inlines $mid, which out-calls $g (SPC), which calls $trap. +;; Combines inlined frame reconstruction with an SPC chain below the fast frame. +(module + (func $trap (result i32) + unreachable) + (func $g (param i32) (result i32) + call $trap) + (func $mid (param i32) (result i32) + local.get 0 + call $g) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $mid) + (func (export "main") (result i32) + i32.const 6 + call $f + drop + i32.const 0) +) diff --git a/test/fastcall/test33_fast_self_trap.wasm b/test/fastcall/test33_fast_self_trap.wasm new file mode 100644 index 0000000000000000000000000000000000000000..b3d17bd308ebc4c4c6382245149db709fca234a4 GIT binary patch literal 68 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mW@2Du7i3~fODrz2N@HMP$xY1611b??;$l!> WaAeGKWXR*@WN_pZV32ZT;06G8lnN{W literal 0 HcmV?d00001 diff --git a/test/fastcall/test33_fast_self_trap.wasm.exit b/test/fastcall/test33_fast_self_trap.wasm.exit new file mode 100644 index 000000000..ace9d0362 --- /dev/null +++ b/test/fastcall/test33_fast_self_trap.wasm.exit @@ -0,0 +1 @@ +255 diff --git a/test/fastcall/test33_fast_self_trap.wasm.flags b/test/fastcall/test33_fast_self_trap.wasm.flags new file mode 100644 index 000000000..3920956e2 --- /dev/null +++ b/test/fastcall/test33_fast_self_trap.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=0 diff --git a/test/fastcall/test33_fast_self_trap.wasm.out b/test/fastcall/test33_fast_self_trap.wasm.out new file mode 100644 index 000000000..a99ccedcc --- /dev/null +++ b/test/fastcall/test33_fast_self_trap.wasm.out @@ -0,0 +1,4 @@ +fast function fast:f + +3 + +8 + !trap[DIV_BY_ZERO] diff --git a/test/fastcall/test33_fast_self_trap.wat b/test/fastcall/test33_fast_self_trap.wat new file mode 100644 index 000000000..949683dbf --- /dev/null +++ b/test/fastcall/test33_fast_self_trap.wat @@ -0,0 +1,15 @@ +;; Fast handler traps directly (div-by-zero inside $f itself, no out-call). +;; The fast handler frame should be the trap site in the stack trace. +(module + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + i32.const 1 + i32.add + i32.const 0 + i32.div_u) + (func (export "main") (result i32) + i32.const 9 + call $f + drop + i32.const 0) +) diff --git a/test/fastcall/test34_second_outcall_trap.wasm b/test/fastcall/test34_second_outcall_trap.wasm new file mode 100644 index 0000000000000000000000000000000000000000..f6066c373e18435fefa0021d7357562629e4b417 GIT binary patch literal 83 zcmWm2F%Ezr5Cp)z13|e4TPhNNVaHFPA<+aI?D@J_O)@CG5dd +3 + +5 + +1 + !trap[UNREACHABLE] diff --git a/test/fastcall/test34_second_outcall_trap.wat b/test/fastcall/test34_second_outcall_trap.wat new file mode 100644 index 000000000..6e07fa4b0 --- /dev/null +++ b/test/fastcall/test34_second_outcall_trap.wat @@ -0,0 +1,21 @@ +;; Fast handler makes two out-calls; the second one traps. +;; Verifies the PC recorded for the fast frame is the second call site, not the first. +(module + (func $ok (param i32) (result i32) + local.get 0 + i32.const 1 + i32.add) + (func $trap (param i32) (result i32) + local.get 0 + drop + unreachable) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $ok ;; first call, succeeds + call $trap) ;; second call, traps + (func (export "main") (result i32) + i32.const 2 + call $f + drop + i32.const 0) +) From ad9ab8da24f871c11897e3622078b3d6029330a9 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 9 Apr 2026 13:41:15 -0400 Subject: [PATCH 40/91] Update some register stuff --- src/engine/compiler/SinglePassCompiler.v3 | 8 +++++ src/engine/x86-64/X86_64SinglePassCompiler.v3 | 31 +++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 7375dab68..76f7f946f 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -387,7 +387,10 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def ip_slot = X86_64MasmRegs.INT_EXEC_ENV.ip_slot; masm.emit_addw_r_i(r_ip, fast_operand_size); masm.emit_mov_m_r(ValueKind.REF, ip_slot, r_ip); + computePc(-(fast_operand_size + 1)); + saveCallerIVars(); // XXX why do we have to spill? because div will clobber rax + // XXX now saving IVars because it will fail in a div-by-zero (or any HW trap) // In a single pass, we don't know at this point if a div will be used // add as a property picked up during validation? } @@ -2214,6 +2217,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def restoreDispatchTableReg(); def restoreCallerIVars(); def computePc(delta: int); + def computeCurIpForTrap(delta: int); + def computeCurIpFromIp(delta: int); // Emit code to materialize stack frames for each inlined function. def emitReconstructStackFrames(frames: Array) -> int { Metrics.spc_static_reconst.val++; @@ -2221,6 +2226,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (fast) { computePc(-(fast_operand_size + 1)); saveCallerIVars(); + restoreDispatchTableReg(); } else { def real_frame = frames[0]; masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); @@ -2334,6 +2340,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_addw_r_i(regs.sp, space); masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); if (fast) { + // In fast mode, frame.vfp_slot is the caller's ($main's) VFP, not $f's. + // restoreCallerIVars restores r_vfp from the interpreter frame correctly. restoreCallerIVars(); restoreDispatchTableReg(); } diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 776177ba8..8e993f36e 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -127,6 +127,13 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { asm.q.lea(r_curpc, X86_64Addr.new(r_ip, null, 1, delta - offsets.Array_contents)); asm.q.sub_r_m(r_curpc, m_code); } + def computeCurIpForTrap(delta: int) { + if (!FeatureDisable.stacktraces) computeCurIpFromIp(delta); + } + def computeCurIpFromIp(delta: int) { + def offsets = masm.getOffsets(); + asm.q.lea(r_curpc, X86_64Addr.new(r_ip, null, 1, delta - offsets.Array_contents)); + } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { var b = pop(), a = popReg(); @@ -1357,8 +1364,28 @@ class X86_64SpcModuleCode extends X86_64SpcCode { } else if (inline_ctx.tail == null) { h.set_curpc(inline_ctx.head.pc); } else { - p_rsp = reconstructInlinedFramesForTrap(p_rsp, inline_ctx); - (ucontext + ucontext_rsp_offset).store(p_rsp); + // FIXME clean up this code + // fast calls: append interpreter frame + var frame_wf = (p_rsp + X86_64InterpreterFrame.wasm_func.offset).load(); + var l = inline_ctx; + while (l.tail != null) l = l.tail; + var outer_fid = l.head.func_index; + if (frame_wf != null && frame_wf.decl.func_index != outer_fid) { + // var frame_pc = (p_rsp + X86_64InterpreterFrame.curpc.offset).load(); + def frame_pc = X86_64Interpreter.computePCFromFrame(p_rsp); + // TODO we probably need to reconstruct an interpreter frame's pc here + def arr = Lists.toArray(inline_ctx); + def narr = Array.new(arr.length + 1); + for (i < arr.length) narr[i] = arr[i]; + narr[arr.length] = FuncLoc(frame_wf.decl.func_index, frame_pc); + inline_ctx = Lists.fromArray(narr); + } + if (inline_ctx.tail == null) { + (p_rsp + X86_64InterpreterFrame.curpc.offset).store(inline_ctx.head.pc); + } else { + p_rsp = reconstructInlinedFramesForTrap(p_rsp, inline_ctx); + (ucontext + ucontext_rsp_offset).store(p_rsp); + } } } From b54039893cfa6113d687f8e2eaa71829e5af24d0 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 15 Apr 2026 12:14:38 -0400 Subject: [PATCH 41/91] Claude's junk --- src/engine/compiler/SinglePassCompiler.v3 | 50 +++++++++++++++++------ src/engine/x86-64/X86_64MasmRegs.v3 | 7 +++- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 76f7f946f..64fd3d95e 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -14,6 +14,7 @@ class SpcExecEnv { var mem0_base_slot: MasmAddr; var inlined_mem0_base_slot: MasmAddr; var accessor_slot: MasmAddr; + var saved_fast_vfp_slot: MasmAddr; // scratch slot for saving fast VFP across frame reconstruction // Register information. var sp: Reg; @@ -2170,6 +2171,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (!needsEpilogue()) return; // Compute VSP = VFP + state.sp + // In fast mode this must happen before reloading VFP from the interpreter frame, + // because frame.vfp_slot holds the caller's VFP (not the fast handler's VFP). emit_compute_vsp(regs.vsp, state.sp); if (!fast) { // Return to caller // \ fast context: do not emit these instructions @@ -2232,17 +2235,25 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); } - // NOTE we could use interpreter-backed registers for these instead of allocating new regs + // In fast mode, interpreter ivars are live in their registers throughout the handler body + // (INT_ALLOC never allocates them), so use them directly instead of stale frame slots. // load instance - var inst_reg = allocTmp(ValueKind.REF); - masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); - var mem_reg = allocTmp(ValueKind.REF); - masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); + var inst_reg: Reg; + var mem_reg: Reg; + if (fast) { + inst_reg = regs.instance; + mem_reg = regs.mem0_base; + } else { + inst_reg = allocTmp(ValueKind.REF); + masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); + mem_reg = allocTmp(ValueKind.REF); + masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); + } // Load instance.functions def func_reg = allocTmp(ValueKind.REF); masm.emit_v3_Instance_functions_r_r(func_reg, inst_reg); - def vfp_reg = allocTmp(ValueKind.REF); - masm.emit_mov_r_m(ValueKind.REF, vfp_reg, frame.vfp_slot); + def vfp_reg = if(fast, regs.vfp, allocTmp(ValueKind.REF)); + if (!fast) masm.emit_mov_r_m(ValueKind.REF, vfp_reg, frame.vfp_slot); var prev_base_sp = int.view(frames[0].local_base_sp); var wasm_func_reg = allocTmp(ValueKind.REF); @@ -2254,6 +2265,14 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_m(ValueKind.REF, inl_mem0_reg, frame.inlined_mem0_base_slot); } + // In fast mode, save the fast handler's VFP before allocating child frames. + // emit_reload_regs() (inside emitCallToReg) would otherwise load the innermost + // child frame's VFP into regs.vfp, which is not the fast handler's own VFP. + // We use frame.vsp_slot as scratch storage. The save goes to [original_rsp+vsp_offset] + // before sub_rsp; emit_spill_vsp runs after sub_rsp and writes to [new_rsp+vsp_offset], + // which is a different address, so there is no collision. + if (fast) masm.emit_mov_m_r(ValueKind.REF, frame.vsp_slot, regs.vfp); + // Pre-allocate stack space for all reconstructed frames at once. def total_space = (frames.length - 1) * (FRAME_SIZE + 8); masm.emit_subw_r_i(regs.sp, total_space); @@ -2338,13 +2357,18 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl frames_reconstructed = false; if (space > 0) { masm.emit_addw_r_i(regs.sp, space); + } + if (fast) { + // In fast mode, emitReconstructStackFrames saved the fast handler's VFP + // to frame.vsp_slot (before sub_rsp, so at [original_rsp+vsp_offset]). + // After add_rsp restores RSP, frame.vsp_slot refers to that same address. + // Restore interpreter ivars (which clobbers regs.vfp with the interpreter's + // saved VFP), then reload the fast handler's VFP from the saved slot. + restoreCallerIVars(); + masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vsp_slot); + restoreDispatchTableReg(); + } else if (space > 0) { masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); - if (fast) { - // In fast mode, frame.vfp_slot is the caller's ($main's) VFP, not $f's. - // restoreCallerIVars restores r_vfp from the interpreter frame correctly. - restoreCallerIVars(); - restoreDispatchTableReg(); - } } } else { emit(); diff --git a/src/engine/x86-64/X86_64MasmRegs.v3 b/src/engine/x86-64/X86_64MasmRegs.v3 index 73af95b67..47fa6ae6b 100644 --- a/src/engine/x86-64/X86_64MasmRegs.v3 +++ b/src/engine/x86-64/X86_64MasmRegs.v3 @@ -142,6 +142,11 @@ component X86_64MasmRegs { xint.code_slot = m(X86_64InterpreterFrame.code.offset); xint.eip_slot = m(X86_64InterpreterFrame.eip.offset); + // In fast mode, use the code field as scratch for saving the fast VFP across frame + // reconstruction. Frame reconstruction never writes to code_slot, and + // restoreCallerIVars() does not restore any register from it. + xfast.saved_fast_vfp_slot = m(X86_64InterpreterFrame.code.offset); + xint.frameSize = xspc.frameSize = X86_64InterpreterFrame.size; xfast.frameSize = 0; @@ -167,7 +172,7 @@ component X86_64MasmRegs { // A register allocator for interpreter contexts. def INT_ALLOC = (fun -> RegAlloc { var pools = [ - RegPool32.new([RCX, RDX, R8, R9]), // could use callee-restore (but put at end) + RegPool32.new([RBP, RCX, RDX, R8, R9]), // could use callee-restore (but put at end) // if callee-restore registers are used, have to emit a restore at the end RegPool32.new([XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14]) ]; From 80c1a61a316be5a80231de11e9c2f51f06ff789e Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 15 Apr 2026 12:14:45 -0400 Subject: [PATCH 42/91] Revert "Claude's junk" This reverts commit bce391eac9cd6549d7277654f8e89ae885f6fdca. --- src/engine/compiler/SinglePassCompiler.v3 | 50 ++++++----------------- src/engine/x86-64/X86_64MasmRegs.v3 | 7 +--- 2 files changed, 14 insertions(+), 43 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 64fd3d95e..76f7f946f 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -14,7 +14,6 @@ class SpcExecEnv { var mem0_base_slot: MasmAddr; var inlined_mem0_base_slot: MasmAddr; var accessor_slot: MasmAddr; - var saved_fast_vfp_slot: MasmAddr; // scratch slot for saving fast VFP across frame reconstruction // Register information. var sp: Reg; @@ -2171,8 +2170,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (!needsEpilogue()) return; // Compute VSP = VFP + state.sp - // In fast mode this must happen before reloading VFP from the interpreter frame, - // because frame.vfp_slot holds the caller's VFP (not the fast handler's VFP). emit_compute_vsp(regs.vsp, state.sp); if (!fast) { // Return to caller // \ fast context: do not emit these instructions @@ -2235,25 +2232,17 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); } - // In fast mode, interpreter ivars are live in their registers throughout the handler body - // (INT_ALLOC never allocates them), so use them directly instead of stale frame slots. + // NOTE we could use interpreter-backed registers for these instead of allocating new regs // load instance - var inst_reg: Reg; - var mem_reg: Reg; - if (fast) { - inst_reg = regs.instance; - mem_reg = regs.mem0_base; - } else { - inst_reg = allocTmp(ValueKind.REF); - masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); - mem_reg = allocTmp(ValueKind.REF); - masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); - } + var inst_reg = allocTmp(ValueKind.REF); + masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); + var mem_reg = allocTmp(ValueKind.REF); + masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); // Load instance.functions def func_reg = allocTmp(ValueKind.REF); masm.emit_v3_Instance_functions_r_r(func_reg, inst_reg); - def vfp_reg = if(fast, regs.vfp, allocTmp(ValueKind.REF)); - if (!fast) masm.emit_mov_r_m(ValueKind.REF, vfp_reg, frame.vfp_slot); + def vfp_reg = allocTmp(ValueKind.REF); + masm.emit_mov_r_m(ValueKind.REF, vfp_reg, frame.vfp_slot); var prev_base_sp = int.view(frames[0].local_base_sp); var wasm_func_reg = allocTmp(ValueKind.REF); @@ -2265,14 +2254,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_m(ValueKind.REF, inl_mem0_reg, frame.inlined_mem0_base_slot); } - // In fast mode, save the fast handler's VFP before allocating child frames. - // emit_reload_regs() (inside emitCallToReg) would otherwise load the innermost - // child frame's VFP into regs.vfp, which is not the fast handler's own VFP. - // We use frame.vsp_slot as scratch storage. The save goes to [original_rsp+vsp_offset] - // before sub_rsp; emit_spill_vsp runs after sub_rsp and writes to [new_rsp+vsp_offset], - // which is a different address, so there is no collision. - if (fast) masm.emit_mov_m_r(ValueKind.REF, frame.vsp_slot, regs.vfp); - // Pre-allocate stack space for all reconstructed frames at once. def total_space = (frames.length - 1) * (FRAME_SIZE + 8); masm.emit_subw_r_i(regs.sp, total_space); @@ -2357,18 +2338,13 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl frames_reconstructed = false; if (space > 0) { masm.emit_addw_r_i(regs.sp, space); - } - if (fast) { - // In fast mode, emitReconstructStackFrames saved the fast handler's VFP - // to frame.vsp_slot (before sub_rsp, so at [original_rsp+vsp_offset]). - // After add_rsp restores RSP, frame.vsp_slot refers to that same address. - // Restore interpreter ivars (which clobbers regs.vfp with the interpreter's - // saved VFP), then reload the fast handler's VFP from the saved slot. - restoreCallerIVars(); - masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vsp_slot); - restoreDispatchTableReg(); - } else if (space > 0) { masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); + if (fast) { + // In fast mode, frame.vfp_slot is the caller's ($main's) VFP, not $f's. + // restoreCallerIVars restores r_vfp from the interpreter frame correctly. + restoreCallerIVars(); + restoreDispatchTableReg(); + } } } else { emit(); diff --git a/src/engine/x86-64/X86_64MasmRegs.v3 b/src/engine/x86-64/X86_64MasmRegs.v3 index 47fa6ae6b..73af95b67 100644 --- a/src/engine/x86-64/X86_64MasmRegs.v3 +++ b/src/engine/x86-64/X86_64MasmRegs.v3 @@ -142,11 +142,6 @@ component X86_64MasmRegs { xint.code_slot = m(X86_64InterpreterFrame.code.offset); xint.eip_slot = m(X86_64InterpreterFrame.eip.offset); - // In fast mode, use the code field as scratch for saving the fast VFP across frame - // reconstruction. Frame reconstruction never writes to code_slot, and - // restoreCallerIVars() does not restore any register from it. - xfast.saved_fast_vfp_slot = m(X86_64InterpreterFrame.code.offset); - xint.frameSize = xspc.frameSize = X86_64InterpreterFrame.size; xfast.frameSize = 0; @@ -172,7 +167,7 @@ component X86_64MasmRegs { // A register allocator for interpreter contexts. def INT_ALLOC = (fun -> RegAlloc { var pools = [ - RegPool32.new([RBP, RCX, RDX, R8, R9]), // could use callee-restore (but put at end) + RegPool32.new([RCX, RDX, R8, R9]), // could use callee-restore (but put at end) // if callee-restore registers are used, have to emit a restore at the end RegPool32.new([XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14]) ]; From a490e0bb2b8438da68d8b41b78b6631b84ed7035 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Fri, 17 Apr 2026 14:33:31 -0400 Subject: [PATCH 43/91] Streamline compiler to help fix bug --- src/engine/compiler/SinglePassCompiler.v3 | 69 ++++++++++--------- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 11 +-- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 76f7f946f..a626e59db 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -384,15 +384,12 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } else { // Advance IP past the fast-call opcode and spill it def r_ip = X86_64MasmRegs.INT_EXEC_ENV.ip; - def ip_slot = X86_64MasmRegs.INT_EXEC_ENV.ip_slot; - masm.emit_addw_r_i(r_ip, fast_operand_size); - masm.emit_mov_m_r(ValueKind.REF, ip_slot, r_ip); - computePc(-(fast_operand_size + 1)); - saveCallerIVars(); - // XXX why do we have to spill? because div will clobber rax - // XXX now saving IVars because it will fail in a div-by-zero (or any HW trap) - // In a single pass, we don't know at this point if a div will be used - // add as a property picked up during validation? + masm.emit_addw_r_i(r_ip, fast_operand_size); // increment ip + computePc(-(fast_operand_size + 1)); // compute r_curpc + saveCallerIVars(); // save r_ip and r_curpc + // XXX why do we have to save? + // 1. r_ip = rax (clobbered by `div`) + // 2. m_curpc = HW trap reads this } // Compute VFP = VSP - sig.params.length * SLOT_SIZE @@ -2223,30 +2220,23 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def emitReconstructStackFrames(frames: Array) -> int { Metrics.spc_static_reconst.val++; masm.emit_inc_metric(Metrics.spc_dynamic_reconst); - if (fast) { - computePc(-(fast_operand_size + 1)); - saveCallerIVars(); - restoreDispatchTableReg(); - } else { - def real_frame = frames[0]; - masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); - } - // NOTE we could use interpreter-backed registers for these instead of allocating new regs - // load instance var inst_reg = allocTmp(ValueKind.REF); - masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); var mem_reg = allocTmp(ValueKind.REF); - masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); - // Load instance.functions def func_reg = allocTmp(ValueKind.REF); - masm.emit_v3_Instance_functions_r_r(func_reg, inst_reg); def vfp_reg = allocTmp(ValueKind.REF); - masm.emit_mov_r_m(ValueKind.REF, vfp_reg, frame.vfp_slot); - var prev_base_sp = int.view(frames[0].local_base_sp); var wasm_func_reg = allocTmp(ValueKind.REF); - var inl_inst_reg: Reg, inl_mem0_reg: Reg; + + var prev_base_sp = int.view(frames[0].local_base_sp); + + // TODO in fast mode, could use those registers (if not previously reset!--invalidated by future opt) + + masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); + masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); + // Load instance.functions + masm.emit_v3_Instance_functions_r_r(func_reg, inst_reg); + if (whamm_config.is_inlined) { // XXX check individual configs? inl_inst_reg = allocTmp(ValueKind.REF); inl_mem0_reg = allocTmp(ValueKind.REF); @@ -2254,6 +2244,17 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_m(ValueKind.REF, inl_mem0_reg, frame.inlined_mem0_base_slot); } + if (fast) { + // the stuff that would need to be saved should be already saved + // (only restore required later) -- as an optimization, should only restore once at epilogue if there is a reconstrcution + masm.emit_mov_r_r(ValueKind.REF, vfp_reg, regs.vfp); + } else { + def real_frame = frames[0]; + masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); + + masm.emit_mov_r_m(ValueKind.REF, vfp_reg, frame.vfp_slot); + } + // Pre-allocate stack space for all reconstructed frames at once. def total_space = (frames.length - 1) * (FRAME_SIZE + 8); masm.emit_subw_r_i(regs.sp, total_space); @@ -2297,6 +2298,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (vfp_delta != 0) masm.emit_addw_r_i(vfp_reg, vfp_delta); def vfp_slot = frame.vfp_slot.plus(frame_offset); masm.emit_mov_m_r(ValueKind.REF, vfp_slot, vfp_reg); + //masm.emit_mov_m_i(vfp_slot, 1); // Save PC def pc_slot = frame.pc_slot.plus(frame_offset); @@ -2321,7 +2323,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } // Guards compiler code with frame reconstruction (if necessary). def withReconstructedInlinedFrames(emit: void -> void) { + //masm.emit_debugger_breakpoint(); if (isInlined()) { + //masm.emit_debugger_breakpoint(); if (frames_reconstructed) { // FIXME this should not happen (but does): // - in the case of deep nesting when one layer is a Whamm probe @@ -2337,15 +2341,18 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl emit(); frames_reconstructed = false; if (space > 0) { - masm.emit_addw_r_i(regs.sp, space); - masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); if (fast) { - // In fast mode, frame.vfp_slot is the caller's ($main's) VFP, not $f's. - // restoreCallerIVars restores r_vfp from the interpreter frame correctly. + masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot.plus(space - FRAME_SIZE)); + //masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); + masm.emit_addw_r_i(regs.sp, space); restoreCallerIVars(); restoreDispatchTableReg(); + } else { + masm.emit_addw_r_i(regs.sp, space); + masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); } } + //masm.emit_debugger_breakpoint(); } else { emit(); } @@ -2442,7 +2449,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } def emit_reload_regs() { // XXX: recompute VFP from VSP - #slots? - masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); + if (!fast) masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); if (module.memories.length > 0) { if (whamm_config.is_inlined) { masm.emit_mov_r_m(ValueKind.REF, regs.mem0_base, frame.inlined_mem0_base_slot); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 8e993f36e..2b32f9b7f 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -98,7 +98,7 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { } def saveCallerIVars() { saveIVar(r_ip); - saveIVar(r_stp); + //saveIVar(r_stp); if (!FeatureDisable.stacktraces) saveIVar(r_curpc); } def restoreDispatchTableReg() { @@ -114,13 +114,14 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { } } def restoreCallerIVars() { - restoreReg(r_ip); + //restoreReg(r_vfp); + //restoreReg(r_vsp); restoreReg(r_stp); + restoreReg(r_ip); restoreReg(r_eip); - restoreReg(r_instance); restoreReg(r_func_decl); - restoreReg(r_mem0_base); - restoreReg(r_vfp); + restoreReg(r_instance); + restoreReg(r_curpc); } def computePc(delta: int) { def offsets = masm.getOffsets(); From 6ec6747fd716f7f6b4fda5639273e42811b3a711 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 20 Apr 2026 12:18:53 -0400 Subject: [PATCH 44/91] Fix saving of vfp --- src/engine/compiler/SinglePassCompiler.v3 | 49 ++++++++++++++--------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index a626e59db..2fe055cd3 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -396,8 +396,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); // XXX: use 3-addr adjustment of VFP masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); + if (!fast) { - // XXX: skip spilling of VFP + // Spill VFP so emit_reload_regs can restore R11 after calls masm.emit_mov_m_r(ValueKind.REF, frame.vfp_slot, regs.vfp); // Load instance.memories[0].start into MEM0_BASE and spill @@ -819,7 +820,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.bindLabel(ctl_top.label); state.resetToMerge(ctl_top); emitProbe(); - if (ctl_top.merge_count > 1) emitReturn(ctl_top); + if (ctl_top.merge_count > 1) { + emitReturn(ctl_top); + } state.ctl_stack.pop(); } emitProbe(); @@ -2169,11 +2172,11 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Compute VSP = VFP + state.sp emit_compute_vsp(regs.vsp, state.sp); if (!fast) { - // Return to caller // \ fast context: do not emit these instructions - masm.emit_mov_r_i(regs.ret_throw, 0); // | instead, emit the dispatch sequence from the interpreter - // Deallocate stack frame // | - masm.emit_addw_r_i(regs.sp, frame.frameSize); // | - masm.emit_ret(); // / + // Return to caller + masm.emit_mov_r_i(regs.ret_throw, 0); + // Deallocate stack frame + masm.emit_addw_r_i(regs.sp, frame.frameSize); + masm.emit_ret(); } else { // Restore VFP from interpreter frame masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); @@ -2221,12 +2224,12 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl Metrics.spc_static_reconst.val++; masm.emit_inc_metric(Metrics.spc_dynamic_reconst); - var inst_reg = allocTmp(ValueKind.REF); - var mem_reg = allocTmp(ValueKind.REF); - def func_reg = allocTmp(ValueKind.REF); - def vfp_reg = allocTmp(ValueKind.REF); - var wasm_func_reg = allocTmp(ValueKind.REF); + var inst_reg: Reg, mem_reg: Reg, func_reg: Reg, vfp_reg: Reg, wasm_func_reg: Reg; var inl_inst_reg: Reg, inl_mem0_reg: Reg; + inst_reg = allocTmp(ValueKind.REF); + mem_reg = allocTmp(ValueKind.REF); + func_reg = allocTmp(ValueKind.REF); + wasm_func_reg = allocTmp(ValueKind.REF); var prev_base_sp = int.view(frames[0].local_base_sp); @@ -2247,8 +2250,10 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (fast) { // the stuff that would need to be saved should be already saved // (only restore required later) -- as an optimization, should only restore once at epilogue if there is a reconstrcution - masm.emit_mov_r_r(ValueKind.REF, vfp_reg, regs.vfp); + vfp_reg = regs.vfp; } else { + vfp_reg = allocTmp(ValueKind.REF); + def real_frame = frames[0]; masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); @@ -2297,8 +2302,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Step vfp_reg by change in local_base_sp from previous frame and save if (vfp_delta != 0) masm.emit_addw_r_i(vfp_reg, vfp_delta); def vfp_slot = frame.vfp_slot.plus(frame_offset); + masm.emit_debugger_breakpoint(); masm.emit_mov_m_r(ValueKind.REF, vfp_slot, vfp_reg); - //masm.emit_mov_m_i(vfp_slot, 1); + //masm.emit_mov_m_l(vfp_slot, 1); // Save PC def pc_slot = frame.pc_slot.plus(frame_offset); @@ -2323,9 +2329,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } // Guards compiler code with frame reconstruction (if necessary). def withReconstructedInlinedFrames(emit: void -> void) { - //masm.emit_debugger_breakpoint(); if (isInlined()) { - //masm.emit_debugger_breakpoint(); + masm.emit_debugger_breakpoint(); if (frames_reconstructed) { // FIXME this should not happen (but does): // - in the case of deep nesting when one layer is a Whamm probe @@ -2342,9 +2347,13 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl frames_reconstructed = false; if (space > 0) { if (fast) { - masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot.plus(space - FRAME_SIZE)); - //masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); - masm.emit_addw_r_i(regs.sp, space); + Trace.OUT.put2("space: %d, %d\n", space - FRAME_SIZE - 8, space); + masm.emit_debugger_breakpoint(); + //masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot.plus(space - FRAME_SIZE)); + masm.emit_addw_r_i(regs.sp, space - FRAME_SIZE - 8); + masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); + //masm.emit_subw_r_i(regs.vfp, 0x20); + masm.emit_addw_r_i(regs.sp, FRAME_SIZE); restoreCallerIVars(); restoreDispatchTableReg(); } else { @@ -2352,7 +2361,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); } } - //masm.emit_debugger_breakpoint(); + masm.emit_debugger_breakpoint(); } else { emit(); } From 2b5bc9e912b2015c363cf06d2814ebf33a7eb1e1 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 20 Apr 2026 15:18:24 -0400 Subject: [PATCH 45/91] More vfp fix progress --- src/engine/compiler/SinglePassCompiler.v3 | 58 ++++++++++++------- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 6 +- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 2fe055cd3..a828ac3f4 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -150,6 +150,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (Trace.compiler) OUT.put1("==== begin compile: %q ========================", func.render(module.names, _)).ln(); var before_code_bytes = masm.curCodeBytes(); var before_data_bytes = masm.curDataBytes(); + + //masm.emit_debugger_breakpoint(); if (fast) { fast_operand_size = uleb_size(func.func_index); @@ -364,6 +366,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (!cond) bailout(Strings.format3(msg, p1, p2, p3)); } def emitPrologue() { + //masm.emit_debugger_breakpoint(); if (!fast) { // Allocate stack frame masm.emit_subw_r_i(regs.sp, frame.frameSize); @@ -390,11 +393,16 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // XXX why do we have to save? // 1. r_ip = rax (clobbered by `div`) // 2. m_curpc = HW trap reads this + + // spill VFP? + //masm.emit_debugger_breakpoint(); + masm.emit_mov_m_r(ValueKind.REF, frame.vfp_slot, regs.vfp); } // Compute VFP = VSP - sig.params.length * SLOT_SIZE masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); // XXX: use 3-addr adjustment of VFP masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); + //masm.emit_debugger_breakpoint(); if (!fast) { @@ -2179,7 +2187,11 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_ret(); } else { // Restore VFP from interpreter frame - masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); + //masm.emit_debugger_breakpoint(); + masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); // don't need to deallocate before? frame is interpreter's frame? + //masm.emit_debugger_breakpoint(); + restoreCallerIVars(); + restoreDispatchTableReg(); emitFastDispatch(); } } @@ -2226,19 +2238,11 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var inst_reg: Reg, mem_reg: Reg, func_reg: Reg, vfp_reg: Reg, wasm_func_reg: Reg; var inl_inst_reg: Reg, inl_mem0_reg: Reg; - inst_reg = allocTmp(ValueKind.REF); - mem_reg = allocTmp(ValueKind.REF); - func_reg = allocTmp(ValueKind.REF); - wasm_func_reg = allocTmp(ValueKind.REF); var prev_base_sp = int.view(frames[0].local_base_sp); // TODO in fast mode, could use those registers (if not previously reset!--invalidated by future opt) - masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); - masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); - // Load instance.functions - masm.emit_v3_Instance_functions_r_r(func_reg, inst_reg); if (whamm_config.is_inlined) { // XXX check individual configs? inl_inst_reg = allocTmp(ValueKind.REF); @@ -2250,9 +2254,18 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (fast) { // the stuff that would need to be saved should be already saved // (only restore required later) -- as an optimization, should only restore once at epilogue if there is a reconstrcution - vfp_reg = regs.vfp; + vfp_reg = regs.vfp; + inst_reg = regs.instance; + mem_reg = regs.mem0_base; } else { - vfp_reg = allocTmp(ValueKind.REF); + vfp_reg = allocTmp(ValueKind.REF); + inst_reg = allocTmp(ValueKind.REF); + mem_reg = allocTmp(ValueKind.REF); + + masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); + masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); + // Load instance.functions + masm.emit_v3_Instance_functions_r_r(func_reg, inst_reg); def real_frame = frames[0]; masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); @@ -2260,6 +2273,11 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_m(ValueKind.REF, vfp_reg, frame.vfp_slot); } + // Load instance.functions + func_reg = allocTmp(ValueKind.REF); + wasm_func_reg = allocTmp(ValueKind.REF); + masm.emit_v3_Instance_functions_r_r(func_reg, inst_reg); + // Pre-allocate stack space for all reconstructed frames at once. def total_space = (frames.length - 1) * (FRAME_SIZE + 8); masm.emit_subw_r_i(regs.sp, total_space); @@ -2302,7 +2320,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Step vfp_reg by change in local_base_sp from previous frame and save if (vfp_delta != 0) masm.emit_addw_r_i(vfp_reg, vfp_delta); def vfp_slot = frame.vfp_slot.plus(frame_offset); - masm.emit_debugger_breakpoint(); + //masm.emit_debugger_breakpoint(); masm.emit_mov_m_r(ValueKind.REF, vfp_slot, vfp_reg); //masm.emit_mov_m_l(vfp_slot, 1); @@ -2330,7 +2348,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Guards compiler code with frame reconstruction (if necessary). def withReconstructedInlinedFrames(emit: void -> void) { if (isInlined()) { - masm.emit_debugger_breakpoint(); + //masm.emit_debugger_breakpoint(); if (frames_reconstructed) { // FIXME this should not happen (but does): // - in the case of deep nesting when one layer is a Whamm probe @@ -2347,21 +2365,17 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl frames_reconstructed = false; if (space > 0) { if (fast) { - Trace.OUT.put2("space: %d, %d\n", space - FRAME_SIZE - 8, space); - masm.emit_debugger_breakpoint(); - //masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot.plus(space - FRAME_SIZE)); - masm.emit_addw_r_i(regs.sp, space - FRAME_SIZE - 8); + masm.emit_addw_r_i(regs.sp, space - (FRAME_SIZE + 8)); masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); - //masm.emit_subw_r_i(regs.vfp, 0x20); - masm.emit_addw_r_i(regs.sp, FRAME_SIZE); - restoreCallerIVars(); - restoreDispatchTableReg(); + masm.emit_addw_r_i(regs.sp, FRAME_SIZE + 8); + //restoreCallerIVars(); + //restoreDispatchTableReg(); } else { masm.emit_addw_r_i(regs.sp, space); masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); } } - masm.emit_debugger_breakpoint(); + //masm.emit_debugger_breakpoint(); } else { emit(); } diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 2b32f9b7f..f84d4aeb8 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -86,6 +86,7 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.trap_stubs = TRAPS_STUB; } def emitFastDispatch() { + //mmasm.emit_debugger_breakpoint(); // XXX Restore IP from the interpreter frame slot asm.movq_r_m(r_ip, m_ip); mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, @@ -114,13 +115,14 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { } } def restoreCallerIVars() { - //restoreReg(r_vfp); - //restoreReg(r_vsp); + //restoreReg(r_vfp); // restored explicitly before this call (emitReturn line 2175) + //restoreReg(r_vsp); // recomputed from r_vfp + result_slots (emit_compute_vsp) restoreReg(r_stp); restoreReg(r_ip); restoreReg(r_eip); restoreReg(r_func_decl); restoreReg(r_instance); + restoreReg(r_mem0_base); restoreReg(r_curpc); } def computePc(delta: int) { From 55f3e974bb95d9474c895eb85201b0a6316f40c7 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 20 Apr 2026 16:21:04 -0400 Subject: [PATCH 46/91] Fix bug --- src/engine/compiler/SinglePassCompiler.v3 | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index a828ac3f4..1e9dd61b3 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -2187,10 +2187,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_ret(); } else { // Restore VFP from interpreter frame - //masm.emit_debugger_breakpoint(); - masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); // don't need to deallocate before? frame is interpreter's frame? - //masm.emit_debugger_breakpoint(); - restoreCallerIVars(); + masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); + // In fast mode, caller ivars (stp, eip, func_decl, instance, mem0_base) were + // never clobbered and need no restoration — only r_ip is reloaded by emitFastDispatch. restoreDispatchTableReg(); emitFastDispatch(); } @@ -2251,14 +2250,12 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_m(ValueKind.REF, inl_mem0_reg, frame.inlined_mem0_base_slot); } + vfp_reg = allocTmp(ValueKind.REF); if (fast) { - // the stuff that would need to be saved should be already saved - // (only restore required later) -- as an optimization, should only restore once at epilogue if there is a reconstrcution - vfp_reg = regs.vfp; + masm.emit_mov_r_r(ValueKind.REF, vfp_reg, regs.vfp); // copy so reconstruction can step without clobbering live vfp inst_reg = regs.instance; mem_reg = regs.mem0_base; } else { - vfp_reg = allocTmp(ValueKind.REF); inst_reg = allocTmp(ValueKind.REF); mem_reg = allocTmp(ValueKind.REF); From 3bcd8b1b81c1e5c6c67fd4564b38b06703d65e4e Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 20 Apr 2026 16:30:15 -0400 Subject: [PATCH 47/91] Fix test expectation --- test/fastcall/test34_second_outcall_trap.wasm.out | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fastcall/test34_second_outcall_trap.wasm.out b/test/fastcall/test34_second_outcall_trap.wasm.out index 9c31161d3..9538df828 100644 --- a/test/fastcall/test34_second_outcall_trap.wasm.out +++ b/test/fastcall/test34_second_outcall_trap.wasm.out @@ -1,5 +1,5 @@ fast function fast:f +3 +5 - +1 + +4 !trap[UNREACHABLE] From 3629afd0bb303c581bc8ec56f37ee9d386e2d97f Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 20 Apr 2026 16:48:52 -0400 Subject: [PATCH 48/91] Remove too early of Instance.functions --- src/engine/compiler/SinglePassCompiler.v3 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 1e9dd61b3..1c54342e2 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -2259,11 +2259,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl inst_reg = allocTmp(ValueKind.REF); mem_reg = allocTmp(ValueKind.REF); - masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); - masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); - // Load instance.functions - masm.emit_v3_Instance_functions_r_r(func_reg, inst_reg); - def real_frame = frames[0]; masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); From 3d1733eba002a82b2e49f6a2322df5b8f0f41126 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 20 Apr 2026 16:55:12 -0400 Subject: [PATCH 49/91] Fix non-fast reconstruction --- src/engine/compiler/SinglePassCompiler.v3 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 1c54342e2..03cff9ae6 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -2240,9 +2240,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var prev_base_sp = int.view(frames[0].local_base_sp); - // TODO in fast mode, could use those registers (if not previously reset!--invalidated by future opt) - - if (whamm_config.is_inlined) { // XXX check individual configs? inl_inst_reg = allocTmp(ValueKind.REF); inl_mem0_reg = allocTmp(ValueKind.REF); @@ -2263,6 +2260,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); masm.emit_mov_r_m(ValueKind.REF, vfp_reg, frame.vfp_slot); + // load instance + masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); + masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); } // Load instance.functions From 73f8c2bac4b91844c1a5c66ba77a471fccf18bcb Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 20 Apr 2026 17:32:45 -0400 Subject: [PATCH 50/91] Remove unnecessary else if block --- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index f84d4aeb8..848240c01 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -1364,8 +1364,6 @@ class X86_64SpcModuleCode extends X86_64SpcCode { var h = X86_64FrameHandle.Spc(p_rsp); if (inline_ctx == null) { h.set_curpc(-1); - } else if (inline_ctx.tail == null) { - h.set_curpc(inline_ctx.head.pc); } else { // FIXME clean up this code // fast calls: append interpreter frame From e5b1bb1fb490ec19ad179fd71de7abb91796933c Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 20 Apr 2026 17:57:30 -0400 Subject: [PATCH 51/91] Streamline code to detect fast handlers in hardware traps --- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 848240c01..7bc179062 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -1365,24 +1365,19 @@ class X86_64SpcModuleCode extends X86_64SpcCode { if (inline_ctx == null) { h.set_curpc(-1); } else { - // FIXME clean up this code - // fast calls: append interpreter frame - var frame_wf = (p_rsp + X86_64InterpreterFrame.wasm_func.offset).load(); - var l = inline_ctx; - while (l.tail != null) l = l.tail; - var outer_fid = l.head.func_index; - if (frame_wf != null && frame_wf.decl.func_index != outer_fid) { - // var frame_pc = (p_rsp + X86_64InterpreterFrame.curpc.offset).load(); + // If the outermost function in the inline_ctx doesn't match the function in the frame, + // then we are in a fast handler. In that case, we add it to the inline_ctx. + // FIXME wrong if a fast handler is interpreted, calls itself with fast_call, and HW traps + def frame_wf = (p_rsp + X86_64InterpreterFrame.wasm_func.offset).load(); + def arr = Lists.toArray(inline_ctx); + def exec_fl = arr[arr.length - 1]; + if (frame_wf.decl.func_index != exec_fl.func_index) { def frame_pc = X86_64Interpreter.computePCFromFrame(p_rsp); - // TODO we probably need to reconstruct an interpreter frame's pc here - def arr = Lists.toArray(inline_ctx); - def narr = Array.new(arr.length + 1); - for (i < arr.length) narr[i] = arr[i]; - narr[arr.length] = FuncLoc(frame_wf.decl.func_index, frame_pc); - inline_ctx = Lists.fromArray(narr); + inline_ctx = Lists.fromArray(Arrays.append(FuncLoc(frame_wf.decl.func_index, frame_pc), arr)); } + // Check on the size of the inline context if (inline_ctx.tail == null) { - (p_rsp + X86_64InterpreterFrame.curpc.offset).store(inline_ctx.head.pc); + h.set_curpc(inline_ctx.head.pc); } else { p_rsp = reconstructInlinedFramesForTrap(p_rsp, inline_ctx); (ucontext + ucontext_rsp_offset).store(p_rsp); From 990221d9d99650f1aabbf23cda36f3c210e0de6d Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 11:35:24 -0400 Subject: [PATCH 52/91] Remove `int` directory --- int/Export | 9 - int/Export.v3 | 12 -- int/Export.wasm | Bin 8230 -> 0 bytes int/Interpreter | 9 - int/Interpreter.v3 | 403 ---------------------------------------- int/Interpreter.wasm | Bin 13303 -> 0 bytes int/InterpreterBug | Bin 14264 -> 0 bytes int/InterpreterBug.v3 | 25 --- int/InterpreterBug.wasm | Bin 5307 -> 0 bytes int/RiRuntime | 9 - int/RiRuntime.wasm | Bin 4434 -> 0 bytes 11 files changed, 467 deletions(-) delete mode 100755 int/Export delete mode 100644 int/Export.v3 delete mode 100644 int/Export.wasm delete mode 100755 int/Interpreter delete mode 100644 int/Interpreter.v3 delete mode 100644 int/Interpreter.wasm delete mode 100755 int/InterpreterBug delete mode 100644 int/InterpreterBug.v3 delete mode 100644 int/InterpreterBug.wasm delete mode 100755 int/RiRuntime delete mode 100644 int/RiRuntime.wasm diff --git a/int/Export b/int/Export deleted file mode 100755 index df2a0f18a..000000000 --- a/int/Export +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -S=${BASH_SOURCE[0]} -while [ -h "$S" ]; do - DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) - S=$(readlink "$S") - [[ $S != /* ]] && S=$DIR/$S -done -DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) -wizeng $DIR/Export.wasm "$@" diff --git a/int/Export.v3 b/int/Export.v3 deleted file mode 100644 index 2409223df..000000000 --- a/int/Export.v3 +++ /dev/null @@ -1,12 +0,0 @@ -export "fast:foo" def foo(x: int, y: int) -> int { - var val = y; - for (i < x) { - val += i * y; - } - return val; -} - -export "main" def main() -> int { - System.puts(Strings.format1("%d\n", foo(11, 2))); - return 0; -} diff --git a/int/Export.wasm b/int/Export.wasm deleted file mode 100644 index 65fa630c5756a892cb837eeb1aa7b0398e3baab3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8230 zcmc&(Ta08!d9JE+?XI5bTI_|my?E=iy~ZG|S=RP=J*@4iUGLgUxW?puvD@PwJUz2B zJG1REmWX?B96&&X6-<-|BCR5#<-rz+06|d{d5IHQ0VzBXiHArb!a|X9QKFy-MIh(< z{yN>$y}L%vQ)Z_7)T#5=fB(Pw>x}B1KdY5e`tNslch&sEdZb4WC!-NBDJ~=Ru)-hi zjLd0F@UemqPP8_ht~TWO37`>+vUx3PbwYn zSI$55#P;g2KfWJ6w!QhpL;Vjcll(Ke{1B?9nbKLVv?|I(Yu(7QOl6r#bVK1c!EF$WtQWS=8C!W8A{XV)ZN*~WTY>( zF13p1InJ{F#&G*dmE~vqXE(Q>G%6eR9$D{eRj%~T4;NQ9H&v0I?X7O8yzxz0t%A14 z7fzkN|ADuhdDqXs`#pEQ_kHjGz%M-b#t;7Dn||q+f8|$y?bm?xBaTZ}o0{ z+o8j6eZ<|n+#|Js$ecRqCU9gnRxfBI)){c){F;a{Pgy2YqCnB00b=<4tv^}~0i zOI`*1x<=c2yBdMF1jg^t%i z8?Sx7VA23V5MpW}PIa^KiY(Yc_{bJkBq8I9#N(3s1R}sNxy7U%ss*k-bGieLh9Xn1 z@yMs|Az73PwaEaF2T^k^ntxK<;HisoZ?K;in%On853IG4wh%6MUK_ye+vM8`qtl31kje@_;gs7C8`}17 zB%~A(moSX=qAHE65YSf?mV+d5*LRo>dH4ZmLKzOi_YBNVRUn*I!E`82)vm&WSM`>A zW2a@f=EoB*olYy^%ztqPR_Eb=CZqops>EGaf#EIYJ5&~;vwfNBwDK%mpvK{={DuuV zjOLF|?Z?Fw1XYC}u{8Mom3q7u^yA^&)}RYd#-|JB%jCRZzRC+?gW-j};TPg?Oe=nk zOTPlbFU~%dGL0;xDBJeyzXPT^gD!{FH%JU;eODBJh2P@q0~xajwX+yWXsvLf;k>!P zg$qVxySru0@yUFZnI%^sDD*SO&-`(hoDj(0f zH*=9#=JPdH={PBFkU-QfxW$NT+(FojvaU^^EL||-fr*GJnj&Ofl;(ts2toxXSBN4G z4Q4otBO;?ZX!Q(XVjL+bFQKfXQ^yxtrjr;`%a_G=4FPckPuKo;H~9qK`CUn)Yy`jo z#K4mg)ru=Isvt(`Dn%GlZwQ?U28628WfZGJ!OoN8G}s&lVM*1GG}s zS0bSG?@u#{+JNYBJrNJO`@C6mhk#R6YL@sb^7oydn}Ln7SUnL7ygkG+PW?WBr;v-t zu8T10Ch9=PZYvVQV`X;^%43jr+t3h3M|I{fxw_#c}@8|sdz_+3;hPD`_4ulx2 z`ZgW!TWy;~)N72H0!jCnHptXQrj|^bzTumfIf(TxiowxQv2vP6P9A0CQIbdDb6-sJ zNLm_*Q6*A<+%ZJCFtSfe@N;B7Y$TpR+1mMF8sUwoUtt@Yn#YD2=~F;+9OZFTgE-2J zBd$zk6p1nrkuQ-z_T3cw8-oAW^p#Es{Fr%I4Z5;Exv zut>}9a&spOF787*xE-^Gb^&A=_#0xbnlM;7kBJBJY z{R8}rD9LXzsXG^vt@#ulNKzaAkgEB)0c-`l;b!;4TNH>k%^huL;R0q9@aHE|?uZzdmqBXgKRx<{s|?;#eq6VQYkKv%;2NwFIHpphW?cXOlg`xCMx8GG72ZZX2K_0Gk|`Qg8P@ilWPRvc<;=tWbQb?A%1&O^RK4}oCfvKJFlUS1>-3jfjZWB`5 zTR=+cLr)9eZUYhO@`OW&>_U0vn*yw3$So$WfDGS=pxa3=&ddzLrx5`u&>$%h;rleaRNjC2`)kJ7k{V zxj^8y_ItttZIiwzJhB(O{(!WQ*_a6)kV`UolGJSU#jcr58sV71SK8efc~4q^RNuTHu6x+&jTQ~tR)0XrSF>N1rAp%vK&RTmXbaE!xL zrlE^NG_c7VS~>{>$$*J&g1Jd-NfN`2iX1Oy-WPsk3MUF0D zVlTs-ir%1?x=?~Am8+DwiDeE?Nr}|GP8Lf#8P^8F!I&iDFv)|y8GN{_qR!L}Wz1~doACu{#!%9bF;trO>9hymfW1a^XZz6yuwD})gnCd&F4=owXb%pJ4# zPbD9+QHFfD*ezc0irWHD7C4@2 ziOzdDtD00*$;&a`m$#^s1(+z*wg&D#r^ZtjOM|u*jh4=#K)UhNZmVApb1#25;mGOJ(`dNXew)CW99-D8ot6s zaN_#*_(%fX6HhcR1Q9QKq%^iPwq}mjy?I*vB%v9 z-l75aY}5@8J=yf3$H-ha5nl1Mlem+3bsjE&IgR5PDjs3neeoT7$(ThZQ^yjXQgGgg z-4xz}fQFkPoaIsWNL|1e^9DO7l8cdtr}z&GR)~0txhntX8oy+RuNz+8bC_^R4cMZF z<{I890N#$sZS1QOylJRkU(0q}M+_M%Sjw%qZNEl)X1gQ}?F=+Cu}jjjQKKc&)QP1e zoAuQlGkHtjbN(Oseth-P5x-&holpPg_5xfAci`?X&dP?9pF0 zO;*^C*E+cu)!z88rp7O+y|qU!H{pP_|4nSsIH+3zuTm++4}W&AQ2@yJk%|A~R|fh7 zpF@u}703MH)#7t{bNg&>cxrolb6e&*m>X_x`m?=_C;f^%^ykm@mseL-``hPVd)?1r z-Rj0pZ+-RAE0$4KfzSQRdvb2X{dS-KYVB-8-48eYgZ;Cs51#8S_itU^Twm`m z4@IXGw8QPk`{cvVN^kvqA6L#Bd~U)Q=Q&>VaZG|l9KG%KI~MLdc2_uY^1f52x%P7X_har%ZSUqI z1E}gB>-Qe*Z)2W%X?z~2^|}G$sy2SnkG-_rU+Hi6H=qEv?uniL@IC%&@;JBB8}`<5 U<@h>$e%8(^b diff --git a/int/Interpreter b/int/Interpreter deleted file mode 100755 index 55ced8cc9..000000000 --- a/int/Interpreter +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -S=${BASH_SOURCE[0]} -while [ -h "$S" ]; do - DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) - S=$(readlink "$S") - [[ $S != /* ]] && S=$DIR/$S -done -DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) -wizeng $DIR/Interpreter.wasm "$@" diff --git a/int/Interpreter.v3 b/int/Interpreter.v3 deleted file mode 100644 index 13f0a1b9e..000000000 --- a/int/Interpreter.v3 +++ /dev/null @@ -1,403 +0,0 @@ -export "fast:const0" def const0() -> long { return 0; } -export "fast:const1" def const1() -> long { return 1; } -export "fast:constN" def constN(n: int) -> long { return n; } -export "fast:add" def add(l: long, r: long) -> long { return l + r; } -export "fast:sub" def sub(l: long, r: long) -> long { return l - r; } -export "fast:fact" def fact(n: long) -> long { - var v: long = 1; - for (i < n) { - v *= i + 1; - } - return v; - } -export "fast:seq" def seq(f: long, s: long) -> long { return s; } -export "fast:select" def select(c: long, t: long, f: long) -> long { return if(c != 0, t, f); } -export "fast:if" def if_(c: long) -> bool { return c != 0; } -export "fast:nop" def nop() -> void {} -export "fast:print" def print(n: long) -> long { - System.puts(Strings.format1("%d\n", n)); - return 0; - } -export "fast:double" def double(n: long) -> long { return add(n, n); } - -def HANDLER_CONST0 = CiWasmTarget.functionId(const0); -def HANDLER_CONST1 = CiWasmTarget.functionId(const1); -def HANDLER_CONSTN = CiWasmTarget.functionId(constN); -def HANDLER_ADD = CiWasmTarget.functionId(add); -def HANDLER_SUB = CiWasmTarget.functionId(sub); -def HANDLER_FACT = CiWasmTarget.functionId(fact); -def HANDLER_SEQ = CiWasmTarget.functionId(seq); -def HANDLER_SELECT = CiWasmTarget.functionId(select); -def HANDLER_IF = CiWasmTarget.functionId(if_); -def HANDLER_NOP = CiWasmTarget.functionId(nop); -def HANDLER_PRINT = CiWasmTarget.functionId(print); -def HANDLER_DOUBLE = CiWasmTarget.functionId(double); - -export "main" def main() -> int { - def buf = StringBuilder.new(); - - //def prog = Select(Sub(ConstN(1), Const1), Add(Const1, ConstN(100)), Seq(Sub(Add(Const1, ConstN(2)), Const0), ConstN(15))); - - //def prog = AST.If(Const1, ConstN(2), ConstN(3)); - def prog = Double(Fact(ConstN(13))); - - //def prog = Const1; - def bytecode = compile(prog); - def val = eval(bytecode); - - prog.display(buf); - buf.ln(); - buf.put1("=> %d", val); - buf.ln(); - System.puts(buf.extract()); - - def f: Func.F = wasmCompile(bytecode); - def val_ = f.f(); - - buf.put1("=> %d", val_); - buf.ln(); - System.puts(buf.extract()); - - return 0; -} - -def eval(bytecode: Array) -> long { - def vstk = ArrayStack.new(); - var pc = 0; - - // print out bytecode - def b = StringBuilder.new(); - while (pc < bytecode.length) { - b.put1("+%d ", pc); - - def instruction = Ref.at(bytecode, pc); - def opcode = instruction.opcode; - def operand = instruction.operand; - pc += Instruction.size; - - b.puts(opcode.name); - match (opcode) { - CONSTN, IF, ELSE => b.put1(" %d", operand); - _ => ; - } - b.ln(); - } - System.puts(b.extract()); - - pc = 0; - while (pc < bytecode.length) { - System.puts(Strings.format1("pc=%d\n", pc)); - def instruction = Ref.at(bytecode, pc); - def opcode = instruction.opcode; - def operand = instruction.operand; - pc += Instruction.size; - - match (opcode) { - CONST0 => vstk.push(0); - CONST1 => vstk.push(1); - CONSTN => vstk.push(operand); - ADD => { - def right = vstk.pop(); - def left = vstk.pop(); - vstk.push(left + right); - } - SUB => { - def right = vstk.pop(); - def left = vstk.pop(); - vstk.push(left - right); - } - FACT => { - def arg = vstk.pop(); - var val: long = 1; - for (i < arg) { - val *= i + 1; - } - vstk.push(val); - } - PRINT => { - def arg = vstk.pop(); - System.puts(Strings.format1("%d\n", arg)); - vstk.push(0); - } - DOUBLE => { - def arg = vstk.pop(); - vstk.push(arg + arg); - } - SEQ => { - def snd = vstk.pop(); - def fst = vstk.pop(); - vstk.push(snd); - } - SELECT => { - def snd = vstk.pop(); - def fst = vstk.pop(); - def cond = vstk.pop(); - vstk.push(if(cond != 0, fst, snd)); - } - IF => { - def cond = vstk.pop(); - if (cond == 0) pc += operand; - } - ELSE => { - pc += operand; - } - END => {} // nop - } - } - return vstk.peek(); -} - -enum Opcode(handler: int) { - CONST0 (HANDLER_CONST0) - CONST1 (HANDLER_CONST1) - CONSTN (HANDLER_CONSTN) - ADD (HANDLER_ADD) - SUB (HANDLER_SUB) - FACT (HANDLER_FACT) - SEQ (HANDLER_SEQ) - SELECT (HANDLER_SELECT) - IF (HANDLER_IF) - ELSE (HANDLER_NOP) - END (HANDLER_NOP) - PRINT (HANDLER_PRINT) - DOUBLE (HANDLER_DOUBLE) -} - -layout Instruction { - +0 opcode: Opcode; - +1 operand: byte; - =2; -} - -type AST { - case Const0 { - def compile(w: DataWriter) { - w.putb(Opcode.CONST0.tag).putb(0); - } - def display(s: StringBuilder) { - s.putc('0'); - } - } - case Const1 { - def compile(w: DataWriter) { - w.putb(Opcode.CONST1.tag).putb(0); - } - def display(s: StringBuilder) { - s.putc('1'); - } - } - case ConstN(n: byte) { - def compile(w: DataWriter) { - w.putb(Opcode.CONSTN.tag).putb(n); - } - def display(s: StringBuilder) { - s.putd(n); - } - } - case Add(left: AST, right: AST) { - def compile(w: DataWriter) { - left.compile(w); - right.compile(w); - w.putb(Opcode.ADD.tag).putb(0); - } - def display(s: StringBuilder) { - s.putc('('); - left.display(s); - s.puts(" + "); - right.display(s); - s.putc(')'); - } - } - case Fact(arg: AST) { - def compile(w: DataWriter) { - arg.compile(w); - w.putb(Opcode.FACT.tag).putb(0); - } - def display(s: StringBuilder) { - s.puts("(fact "); - arg.display(s); - s.putc(')'); - } - } - case Print(arg: AST) { - def compile(w: DataWriter) { - arg.compile(w); - w.putb(Opcode.PRINT.tag).putb(0); - } - def display(s: StringBuilder) { - s.puts("(print "); - arg.display(s); - s.putc(')'); - } - } - case Double(arg: AST) { - def compile(w: DataWriter) { - arg.compile(w); - w.putb(Opcode.DOUBLE.tag).putb(0); - } - def display(s: StringBuilder) { - s.puts("(double "); - arg.display(s); - s.putc(')'); - } - } - case Sub(left: AST, right: AST) { - def compile(w: DataWriter) { - left.compile(w); - right.compile(w); - w.putb(Opcode.SUB.tag).putb(0); - } - def display(s: StringBuilder) { - s.putc('('); - left.display(s); - s.puts(" - "); - right.display(s); - s.putc(')'); - } - } - case Seq(fst: AST, snd: AST) { - def compile(w: DataWriter) { - fst.compile(w); - snd.compile(w); - w.putb(Opcode.SEQ.tag).putb(0); - } - def display(s: StringBuilder) { - s.putc('('); - fst.display(s); - s.puts(" ; "); - snd.display(s); - s.putc(')'); - } - } - // eager evaluation of branches - case Select(cond: AST, left: AST, right: AST) { - def compile(w: DataWriter) { - cond.compile(w); - left.compile(w); - right.compile(w); - w.putb(Opcode.SELECT.tag).putb(0); - } - def display(s: StringBuilder) { - s.puts("(select "); - cond.display(s); - s.putc(' '); - left.display(s); - s.putc(' '); - right.display(s); - s.putc(')'); - } - } - // lazy evaluation of branches - case If(cond: AST, left: AST, right: AST) { - def compile(w: DataWriter) { - cond.compile(w); - w.putb(Opcode.IF.tag).putb(0); - def hole1 = w.pos; - left.compile(w); - w.putb(Opcode.ELSE.tag).putb(0); - w.data[hole1 - 1] = byte.!(w.pos - hole1); - def hole2 = w.pos; - right.compile(w); - w.data[hole2 - 1] = byte.!(w.pos - hole2); - w.putb(Opcode.END.tag).putb(0); - - } - def display(s: StringBuilder) { - s.puts("(if "); - cond.display(s); - s.putc(' '); - left.display(s); - s.putc(' '); - right.display(s); - s.putc(')'); - } - } - - def compile(w: DataWriter); - def display(s: StringBuilder); -} - -def Const0 = AST.Const0; -def Const1 = AST.Const1; -def ConstN = AST.ConstN; -def Add = AST.Add; -def Sub = AST.Sub; -def Fact= AST.Fact; -def Print = AST.Print; -def Seq = AST.Seq; -def Select = AST.Select; -def If = AST.If; -def Double = AST.Double; - -def compile(prog: AST) -> Array { - def w = DataWriter.new(); - - prog.compile(w); - - return w.extract(); -} - -type Func { - case F(f: () -> long); -} - -def wasmCompile(bytecode: Array) -> Func.F { - def w = DataWriter.new(); - - w.put_uleb32(0); // 0 locals - - var pc = 0; - while (pc < bytecode.length) { - def instruction = Ref.at(bytecode, pc); - def opcode = instruction.opcode; - def operand = instruction.operand; - pc += Instruction.size; - - // setup for handler, if necessary (guest-level operands) - match (opcode) { - CONSTN => { - w.putb(I32_CONST); - w.put_sleb32(operand); - } - _ => ; - } - // call handler function - if (opcode.handler != HANDLER_NOP) { - w.putb(CALL); - w.put_uleb32(u32.!(opcode.handler)); - } - // post-handler wasm bytecodes - match (opcode) { - IF => { - w.putb(IF); - w.putb(RESULT_I64); - } - ELSE => w.putb(ELSE); // didn't emit handler anyway - END => w.putb(END); // didn't emit handler anyway - _ => ; - } - } - w.putb(END); - - // create wasm function - def sig = CiWasmTarget.functionTypeId(); - def wasm = w.extract(); - def fid = wave.new_func(sig, Pointer.atContents(wasm), wasm.length); - if (fid < 0) { - System.puts("failed to compile wasm function\n"); - System.error("error", "failed to compile"); - } - def func = CiRuntime.forgeClosure(Pointer.NULL + fid, void); - - return Func.F(func); -} - -def IF: byte = 0x04; -def ELSE: byte = 0x05; -def END: byte = 0x0B; -def CALL: byte = 0x10; -def DROP: byte = 0x1A; -def I32_CONST: byte = 0x41; -def I64_CONST: byte = 0x42; - -def RESULT_I64: byte = 0x7E; diff --git a/int/Interpreter.wasm b/int/Interpreter.wasm deleted file mode 100644 index efa0a14d209036a0fbc675b325e7378e090c282a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13303 zcmc&*dvIJ=dB5jA_H|dK4)*NT6<1emZko2b#>LMJZPzv2h|F`>=k}HEAp_c z2VJyQEP^c{STd481^XdlKP1@hig|jR0#x%&&UyxM?Zr7TBGf zU$|g7rr(Uuotj>1PNx0o_NjBNdM8f%owKd^bEo3-mgjuo{h<0e<)(kwjBVSF>ndd_ zM=6!VcizT>O$_DiLeWvSa)@Tz0J&_I@L$PuogA=oZV^4l@qLUdVB}m-C=`?`mkWhl z!2yY4exT?S^Nw8{#O#55u9(Lp`E#6tS19C*MfVYISuI!--iM^6E|xEr^B*M3WiM`a zS{JOXxw&|5zIDO2yiV=(Y^*GQy4LROpPX;DJ3FnxOmCM}$@K29f`VYyrlzbR(`+xD zwuX~tyl8DQ=_isF9?TUMm}le2G{d)EWg&HDVi7ZzLX z&eHO^^B1n&F?#*j%}1`={)X4T@jbuw-uFGUvZ~&%9#$VvkErm2>d=SOi4UvekE)NT zkE&ZfrjCAG-SY|c_TN_HpH!bx_kLRK{ERyAS@oFGpHtP(tG!=P`yW@ke@E>q{n2+t zYmR04zwRS4v?9w-8Y*dM%l|OBx3r~IBh#Kq5tRQ0BlQ(+jk|}m9Xg&?p;NYe?f4&% z$rb;T@{B%3r9_tn*92Er`~ym@M1KsOS=(*PG`d}FHL5ClIvIQm=z_V(3SLw3wHmW6 zzX*uGPh?S?M-Nnl_QutLJ4c88P| zs;C@XUbP|@#3KdT+wjpNSoY^+UE4v3j)AOlMXh>}pc-5qTn6cVRd~s*L{D)NIPijq z3xniLH5XYY+(YQ)B6l__G_anEHeo%jbZ*RcBNf^X1gMFI1+A)=&hR3?5xsX2Gn~ld z3`gVPY6nYD&e-7yCOV+1y+DnCqRk~;tuUnB+lgjYZD@xCFx&|3vVyKEzHj*-6$Met zSoyI3MRt|F5^cqrb`)?5g>Y?E1+T-_uk*hM)mmzJMdUUdZ6?NWupNT5LI>O6?#Y^l zc3o~L0kEqbVF>)%jc}-MWaw6zW<>?SONE|U%hlzGO-1Q^g6jw_$K5dJX;*uV zFh`Ue*tLBFfC|w90C2dTC^UGzsPsP`PBcUv4jUZ~LxXwj`T7wE5Yp=@3P!qtqI{z$ z|B{OGUtLi}Dym54)~Tedg=$F`Bl{ROnU5}7!HyA~*X3Yz#N(WN6aWIpe?mO2m{>5v zMYV97(QaNBuo+zneQX_4@j1)qEET#C<#lNwfCTCOpepe|1PPIf$MoQV4G*LLMc?O= z!PU{rd`6E_mcb3=DuVaHb;RyrKD2xI482kLpEh2k3_%s`3U-cE{EsER6_wD{mj77K z*Dx3K>|l4W3j;q$ypF0UR6%7W`VtrRL^oAir-Y%YV=e+NmoJzHmWMA3u|53*kjdAC zureVU8Ubp?9Ye)!Da=Cn$iM>!%>Q08RrYI3d}N4%=^`N7!QM0vSpMT?TPcr-$IvDn zYzN5vII}fZ_Q$U>_GATP3>wDoyAAABAd%G|jhW!4beq{tmkn^Uc?ACNr_64a;3}a~ zMI|Z+9LvN1bHVXeASw~FC&3941uq_gX6PF2*$h-Ba%vZn2^~h*2I3IJM;X#WmH*R( zTz5~dSX^Rf)f`RR(jJ1o-3j)A1+i@U8uxBkK`YmeGj`GVUW6)p$05?b+f5^$$2h@FYgl)aRJ{vEZ zh6E7k5ZuGUe?_2jD13Dr)_{{T2u06W+GQV)?3!+rUqb3mJsWXOY72>5PLx}UR*nt8 zZV}uwj5?ge`UBa=1jb}1!nFS|9a`nOzJSo1v3V1O=?SPKvT#S74|;dO0yKpdLP~1v zP^XE_iZi9yNRT`raa7a}17g??+=~D0L=qyo{g5VIKCuY5YAoW?mYB-)%cKP1YUnL^ z6Gi_LAtMkD3Xtf_j3Ci7CV)XI75~pf0*oJK3M-RjQs|mlFxM9?W4caoXoP7c7yX2g zs1R+VbvRLB8EFe*khGN_H`Xhq!v9 zeqWvaS7cS%M50FqD46aEfDnI;SXGx1+mxY@x?#itBdAHueqb6#bPzN}msESEJ_T=Bm>bvm@kN~*Uxan*oOVtOSS*4- zGq`btL77t!VDLb0WRd}O(5t#8$3PCI0nM6*i=tS&GxT^?$EbE+pg2GSa+Wye|GUTs zS|Qb{4IynL7T1Ucc13H0ksuU%n%H2AvZ$I3&7`V_0I{^wXfQPtXawm7d{e$vApX>| z7)Po@+MWpzFKk9m{u2`zIyL}O1~F6egL-PmI80nihj#T4l7yg(4Oby&ia6-nH_}73 zY>;KM1K0=}F3NAFsU#>3a8gAk=?WAc4(b6^-MVa?1BJbd2mlefs2#^lNYdqsFS;mH ziz!hQ9zCK(67ANUAd2cxm)3Y3Jzp4u=NiTeSsFRgC>X{HWGoLO$!BT6>{v51MSwpj zT;gT4;u|N(uNAo+><?{TI)M3};jSg62>bzkhPbP92wz|&t4gZ<~ zg1JZ>=>`ggSo=5+Sx9=(mrO&915y3}%SeD$Ez9zMDW-|DS`wL&f|hXzC&R?&84-d~ zaxytO;zfZ8;3^7`&xvLZ4_&lZoW)?AAs@n#B#j3Fi05fbRA3H?^pY;t@ezY_!uVlw zHpemFioT8jDc@g7+B1<_iWU|dICLkFG5c9=Wz2q#570&P>0VRHlpgLgW`u;l0>p3j zx+Ed@3JD3WT=Bm~5h7JY)(#67BdZqV`!r$Ev;2k68NF)ongSVAcsW$!36G*eE(0R zV1Zu(8MTpkf9UZc>A*|V0gSxVsKQlEx+-+jRo=v992V(ldE=v&&eKcr5bujHhX2aU zDM?~RsfG^zp?+-ycazr_$ZP1Z`Jy!CPS?Md7;$z9Yntk?7~f&?0v^ zsw`GL z0mhXcnWTgrV0&SrP z)r0oEhIXd3!U3C=w2>oIDY5Kvt5u**#V?@Phf~dMp;FwgPf*UIS6Naz^D3SD-Eo;%w$83RA z{LdStCuH@f`7P1wt+=)9rW~XK=MYP2hA7+IZQ#gnE((#Ix~F*BlsK@qU^X7?8-QoI z!mR_AjdX)6nh*q%fN9Q?(tk#fNFE1h+e0QcAvZZr<9gTf|A#noNZf9I&oCR2pEgVq zhOjD9mlsg8!61zZTR1KtIvDSuPqS1>x)#vMj}YmiAXG5_3y=bp8#L_mJ3MKq3M$d` zpKPf*5IKv3u3RAc(c@%O4>WikRf*79J-^5WE6`}I;zbe=Q5(I2zx*PO|F~QUPD6}h zpWz^`I0qtoSr5)Of>Yc$+z>7d*b>VlI$}x4+CmmrT*%dBNhW1oV5#k+I`V@WiY~Z% zSkBym`8cK~3>1X{B@7^Tl$grWOl8P;NJn09x`87Z$mDQTO%L3jIm#kP&X7S=7!rKl zS=`P`aZVa!Fl* z&?5!zq8D*hibM)H>I9t4qEeHy2QM{yP%?Q`S|DcG9QX!g0U^#aTO>z;97CYSm3_4O z*w23G@PYvr$MZ5mjoYj;;01rC?DSWUjAhC>T>W8Kn^*|L4J!U94@UQ z`s1Pyf_3ndP^n)IKVn#56$Y-|FB`6L&j7C9f!!UpCVpelU?bN1L^StjL~}nx{S8^e zTvFkZLqd`6krnn76`(2CjY`)?(d4Q8F2(01*P^@4-DWm_sQBF)<4_ zBr-phJV274B}a&DxUz^=+AskZtIaI>pE2;~AHi_+62F5RP{~M5B0}PCCk&jt(=iz) zLV1cv&AK5{%&1@sC+{Gp-T+$0UYNOfD`Akyml7U?%WLUyA317%kfnyeRZ=PKS8V1mkIgi-IzYo{r`qi8`EZuE)Aq!5u8Y z{za%Dm41qi(84^+lp>g$qd%A@(qM{@LxqD}C39JqLN;eH5g8CG$^-K&X%z|HK21i9)C zM~{9GEJTm-TPkTbP@YVqzLt@1_KzrzJSQX1%Lqzs{}YmMArr`9hJq9WA#57=xR+R|avZw#;=SC}ljZB<>;+ z@>@v>U_<`qpV61QzE*XmR?S6FMN+Hgf=0Je&1EXpfYH}j5Ke^P4RxxQty6K`3|Q3> zTBbmCf(CyXGm6JAGWau9XD}nxJ?KDZhDfH8WMPRC(Zn8HumXpr280EtGZ)+*?FL>2 zO$Z!YsOI$?x@1X@-HwMtb52G`SkXOF7D#1sX$Kyw+>;I(um6F|N#JhAGPD5Nlh{*egH92Q{U ziP(b%Q~^4SC-llJsgIG8m^?h-AFT8jWrzy>zqkBHyW_#@vYl-{ZhmBDaCH`bL$-5G z56SXB(xdc~?pq;d9hJT$V!DnGrvUBXMO1y=SyWTt_G8-F)%Nv|?MZ$=4lc_g-PmL4 zwf*=v`Jd=t>jzd3_sU-LV6S=A+9}_$Qr0haUvE;uKd%w%x4Kw=vu5NkGPAyyY5!}c z{nJeQXPNeoGVQ<0v|s2G{g3;4|J2v}%Qf7*)HnM5zTRJV_wd~{v;J;P|9M3JZ}6H> z;Sl0W7%fvl*W)nGb1ce5Pyl*?3BK=Jn+K+ydJA9Nx^-d<^?@1gSx#CPu8dFajX66 z^R{AMy}4YQtxv6+M!GKPwwB_Q*Xi19I|hvXJU+)Kdpul?ekq?E_+0AmH^JEl z{`NVCa@I#sl38xEHW#a3;e|)*ca>G|DIbI@||nFP+}h4~Q2x_mMI0wr=S|!W*ua z1zEZ@u*-9!_@1BKnj4iDZ?EXX;Onp>gD2}JmztgWTs&HD);q5$_xfihuiVr}(YWbr z`-sGFj;k)uqS1?w7}RaU(Zt=OM<|_Lqf_>Jn9SeRe9 zeoJOGFn(%jHa@*)_l` z9JS7ffcFf`#@eF@NoQiS;k}pjqj%;_|HiEuC0}!9cK&p2c64rR=iZygvcis=Q#S=C zNv=IQwX|Sp?i)(hIfGZ&4d~{q^lOugOZ8T~e~rEq@SC>wbA;XAvvBu3H?dw0?KiK7 zz31Rf{S+qgvN;8Cz3ziEO7#H_-m*rhSo*w3?$G*yDH(_c8PO%wibEY9>h+Tde~lIQ0rHbZX!D8eI^&d}`0`V;jQ9_8wmkpE|X)XZMMX;PpMbZ`}yKG`9CG z8^P;id*8aX7ab&QkDs567nrSY+jO#id~(zn-NaxYoM!@*Zj{M#wsXz;zm4c-OGtwU(O4>P_U~_kix(DgtX`nL8y(oeWZ> zbm@tpN6#>I_fTS$JsZ4djlGG`ca6P$Bk-Qx_ih9p+k4*@_ys%&h99@?nr|OPRWVna zeFr0U3Ql16Uv}Gk^Gpit;l6WI7M>tKu;q?gr@kB?LuCY`jB66_Cf~Ioxc%-;>#%2= zr;J!2wKIvJ9yHQSk~Jy@@LcOj^JF}Idu`!#4={ed1Hj~!6K88v^XDWiCK4W{^aU`r z%`AOfLPB=fK-%$ePZu(4cD^&c;Wie|n59kWF#%s#0D@@#zm$k|$} UVJ4#bn5!*t;*0?xt|x&11xP$it^fc4 diff --git a/int/InterpreterBug b/int/InterpreterBug deleted file mode 100755 index a88079884ac045c9524394129b06524883b48ba5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14264 zcmcgydw5jUwclsvOy(qv%m7hGMLmIm4%)zkhX$|c009ndfJm^WT&j5uNhB{P14gga zfdj~N)FSFF)_MiC)q2~4qBfu%G6@F7))KT9#d>)to*1w^RDxLM{?^{-Odi_W-aqbq z-HL?d|m%8YN`FY zXq}^9kDzCDZJTJ;f>zJpDTDpjrDu84HC{>c88G`x`>$(pn*E-rtMAIZlop@p)9zj1 zQ}SLjmSISXb!hjF+Hp3OGOp##oh?_RbUS9pPHFZ@#fupWpRfJfr1_}aI#`QMnu~ zRhzQGtt#%7v=het=U{D|(Cc3?_bO5dX6QTe+v7wyUO*$QKwIGR>Yqs9M%B+U_dQ#u zFt+4#Mek6I)6fdY`{IQ@btfAM3^7g4YsCr$%N6RL{HpujSr{OEUUVqQ19mNWK-H3` zRj67qo&jfCtX+${d|*advWG9#+dz2u5WQ6bG7r{z2x<2(wYco#JOU+spr;~m<{>@h zYq3IKPy_ctqd+FCSR$HJcoR!8s2Eq8gPNxIF!#!_geQInAM}t$@-;9TEF=*M!Ip6= z=3kA8q&5&QA_aN$vx2HkUI3)=-5VPtR;#j3jAU`mlkMJhv5g&SdtqU7b`y#lVcr5BepV; z!b;6qs&4jt|9lRu=gb2~E5n&DO42dA+t6x}@mRR49q?gpK8rf-@+l$O`Em3OLjKScYRH*e1CJ)1u&ZKn3vt!D3bEWJuGIjy5--sdu>b!#zg) z3lVJyi+?9SPQEtWUO0Ci%YSfhzQlKnD(7zCx%}N#qdTUb7D&Le0Kj8BkhcJ(Sg>B zMN8~AH{N)ZukGh?My%gt~krOy#4x{G2jP8OUsq;WVM+W5d85pk~e@jZ#plA#pHi5*x)#~we5 zyj@&m3Iy?)G(pAQt0=wb;_)7PhT{gkN?enTOnxqMD*kqD`H?7*F-bHE++ugH_9X%s z6D^#he9TWP%S=7(Yqut>Wvr4 zlXtmS7Z58+r9)P7vA_#FN*4t>G* z3Z^Uoxl$oXW z`U&)mye^(W3*&R;O|a%%Xcq zYX-${jbb;Fo(aMzydpD9yK?vMFqe+QU^{5?V4qm~X z(T*M0636`J3B8St5j7(sv}z1TIzw9rzEs*bZ`>xfX%yWAh|((9JU1S1+~tG6VkbS| zbri`NgD#9rk?28sg*@FDBBWJGLBJvlEIccvWhp!9LT!iY(+MZXhk*fmu<36UcX(*0 z6exCrTuN#){)lwbv^TS0T`%N;A8>SBYpEP7giId5E*#)DfOzZ~cND(MmN~dzlrtzeoC^XpAZ&sg6KSCP4`mnNVCo2H$L2_C3a5`%ol)=H=ZB61Af!(T7HO|)ge#vuXIUKGS6s;CuS^x zPRZnO-RU*o-(!D4KWStO7P=mx;G0$((^^`p1R-r}OVtKCxtO-Ri#oN=)0%$Z7?ec0 z*)g1wycf5>9y&2m?l#N4RAP={%|U%XuW!hv{-=S>TDuu_C>{F72^2xZhbF4E<)>9V z2)OmWd2S;PHZise`J{Wrz%g139aL+%w3gyisWu9}&qEkOVj%=?A~mq&KzLB05JXlkjllBZ@$ma|8mVhfuEkA@9Kk6JI>{^-xXi%C%@g z@_tBG;+709DDsOXKu0U6iwAGcJ$xIv4MHTI9e9YxEWPzh*am4Eb}6nH)F5_f3Jn3X zm4|9LidW(O!fBBe__}b#;mH84AbdNJO=3O<5pxR6pr~!L!lS{=Tf8=fy4*T^gx2eb zbtVE-$blE-nx?tDi)NC$0@01F6hW(L{kJh<+2k`hz-5u{QKyKi9P znRYqSR3EoFdM1@h@Oygi`Enaw2hvT#>@{A&JiL}HHu+4C8gG3@#A!DY7LDGu@u1w7 zSQJRem?-zTubfny#-k-XCT?Q|FoLGiXVAKf?!-{ys(uTN*H2?QvgBS=*6fFgwchT8 zYEe*WK;Pk~m9O)Jzd@Buz;KEV;J@ts3M|>1ORWww+9+I>ZVI z+scE028$$DNJkEe7)BJHO|}OA!JCf}qi2QmoC0!5`ohux)$rxwk%s%;&BO@r#klFJ zeaD5rQ2y|o9S)Dz3z}x01{B(`EJ&U3Ym9XN4!e22*v-5>Mh8q=tRU*$QR5-XMvw;* zyI@3wIc?1DG)8h~p7fFKFiGWs!T6y#3yWaj69x0}>`@dpjW~^v0CWyoq%{Or3YuvO zXj9-crcgNN^s`NcX2Z?1O_U}(;8po2cAY&^r3?M+-0)j61x^3 z&d&n6&x`mk1koUnI2W>c?5A~fW{@b<4_&D+9y&5b&9n_>t?L8??LYBe~Oc)yueT7JXGS?p*F209J6EC>P~Ij8p}`-PCygaEeeFpY*w~w#p^!j+hH^gM~0^2`+ z5_yGdjp83vMh#%+770C=g7Z6Iwb>1x?;zX8Q&app9)=U z`#kT2CHsuu12-;YL>oH+Cri9#CeOggm*Nb)Ye0VgEy{q+Me*l3uO#eNbTcbL#APM< ziOs#~n2z`Cv3;nBmojod!SYLDmB{Ym!!JMnzb>p!X1l2&4&ubD1{sZ0C#v>A>|O#u*- zc_Ll}d5RG9INvh}4H(BHdR%@%aE%ERXM_FtEu_?jp7Toxp{Ai0M5P2}QTKmSUy%Cp zX(hgJR*vCsgh;Cns5Fd~*ep+(qd4M?2o`pBj&wa+(y&(I?-oz6B4t7 zs``;YI<65rB1(d~pZuOeCT4MB;E5a*!2Q12>;}0zNRY4kJr{v{(Zzf&t#+CCg?khF zuAKBB-F9Lc!iLL?*7+jO-*o!Z2jRZt(ZIbk-Tb6DTAGVLwTN(xdlC?v-;uhd1_1ToDu^ z$n;cFO`lxxSx`Y2tjN>Z1$V?#fdWJd)+#ZMmmY{b-M^r9mO$V~qy2yh;`blx!b#Rh zb7^O}aYEnxSVnk`2aGGB5)22pHDExI+G5$hC9hoykG`jXvqy29IKe2)w_lj>!X0En z?*}6&_;Drdhv-2ySloRd2EnB!)J}F&LVOkxpBl{r+n9k0x`@@phS8?&Y};(rhy&w- z6WBofJd{KtNK=Etp7?Vvc^gm!okCphYZ0zW^TZa`eA2u~to!yUhaMtJPA5;i1a;^I%H z0-aOzMp)%JF=c7|J|;G`PnPE6c=%Q$kYXPHnN}#DPmX1DUC-wrhW{33fnD{|uhkF~ z*y+AR8x8BjGcsKS_%rfeZbp!UPcSI%2?;3Da<#>fN77y16m1IKF5EgjWbuhp$gbTh zdgb4K%-Z<`!&J;;2Ky*&Cf2CIA8-?XbBdN;X1saWGL!UNm8fmgthtGN3-L|jeUC1l z*cW&Yy~7>TbOX5sxB6N1LkV4vSAT*drX#2Xcw2I>{(!eLo5}64p|AiROZl6e-s5rK zJDZ5|M|@ZmRN>V-@EZ8>)%roVQAM{YiU-gnT_+G7p)ip&U^7Y0gpu|IrMLSTLbR2e zV!t0V`uI#fDPGs*V&HD`OK;djOCC6#G;q3;?~rR}xkP z6L^D}tx~QJS@MlsNC2Y2_I_TF4=?yia$0Up#liqF`}fn*pY(A5!qYazGWdG`sjk7K zrldi+s7g$U+>?H!0&dk45AxX<9p$(Sb>uMXK^QZN?xuu@$(f2Dh=&u`7ss z=!*wuEj~nxA&Mp8hU9+wz`#q3MTqYHE%*_?j?gCY{KEq-KynsVLqh$FO!s|snZz1Z zZ=K5D(sd&XV}5k`V~FGDr-uX9Q@eO@791;d)Z*DO*{vW%=x1>A`ZG2nULsF^-MxAb zs$g|ZHn~2}q`-$C>KKp$`O_&78G3IDM4JoAiN-%nZQj5nP=EuIoLt{Lry^xQx!lF@ z6{l#Xq|KQB$j0>*clr3Kw`9+yQYRUgm8z&f;DH)wmdX)zzd&}e9ML6pmoXOKu_TD& zA%_IKe*X7v$V=V0@cYJs_fn}Jw71|j7)J}f*5iLjDA-!FR2`!2L7xYPw-+!R9#Vsj zy8yq&!Lt+43D^ht1dt~wZ0Qh%y)FgWy8r{=wFOxrU=v_FU?-px@FCzRz-e1R_EW%b0BwMM0H@8yase7(5nvhM$AG^;Mki!B4^RgnIiCZ3 z43Om@8xOb>kl_fj)i`c;y=Y@c0gpIYbocozD*0LTo_rRaHk(Cr7P9D~n_0B&DhDgQ z2yuRp%mOYIJV)7KfO1ZhEdpc?_OLZ~GWN3@8G8Zn>RiU&1N;q;Kaa60fXZyF1h5Iv z4tNjnSAYUpqC;f%8ep2u!|DL*0e=PzwnK-2g@CCJy4&G{Pz$r*kb#nbvEbhYvZoCa zV{c*60z2#}n8WVcA7sDYAC`6opOZR+ZPLEr9_f?KC#0Ot`L;YjUEWgL(r3fA*QcJa zy?gwm%}Cnp-nI$$!WB*SP3vB;zO(!-d*`}C_7B&|^3msp$vC@Ze?@_;AJXNG zcAMknEq2H26|&=hp2%_Z3@djG_KlDp{qzI-xvM^7`48=JMjeNoKmPCo=VO2a zKmXL}Sv*1VE^d;ppE=Tb^Xg&Fwv2M+?O&8DpI)&-8G3$`GJ0o|GHF&snf}o_WzJI@ zm6EEH()&C2NU0m%lrpqV>B_wu*|4qCq%mFBNzcz-A$|PXIw|8j_e*0I=E&tAA7asG zbZPB{4@imIlhT1*gdDH&B>yX_)r`R5xbHH9y_vASZxi30?b#aCL z;GD4i%iM|#$Ka-n(RW5NDiXBKiy8EsZS&!ai8+7ER;z6f^ zdopjl{}yLuneP1QkT&OUhO|4|?myt%xBQ^UxFYAh(hrzdoo8qe=u|W z#PL~oJ{ZZ$Sh{gg{tFXbs~=k7`kiCl;7dP0=-PF~Aa{GjsWI|r3rlh4h}x%rCB zMGM23ZM)VDegCrY!+I`j8!BJEXK3lZjhP+s2L@gCt72E+<*@7hMNdeFT@OmBFAv$2 zKb*8pnX}Tq=wjX8a`7-}*Toa1%=(kkn*Yjk{_L9Z&KKSo?|k*n3C{N}ndto6HPfB> zo91U#Z5ola{C{lrS5n1xHQ~s7zI?ADR<~hce z-D10@Y`HBuwcVCT9<;qS^?+^v@@cja>prwid%W0Q_xMQrn(+_W*N=a~zGeKM?0-H{ zEDt_8QqG;wBo|EhxxBFWpuD+wn0w2Fq3-J{huRla4zVA7@{nWdxt}3A!q))|e&q#} zqPm7Pvdz*4M*lszgUd1JBZ&sA`AXfTa9#)NiwybppS>PO;*?=NI31H1RL3Rw#hB?`Kal zmF>kJ?uf5|RD@Wvfq8J?_yHQA8n70zZ@(kJ8Z(NR>MWJ2vr3sCfBFc}A3p%qgGxbv zE!*JQ3_4L(Jy>NPx5^sbpydX?QYp@-C@Zx$GQ(cV8s#FkTP7`#O3nw=1C}C2H8VSl z0(PPO4$98}XHb_UnGKe3sz`P=3FS=5!LA4V9I#!=K$N%R^vhs5Hai<@bFiyyPIfKY z#i&=>WL5*X747wCKZ){}HU+dY0a>8$WT!FTVRtf*J%e2Y7-!F7SJ?-#Y3S4KE_M&v zyHM^!`2ork04BTGAQ|gXUIMrbkPnzHpTp+LgV|HEn>idVHWZOK$C1S@cR1KYv?l`! zP%lKe0C1C|uB@h>&90Ax!j0h&zNam%8oO))tEsPvuyNH5b)j)}O%>Jkp_=jI7Bn=} zHjP_W6RxVM9T$#_t1pYxEDMdBUo(GceWa!?MC;NGRv4vXYGw76wV^PJG!#d|HT6|&!EKG90c=!-BC{JAzKa{#;+p!(>zhL1=?#@3 zR?Qa|3ohr^r27|_0d=n!SUI(#BGlA0wX!md0<`+5Uk8f!y!Auv+ePsKBu%^k%0+XdD+p-6Q@rNBBB_EYjrB3D(6D-PAw6gQStaQmc2 z6E#>W$-<%9hKlLfx^nm#3oosoSpzSuxt)kKf!e(Cn@JE1q-hIQ7-m&j!!`BG z(5%!#WtDI*S~owmcurX(ug++O{zUcvXo@E30j6m7avHO08_LUSzfmv!9Lrqu738Ad z!X65T8^TQN2q(p55Zl}YL3?Y(wGD8IrIAL~z?D`EEpkOSG~ULlL(S8xxxN?Il{NAq z*pOA_M-Ic0#^wQVrC@gesQn7ye!xXI2dV!-lnViw$b=K*A&SgG)d)ayA z63byTw@B<=HuNO*kIunuhUFf&vHRG0ZFcr8{_SU@kK0)uJMRR2e;*ti1Uv(7mzx|B zSN}gB#Uw+zp;x(rnq@VWp=q}*422tdBMR~wj1hAs=Gz&~rw6I)5sez*0ij9}`L9yZ zi4Tnz6d|@)0ZB$i)Gf-t0*{q zYWv5i|8BLhjZ6)y)a2u|{s;6Jjt}8Os>Wtj%-{x1?U8_R2*EX6Rv%F*eyfoNwKpbO zQ4G`gdgK-iF5cKjT;7i>C7rNK7cZ`P-;$s92L{BVefH-Pv~x^>u2Rhyq=rL_L*Y<;MTo0{ int { - def x = A.Z(ay); - - x.foo(); - - return 0; -} - -def ay = A.Y; - -type A { - case X { - def foo() {} - } - case Y { - def foo() {} - } - case Z(a: A) { - def foo() { a.foo(); } - } - - def foo(); -} - - diff --git a/int/InterpreterBug.wasm b/int/InterpreterBug.wasm deleted file mode 100644 index dc25a1547290bd15158034dc6f6fc172e5b574a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5307 zcma)ATWlLy89wLC&CWRSB~Ysax2+euS| zl(H0d#YG?x2q7WyutMM4OP*L~O*w0!@6W;{+?p^Y=1 z|D5yRuj3KPU|k9!tw1ot+)Jxw!3!s{;R6Nq~yh_{wm^RgX}x$Eb2g zF&Edpm29O!(!X(~opyxaWr>!JZtu2`c0Ih=@7}tSZVP4CtAi`I`psb~r1KW(@&H=7 zLVBJfl_PzDj}rvAi6HPDFA${?)b>iMT=M*qH$hk62SG4_PdNx=$-PT_WKSIPzRi$) zSb10peonCCrJZ5_w($J*biLcZt%NsBuC-Gs%J&#o7#Y?+bn3$&`RK<^*FS#dxlerZ zQ~N)?Z{ahajX!tx_~)NL@P!w?xM*Hnnz;81*7bQQcg)-01bj*f3yhXpv})2k$_~Hm zE^1-$iAvQ_%LOIEvd|(5<|03Qm1GN}qOuX;8{fb}`a9+o+Ff=Ry(p}R5Y%$5<{R;n zyNH!<+_ovTA{R1d!A(o;FDTc@SUHPYX+qN~5;ZTU@J!e;U*7$uvWAYMxzn;NsMsAwkMyn?B(*^ZAqFYdJ(#^nk3yNcA z!C%{5%V|OVrdYlX#QVjPSa8HF9ml5{{+1Mw9&|Y^9uTs-X#UMa@6k6~H0dD>P)DA% zC}b6Lis55gusWIS=qS@18STfuT0~?Jz*APc3kZ-O2fQ2X+6{CN&9>qIo~@`b49$;N z6A|svLG0(d(G(G}W!hh(fbV3kuR@4IVpj6}>>Qy8s=C})n$ z1R)umr$ixqQ zoyUYA%xjcQCXV*aSrE0gA32QVw(ID?oR=ZpCsdqfh;jr1hbv9X=wLPcrDe>aeVgC~ z^=G<~hhQ#&)$pel=}ngYh`w#Eppbt>M`#dQWHl)%wuUem zJIGDy1XYhZK`BNffFaZrw3rSA1)lo^bqp6!wiG}o`OIX5QbH7wJG@EqRqQ~cF#OBQ zkSeP?YBB$?NwrDiY)rWV9p4Sj&qy^r*@CULs=?yU_67;8BBJw1ZB8X!HSgmu*f46? z!ogvaiAxt3FI|y*?2lYBR$+g&4Y~}BPzC@wHLeO7Pxke z6f`9R5NftDFd#Iu!nd@=e-^j-@7p&xq)*cybIWbd3FE z=y(&c<(MNCP?N|2Lg&1H5}h~4Bc1p7-%~KT29Q)W1se^eHsypyA1$%jT3Io4j1dIm zjf|W*r0gG_*GS4~h}5bTX%dO8 ztt@wJ5ek$cdlgR@ut7`8H%>NRBLFDeXugKt`>oBH}JqG$BH6qg8yPJNai0B5DU-=+YCUPRXr#K z%AFjF2OX|ixjZT1_RMf)t)}iun_GkiH)J6dkV~R|zExeG^DduY*oEKc zx`0pMhc$9cspi4YdAWM#43#Tyk#MAzXWqjoE|XWXMC9%%5M$MXZ|1j5bt5_s$Q@#j zIvYv@kq2|`cW4N3J=Fy^vcjL>s)arxe2X>mpPCl#)6>G`Y2h2nK07V^=)`DN_+zso zItku3gFH+MmnMZbJ}DIM)g0z!M}!ldh-KdQow2?jo#gonJ}5ZLWUQA{Ye$o|Ezp5u zQIs*PN5RS1MS7zZP~M=bkX#gbcnXi!Tp{c!%GJMeS=bg>g0IV3@uR(YC|c%y%%6!h z>W9jl;iYYcjwx*|Ti=2=64OQu0QwU|oTcaQH%6RCJw-x01+k_UJ^5`A|QhsvKwaDsd9zn&@zNmlx5|?Dr7wM)|J_ zpiq&7-y2bohe=x`2yBoh+;7=D|xd3Yg zC<^ezZZ5JoIl249DNg2|v{)5qvjuo)T8DYwjOr%O1j=$=_QS{-sra5 zX=8}CCxpUvS6V&+ZD{#Oj-Aay{*1pJYI^xR=R40yxeLIjfr)RX<%#`)LP)7PZyQ z1)e_rf_|3mw6~fJlQ!-IAH?-$Dhson$?g?-2MUQK9!R_3S;2 zoE)v_HH@;${4I=Qm-$N=*RLZm-G=Aa`8|n0d!YkA_WCKlU);P=Ur(ByVCr)7@@8k) zTu1${d#lIYbUoSW@x?C?F@#`<$K{2#hnAi94gbrI?IE} z0|ird-ST!L?G2mV&eZJX=J`f_6`}_>R~kvDllBMIxq<_uU)mgATD{2cc%n%rzzd(H zcAE63_ZO)B6vi&WN$tlS<9)Af2v1vF=cLZ=&<8i%Z| zSvsO7ki7GSu9wr*i%IWrv9Y{8#Kw{Nm7B@+?yZ#}%+2(#lWn|l^r%(je7k!sX^$V< zoq?VyEM=;8cNjm@s9w#Aw#BsqR~|!>AZio@Wa04xPuYAk-Cnwx^iNnq)Yp2_Bf^t* KBi$Zm8~+2|nOxHV diff --git a/int/RiRuntime b/int/RiRuntime deleted file mode 100755 index 716d1b2e8..000000000 --- a/int/RiRuntime +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -S=${BASH_SOURCE[0]} -while [ -h "$S" ]; do - DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) - S=$(readlink "$S") - [[ $S != /* ]] && S=$DIR/$S -done -DIR=$(cd -P $(dirname "$S") >/dev/null 2>&1 && pwd) -wizeng $DIR/RiRuntime.wasm "$@" diff --git a/int/RiRuntime.wasm b/int/RiRuntime.wasm deleted file mode 100644 index 049ef40aa3e69f8aebd5db3e2624642b3499f831..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4434 zcmb7HOOISf6|SmVb#Hf9kGmYlPGFL{t{#G5XR^vH6qJE)=aH#jFFj4GnJ(}OKbQy*wZ)354k6D^JAvuz2?1U_A8=Q zdaby&J9t?MGwi+4FQlmdk$FUr)_*F0;?tiwzWUkEef|sQpZwy5FMatdU;SF=>)-h1 zqie@5KJ~3LPd7e%4LUA9CFMB0@gtC{NxblKIu7jFy6zfRYYGbix!q2Kcvg3@N`vl)TIn>@9)kieecDkv$Xq2|uRO7N zS4p>`rCdono1j)BQYET|^!UT8-XaLITn}t4~D{PmcY>L@Qo}+1kir z70AjElASzc3WXxd1*;J+}Z7f!-fL*}P3;PjUN!ZHUM8}IT znJ1`CLVC*((rY<@j*AfJy*O$FC7$~Lbp#EnS_-g}eO5AMsUeG~9o{7SDo@~%wSRww zBGMYG?&OcJ)Lsh7{t+$Ex3vwwBiH;=iMzI20gJE}b6rU&b31{Yx4E7;P-h1uJCJ9-K}}$S@uY8&5@OeXK!*%VL@oO$-z(y zAmL^oL!it7Cvs9DBgg{Rj5|Fm7;dJJa*x~JP`$~R(YexO@)I(;kWbDbrH;8DOdW3` zx14j70x*dRAojaR2(rru9aUwTH|H~ro^mKe%l?I)i~$r?Tj7p@N}FoJqmS13+FnI7 zbc_*$%LnO_6_o6|EUo|{N+LwSh%hIZC{ct)4~i@5qscV4A65K}JwZqtXbn*L3dbyk z%BU+dOhE(N$VgX=|H3}d5czeqP03#LA|**lnd9VE>;_EaBf*i_gDqH)EKw(I~*X2|hsu;6~ z=K4L>7uy#|IF3*{6*29T{# z4+#OdQ$X=WhA}JGmn6boU0lUmQ+K7!5wRf*RZ0cylBr*EAEJ3lO@=as%SrNwClc8M z&5hSfl&k7e5=D;UowQ#1y5o7x6Oyi{Jte|;o?rr2XN?#GvA|{B#HU*~EHi+{Ct|nX{xbhYmM`@YxZ;awPMWrf4?w+Wipi0E%)F`y}T@FeQ zu}7T^&_L#)ockRb0zyx?z(xi92BQ}K2>Tv;ls+^q^uyCa^R!3<6dXtm|I!SNCvFl;LB{pT;)z zLlrLYGB(2`)JE$uw$P2jj2Q!g{sa?i)SKU$YM%BK3GWm05I(A)#RQd_c(f<$F2&*42Nik;!0w=?t`y?);hcm4ClwXNs(dK<-)8@v5}u`vXf5DM?B5zkWf8(UEC4@jNwZ4Qfpf9Bh)<3V4JL*~-XsMp`R z>UUo#Vb;G`^sW{I?9&UT#jBP5GobV8B5QuDk{T47#h}=Mp{|d Date: Tue, 21 Apr 2026 12:40:00 -0400 Subject: [PATCH 53/91] Refactor SPC --- src/engine/compiler/SinglePassCompiler.v3 | 164 +++++++++------------- 1 file changed, 69 insertions(+), 95 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 03cff9ae6..a6a606d41 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -138,25 +138,18 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def gen(module: Module, func: FuncDecl, err: ErrorGen) -> bool { this.osr_pc = -1; this.err = err; - return Metrics.spc_time_us.run(gen0(_, _), (module, func)); + return Metrics.spc_time_us.run(gen0, (module, func)); } def genOsr(module: Module, func: FuncDecl, pc: int, err: ErrorGen) -> MasmLabel { this.osr_pc = pc; this.err = err; - var ok = Metrics.spc_time_us.run(gen0(_, _), (module, func)); + var ok = Metrics.spc_time_us.run(gen0, (module, func)); return if(ok, osr_entry_label); } private def gen0(module: Module, func: FuncDecl) -> bool { if (Trace.compiler) OUT.put1("==== begin compile: %q ========================", func.render(module.names, _)).ln(); var before_code_bytes = masm.curCodeBytes(); var before_data_bytes = masm.curDataBytes(); - - //masm.emit_debugger_breakpoint(); - - if (fast) { - fast_operand_size = uleb_size(func.func_index); - if (Trace.compiler) Trace.OUT.put1("fast operand size: %d\n", fast_operand_size); - } // Reset internal state. regAlloc.clear(); @@ -181,7 +174,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Push initial frame for top-level function state.frame_stack.clear(); if (fast) { - // push a SpcFrame representing the interpreter frame already on the stack + // push an SpcFrame representing the calling interpreter var interp_frame = SpcFrame.new(null, module, 0, 0, 0, -1, null); pushSpcFrame(interp_frame); } @@ -189,7 +182,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl pushSpcFrame(initial_frame); // Emit prologue, which allocates the frame and initializes various registers. - emitPrologue(); + if (fast) emitFastPrologue(); else emitPrologue(); // Visit all local declarations. it.dispatchLocalDecls(this); @@ -366,58 +359,59 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (!cond) bailout(Strings.format3(msg, p1, p2, p3)); } def emitPrologue() { - //masm.emit_debugger_breakpoint(); - if (!fast) { - // Allocate stack frame - masm.emit_subw_r_i(regs.sp, frame.frameSize); - - // Spill VSP - emit_spill_vsp(regs.vsp); // XXX: track VSP-spilled state - // Spill wf: WasmFunction - masm.emit_mov_m_r(ValueKind.REF, frame.wasm_func_slot, regs.func_arg); - // Load wf.instance and spill - masm.emit_v3_WasmFunction_instance_r_r(regs.instance, regs.func_arg); - masm.emit_mov_m_r(ValueKind.REF, frame.instance_slot, regs.instance); - // Clear FrameAccessor - masm.emit_mov_m_l(frame.accessor_slot, 0); // XXX: value kind - // Clear inlined whamm instance - if (SpcTuning.inlineWhammProbes && SpcTuning.intrinsifyWhammProbe) { - masm.emit_mov_m_l(frame.inlined_instance_slot, 0); - } - } else { - // Advance IP past the fast-call opcode and spill it - def r_ip = X86_64MasmRegs.INT_EXEC_ENV.ip; - masm.emit_addw_r_i(r_ip, fast_operand_size); // increment ip - computePc(-(fast_operand_size + 1)); // compute r_curpc - saveCallerIVars(); // save r_ip and r_curpc - // XXX why do we have to save? - // 1. r_ip = rax (clobbered by `div`) - // 2. m_curpc = HW trap reads this - - // spill VFP? - //masm.emit_debugger_breakpoint(); - masm.emit_mov_m_r(ValueKind.REF, frame.vfp_slot, regs.vfp); + // Allocate stack frame + masm.emit_subw_r_i(regs.sp, frame.frameSize); + + // Spill VSP + emit_spill_vsp(regs.vsp); // XXX: track VSP-spilled state + // Spill wf: WasmFunction + masm.emit_mov_m_r(ValueKind.REF, frame.wasm_func_slot, regs.func_arg); + // Load wf.instance and spill + masm.emit_v3_WasmFunction_instance_r_r(regs.instance, regs.func_arg); + masm.emit_mov_m_r(ValueKind.REF, frame.instance_slot, regs.instance); + // Clear FrameAccessor + masm.emit_mov_m_l(frame.accessor_slot, 0); // XXX: value kind + // Clear inlined whamm instance + if (SpcTuning.inlineWhammProbes && SpcTuning.intrinsifyWhammProbe) { + masm.emit_mov_m_l(frame.inlined_instance_slot, 0); } - // Compute VFP = VSP - sig.params.length * SLOT_SIZE masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); // XXX: use 3-addr adjustment of VFP masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); - //masm.emit_debugger_breakpoint(); + // XXX: skip spilling of VFP + masm.emit_mov_m_r(ValueKind.REF, frame.vfp_slot, regs.vfp); + // Load instance.memories[0].start into MEM0_BASE and spill + if (module.memories.length > 0) { + // XXX: skip loading memory base if function doesn't access memory + masm.emit_v3_Instance_memories_r_r(regs.mem0_base, regs.instance); + masm.emit_v3_Array_elem_r_ri(ValueKind.REF, regs.mem0_base, regs.mem0_base, 0); + masm.emit_v3_Memory_start_r_r(regs.mem0_base, regs.mem0_base); + masm.emit_mov_m_r(ValueKind.REF, frame.mem0_base_slot, regs.mem0_base); + } + } + def emitFastPrologue() { + // compute fast operand size to skip over + // XXX this assumes the func index is stored in bytecode as its most compact LEB + fast_operand_size = 1; + var n = func.func_index; + while (n >= 0x80) { + fast_operand_size++; + n >>= 7; + } + // Advance IP past the fast-call opcode and spill it + def r_ip = X86_64MasmRegs.INT_EXEC_ENV.ip; + masm.emit_addw_r_i(r_ip, fast_operand_size); // increment ip + computePc(-(fast_operand_size + 1)); // compute r_curpc + saveCallerIVars(); // save r_ip and r_curpc + // Why do we have to compute and save? + // 1. r_ip = rax (clobbered by HW `div`) |\ can validation catch this? + // 2. m_curpc = HW trap reads this |/ or hidden by arbitrary outcalls? - if (!fast) { - // Spill VFP so emit_reload_regs can restore R11 after calls - masm.emit_mov_m_r(ValueKind.REF, frame.vfp_slot, regs.vfp); + // Compute VFP = VSP - sig.params.length * SLOT_SIZE + masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); // XXX: use 3-addr adjustment of VFP + masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); - // Load instance.memories[0].start into MEM0_BASE and spill - if (module.memories.length > 0) { - // XXX: skip loading memory base if function doesn't access memory - masm.emit_v3_Instance_memories_r_r(regs.mem0_base, regs.instance); - masm.emit_v3_Array_elem_r_ri(ValueKind.REF, regs.mem0_base, regs.mem0_base, 0); - masm.emit_v3_Memory_start_r_r(regs.mem0_base, regs.mem0_base); - masm.emit_mov_m_r(ValueKind.REF, frame.mem0_base_slot, regs.mem0_base); - } - } } def visitLocalDecl(count: u32, vtc: ValueTypeCode) { var vt = vtc.toAbstractValueType(module); @@ -822,16 +816,14 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.bindLabel(ctl_top.label); state.resetToMerge(ctl_top); state.ctl_stack.pop(); - // case for END for fallthrough at end of function? } else if (ctl_top.opcode == Opcode.RETURN.code) { state.emitFallthru(resolver); masm.bindLabel(ctl_top.label); state.resetToMerge(ctl_top); emitProbe(); - if (ctl_top.merge_count > 1) { - emitReturn(ctl_top); - } + if (ctl_top.merge_count > 1) emitReturn(ctl_top); state.ctl_stack.pop(); + return; } emitProbe(); } @@ -867,7 +859,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_br(ret_label); setUnreachable(); } - // for CALL, FAST_CALL, and RETURN_CALL def visitCallDirect(op: Opcode, index: u31, prop: CallProperty) { if (op == Opcode.CALL) { Metrics.spc_static_calls.val++; @@ -2159,7 +2150,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_br(target.label); } } - // Return includes epilogue def emitReturn(ctl: SpcControl) { // All explicit RETURN instructions branch here. masm.bindLabel(ret_label); @@ -2188,9 +2178,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } else { // Restore VFP from interpreter frame masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); - // In fast mode, caller ivars (stp, eip, func_decl, instance, mem0_base) were - // never clobbered and need no restoration — only r_ip is reloaded by emitFastDispatch. - restoreDispatchTableReg(); emitFastDispatch(); } } @@ -2228,14 +2215,13 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def restoreDispatchTableReg(); def restoreCallerIVars(); def computePc(delta: int); - def computeCurIpForTrap(delta: int); - def computeCurIpFromIp(delta: int); // Emit code to materialize stack frames for each inlined function. def emitReconstructStackFrames(frames: Array) -> int { Metrics.spc_static_reconst.val++; masm.emit_inc_metric(Metrics.spc_dynamic_reconst); - var inst_reg: Reg, mem_reg: Reg, func_reg: Reg, vfp_reg: Reg, wasm_func_reg: Reg; + var inst_reg: Reg, mem_reg: Reg, func_reg: Reg, wasm_func_reg: Reg; + def vfp_reg: Reg = allocTmp(ValueKind.REF); var inl_inst_reg: Reg, inl_mem0_reg: Reg; var prev_base_sp = int.view(frames[0].local_base_sp); @@ -2247,25 +2233,24 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_m(ValueKind.REF, inl_mem0_reg, frame.inlined_mem0_base_slot); } - vfp_reg = allocTmp(ValueKind.REF); if (fast) { - masm.emit_mov_r_r(ValueKind.REF, vfp_reg, regs.vfp); // copy so reconstruction can step without clobbering live vfp - inst_reg = regs.instance; - mem_reg = regs.mem0_base; - } else { - inst_reg = allocTmp(ValueKind.REF); - mem_reg = allocTmp(ValueKind.REF); + masm.emit_mov_r_r(ValueKind.REF, vfp_reg, regs.vfp); + inst_reg = regs.instance; // |\ use regs from interpreter + mem_reg = regs.mem0_base; // |/ + } else { def real_frame = frames[0]; masm.emit_mov_m_i(xenv.pc_slot, real_frame.pc); masm.emit_mov_r_m(ValueKind.REF, vfp_reg, frame.vfp_slot); - // load instance + + inst_reg = allocTmp(ValueKind.REF); masm.emit_mov_r_m(ValueKind.REF, inst_reg, frame.instance_slot); + mem_reg = allocTmp(ValueKind.REF); masm.emit_mov_r_m(ValueKind.REF, mem_reg, frame.mem0_base_slot); } - // Load instance.functions + // Load Instance.functions func_reg = allocTmp(ValueKind.REF); wasm_func_reg = allocTmp(ValueKind.REF); masm.emit_v3_Instance_functions_r_r(func_reg, inst_reg); @@ -2312,9 +2297,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Step vfp_reg by change in local_base_sp from previous frame and save if (vfp_delta != 0) masm.emit_addw_r_i(vfp_reg, vfp_delta); def vfp_slot = frame.vfp_slot.plus(frame_offset); - //masm.emit_debugger_breakpoint(); masm.emit_mov_m_r(ValueKind.REF, vfp_slot, vfp_reg); - //masm.emit_mov_m_l(vfp_slot, 1); // Save PC def pc_slot = frame.pc_slot.plus(frame_offset); @@ -2340,7 +2323,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Guards compiler code with frame reconstruction (if necessary). def withReconstructedInlinedFrames(emit: void -> void) { if (isInlined()) { - //masm.emit_debugger_breakpoint(); if (frames_reconstructed) { // FIXME this should not happen (but does): // - in the case of deep nesting when one layer is a Whamm probe @@ -2351,23 +2333,22 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } unrefRegs(); frames_reconstructed = true; - if (Trace.compiler) Trace.OUT.puts("performing frame reconstruction\n"); def space = emitReconstructStackFrames(snapshotFrames()); emit(); frames_reconstructed = false; if (space > 0) { if (fast) { - masm.emit_addw_r_i(regs.sp, space - (FRAME_SIZE + 8)); - masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); - masm.emit_addw_r_i(regs.sp, FRAME_SIZE + 8); - //restoreCallerIVars(); - //restoreDispatchTableReg(); + // reload VFP from the deepest inlined frame + masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot.plus(space - FRAME_SIZE - 8)); + masm.emit_addw_r_i(regs.sp, space); + + restoreCallerIVars(); + restoreDispatchTableReg(); } else { masm.emit_addw_r_i(regs.sp, space); masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); } } - //masm.emit_debugger_breakpoint(); } else { emit(); } @@ -2808,7 +2789,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } state.frame_stack.push(frame); // Update cached copies from new top frame - if (frame.func != null) it.reset(frame.func).at(frame.pc, -1); + if (frame.func != null) it.reset(frame.func).at(frame.pc, -1); // null = func in int module = frame.module; func = frame.func; sig = if(func != null, func.sig); @@ -2842,7 +2823,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl return !isInlined() || ctl_base_sp == 0; } def inlineDepth() -> int { - // subtract extra 1 in the fastcall case return if(fast, state.frame_stack.top - 2, state.frame_stack.top - 1); } def snapshotFrames() -> Array { @@ -3606,9 +3586,3 @@ type WhammInlineConfig(swap_membase: bool, swap_instance: bool, is_inlined: bool // The SPC emits a stub at {stub_label} for each handler in the function. The stub restores the // expected state of the environment, then jumps to {dest_label} to continue execution at handler. type SpcHandlerInfo(is_dummy: bool, func_end: bool, dest_label: MasmLabel, stub_label: MasmLabel, merge_state: Array); - -def uleb_size(v: int) -> int { - var n = 1, data = u32.view(v); - while (data >= 0x80) { data = data >> 7; n++; } - return n; -} From 582aec9544dd742ed4192a63475add06fd0deef7 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 12:44:43 -0400 Subject: [PATCH 54/91] Revert "Add CallProperty to distinguish between tail call and fast call" This reverts commit d6a175ee24e494adb68861c76960d21e95d84900. --- src/engine/compiler/SinglePassCompiler.v3 | 27 +++++++++++----------- src/util/BytecodeVisitor.v3 | 28 ++++++++--------------- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index a6a606d41..747553022 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -859,7 +859,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_br(ret_label); setUnreachable(); } - def visitCallDirect(op: Opcode, index: u31, prop: CallProperty) { + def visitCallDirect(op: Opcode, index: u31, tailCall: bool) { if (op == Opcode.CALL) { Metrics.spc_static_calls.val++; masm.emit_inc_metric(Metrics.spc_dynamic_calls); @@ -867,7 +867,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var func = module.functions[index]; // Try inlining for intra-module, non-tail calls - if (prop != CallProperty.TAIL && shouldInline(func)) { + if (!tailCall && shouldInline(func)) { if (Trace.compiler) Trace.OUT.put2("Inlining call to func #%d (%d bytes)", index, func.orig_bytecode.length).ln(); if (op == Opcode.CALL) { Metrics.spc_static_inlined_calls.val++; @@ -885,12 +885,11 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var tmp = allocTmp(ValueKind.REF); emit_load_instance(tmp); - // Load the function, XXX: skip and compute function from instance + code on stack? masm.emit_v3_Instance_functions_r_r(func_reg, tmp); masm.emit_v3_Array_elem_r_ri(ValueKind.REF, func_reg, func_reg, func.func_index); - emitCallToReg(func.sig, func_reg, vsp_reg, tmp, func.imp != null, prop); + emitCallToReg(func.sig, func_reg, vsp_reg, tmp, func.imp != null, tailCall); }); } def emitInlinedCall(callee_func: FuncDecl, whamm: WhammProbe) { @@ -919,7 +918,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl m = whamm_instance.module; new_local_base_sp = u31.view(state.sp) - u31.view(whamm_sig.length); // XXX - func_body_ctl.val_stack_top = new_local_base_sp; // correct val_stack_top for whamm arg count + func_body_ctl.val_stack_top = new_local_base_sp; // correct val_stack_top for whamm arg count } // create merge state based on outer function's base sp given inlined function's results @@ -966,21 +965,21 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Restore caller spc context popSpcFrame(); } - def emitCallToReg(sig: SigDecl, func_reg: Reg, vsp_reg: Reg, tmp: Reg, checkHostCall: bool, prop: CallProperty) { + def emitCallToReg(sig: SigDecl, func_reg: Reg, vsp_reg: Reg, tmp: Reg, checkHostCall: bool, tailCall: bool) { var retpt = masm.newLabel(it.pc), wasmcall_label = masm.newLabel(it.pc); // Handle the current stack state. - if (prop == CallProperty.TAIL) emitMoveTailCallArgs(sig); // transfer tail call args + if (tailCall) emitMoveTailCallArgs(sig); // transfer tail call args else state.emitSaveAll(resolver, SpillMode.SAVE_AND_FREE_REGS); // spill entire value stack // Compute VSP below the args passed into callee function and spill it emit_compute_vsp(vsp_reg, state.sp - u32.!(sig.params.length)); - if (prop != CallProperty.TAIL) emit_spill_vsp(vsp_reg); + if (!tailCall) emit_spill_vsp(vsp_reg); // Add params to VSP if (sig.params.length > 0) masm.emit_addw_r_i(vsp_reg, sig.params.length * masm.valuerep.slot_size); if (checkHostCall) { // A call to imported function must first check for WasmFunction. masm.emit_br_r(func_reg, MasmBrCond.IS_WASM_FUNC, wasmcall_label); - if (prop == CallProperty.TAIL) { + if (tailCall) { masm.emit_jump_HostCallStub(); // XXX: stub relies on func_arg and VSP } else { masm.emit_call_HostCallStub(); // XXX: stub relies on func_arg and VSP @@ -993,7 +992,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_v3_FuncDecl_target_code_r_r(tmp, tmp); // Call or jump to the entrypoint. - if (prop == CallProperty.TAIL) { + if (tailCall) { masm.emit_jump_r(tmp); setUnreachable(); } else { @@ -1017,7 +1016,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // adjust frame masm.emit_addw_r_i(regs.sp, frame.frameSize); } - def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, prop: CallProperty) { + def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, tailCall: bool) { var sig = SigDecl.!(module.heaptypes[sig_index]); withReconstructedInlinedFrames(fun { var vsp_reg = allocTmpFixed(ValueKind.REF, regs.vsp); @@ -1074,10 +1073,10 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.bindLabel(end); } - emitCallToReg(sig, func_reg, vsp_reg, tmp_reg, true, prop); + emitCallToReg(sig, func_reg, vsp_reg, tmp_reg, true, tailCall); }); } - def visitCallRef(op: Opcode, index: u31, prop: CallProperty) { + def visitCallRef(op: Opcode, index: u31, tailCall: bool) { var sig = SigDecl.!(module.heaptypes[index]); var sv = state.peek(); if (sv.isConst() && sv.const == 0) { @@ -1090,7 +1089,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var tmp = allocTmp(ValueKind.REF); var func_reg = sv.reg; - emitCallToReg(sig, func_reg, vsp_reg, tmp, true, prop); + emitCallToReg(sig, func_reg, vsp_reg, tmp, true, tailCall); } def visit_DROP() { dropN(1); diff --git a/src/util/BytecodeVisitor.v3 b/src/util/BytecodeVisitor.v3 index cacd6c738..505292944 100644 --- a/src/util/BytecodeVisitor.v3 +++ b/src/util/BytecodeVisitor.v3 @@ -20,9 +20,9 @@ class BytecodeVisitor { def visitMisc(op: Opcode) { visitOp(op); } def visitControl(op: Opcode) { visitOp(op); } def visitCall(op: Opcode) { visitOp(op); } - def visitCallDirect(op: Opcode, func_index: u31, prop: CallProperty) { visitCall(op); } - def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, prop: CallProperty) { visitCall(op); } - def visitCallRef(op: Opcode, sig_index: u31, prop: CallProperty) { visitCall(op); } + def visitCallDirect(op: Opcode, func_index: u31, tailCall: bool) { visitCall(op); } + def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, tailCall: bool) { visitCall(op); } + def visitCallRef(op: Opcode, sig_index: u31, tailCall: bool) { visitCall(op); } def visitLocal(op: Opcode, local_index: u31) { visitOp(op); } def visitGlobal(op: Opcode, local_index: u31) { visitOp(op); } def visitTable(op: Opcode, table_index: u31) { visitOp(op); } @@ -69,13 +69,13 @@ class BytecodeVisitor { def visit_BR_IF (depth: u31) { visitControl(Opcode.BR_IF); } def visit_BR_TABLE (labels: Range) { visitControl(Opcode.BR_TABLE); } def visit_RETURN () { visitControl(Opcode.RETURN); } - def visit_CALL (func_index: u31) { visitCallDirect(Opcode.CALL, func_index, SLOW); } - def visit_FAST_CALL (fast_index: int, func_index: u31) { visitCallDirect(Opcodes.indexToFastCall(fast_index), func_index, FAST); } - def visit_CALL_INDIRECT (sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.CALL_INDIRECT, sig_index, table_index, SLOW); } - def visit_RETURN_CALL (func_index: u31) { visitCallDirect(Opcode.RETURN_CALL, func_index, TAIL); } - def visit_RETURN_CALL_INDIRECT(sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.RETURN_CALL_INDIRECT, sig_index, table_index, TAIL); } - def visit_CALL_REF (sig_index: u31) { visitCallRef(Opcode.CALL_REF, sig_index, SLOW); } - def visit_RETURN_CALL_REF(sig_index: u31) { visitCallRef(Opcode.RETURN_CALL_REF, sig_index, TAIL); } + def visit_CALL (func_index: u31) { visitCallDirect(Opcode.CALL, func_index, false); } + def visit_FAST_CALL (fast_index: int, func_index: u31) { visitCallDirect(Opcodes.indexToFastCall(fast_index), func_index, false); } + def visit_CALL_INDIRECT (sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.CALL_INDIRECT, sig_index, table_index, false); } + def visit_RETURN_CALL (func_index: u31) { visitCallDirect(Opcode.RETURN_CALL, func_index, true); } + def visit_RETURN_CALL_INDIRECT(sig_index: u31, table_index: u31) { visitCallIndirect(Opcode.RETURN_CALL_INDIRECT, sig_index, table_index, true); } + def visit_CALL_REF (sig_index: u31) { visitCallRef(Opcode.CALL_REF, sig_index, false); } + def visit_RETURN_CALL_REF(sig_index: u31) { visitCallRef(Opcode.RETURN_CALL_REF, sig_index, true); } def visit_DELEGATE (depth: u31) { visitControl(Opcode.DELEGATE); } def visit_CATCH_ALL () { visitControl(Opcode.CATCH_ALL); } def visit_DROP () { visitMisc(Opcode.DROP); } @@ -654,11 +654,3 @@ class BytecodeVisitor { def visit_SUSPEND (tag: u31) { visitOp(Opcode.SUSPEND); } def visit_SWITCH (cont: u31, tag: u31) { visitOp(Opcode.SWITCH); } } - -enum CallProperty { - SLOW, TAIL, FAST -} - -def SLOW = CallProperty.SLOW; -def TAIL = CallProperty.TAIL; -def FAST = CallProperty.FAST; From 9f1dad52aab8589f7c60d7dcc3ccd63a658b614f Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 13:55:48 -0400 Subject: [PATCH 55/91] Refactor and clean up code --- src/engine/BytecodeIterator.v3 | 7 +- src/engine/CodeValidator.v3 | 3 +- src/engine/Module.v3 | 6 +- src/engine/Opcodes.v3 | 80 +++++++++---------- src/engine/v3/V3Interpreter.v3 | 14 +++- src/engine/x86-64/X86_64Interpreter.v3 | 50 +----------- src/engine/x86-64/X86_64MacroAssembler.v3 | 30 +------ src/engine/x86-64/X86_64MasmRegs.v3 | 1 - src/engine/x86-64/X86_64PreGenStubs.v3 | 4 +- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 12 --- src/engine/x86-64/X86_64Target.v3 | 17 ++-- 11 files changed, 71 insertions(+), 153 deletions(-) diff --git a/src/engine/BytecodeIterator.v3 b/src/engine/BytecodeIterator.v3 index c341bb881..7a5057a9d 100644 --- a/src/engine/BytecodeIterator.v3 +++ b/src/engine/BytecodeIterator.v3 @@ -780,12 +780,7 @@ class BytecodeIterator { RESUME_THROW_REF => v.visit_RESUME_THROW_REF(read_CONT(), read_HANDLERS()); SWITCH => v.visit_SWITCH(read_CONT(), read_TAG()); - /* here, we require that replacing CALL with FAST_CALL does not touch the - * operand, so that the original function can still be recovered from the bytecode itself - * - * in other places, where we have the module, we can go direct from bytecode to func - */ - // FIXME wrap into _ clause + // replacing CALL with FAST_CALL does not touch the operand so that the original function can still be recovered FAST_CALL0 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); FAST_CALL1 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); FAST_CALL2 => v.visit_FAST_CALL(Opcodes.fastCallToIndex(opcode), read_FUNC()); diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index d0d050019..e7b0a4933 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -440,7 +440,7 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e } // not found? allocate FAST_CALL instruction, if there's space if (fast_idx < 0) { - if (fast_funcs.length < 40) { + if (fast_funcs.length < Opcodes.FAST_CALL_OPCODES) { fast_idx = fast_funcs.length; func.fast_call_idx = fast_idx; if (Trace.validation) Trace.OUT.put1("not found, allocating FAST_CALL%d, ", fast_idx); @@ -451,7 +451,6 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e } // replace the bytecode, if it's found or allocated if (fast_idx >= 0) { - //if (Trace.validation) Trace.OUT.put2("replaceCall(opcode_pos, fast_idx)\n", opcode_pos, fast_idx); if (Trace.validation) Trace.OUT.puts("replacing call\n"); this.func.replaceCall(opcode_pos, fast_idx); } else { diff --git a/src/engine/Module.v3 b/src/engine/Module.v3 index a26d75e74..063aea151 100644 --- a/src/engine/Module.v3 +++ b/src/engine/Module.v3 @@ -175,13 +175,12 @@ class FuncDecl(sig_index: int) extends Decl { def replaceCall(pc: int, idx: int) { // "orig" will become a copy of the original code, to allow in-place modification of old code if (cur_bytecode == orig_bytecode) orig_bytecode = Arrays.dup(orig_bytecode); - // sanity check - if (cur_bytecode[pc] != Opcode.CALL.code) { + if (cur_bytecode[pc] != Opcode.CALL.code) { // sanity check def realOp = Opcodes.find(0, cur_bytecode[pc]); System.error("replace bytecode", Strings.format1("not replacing call (got %s)", realOp.mnemonic)); } cur_bytecode[pc] = byte.!(Opcodes.indexToFastCall(idx).code); - // do NOT replace the operands, as a convenience for BytecodeIterator + // do not replace the operands, beeded for BytecodeIterator } def reset() -> this { if (cur_bytecode == orig_bytecode) return; @@ -217,7 +216,6 @@ class FuncDecl(sig_index: int) extends Decl { Trace.OUT.put3("(func=%q, tag=%d, throw_pc=%d)", this.render(instance.module.names, _), tag.decl.tag_index, throw_pc).ln(); } - while (i < handlers.length) { // XXX: speed this up with a binary search var e = handlers[i]; if (Trace.exception) Trace.OUT.put3(" entry[%d...%d] tag=%d", e.start, e.end, e.tag).ln(); diff --git a/src/engine/Opcodes.v3 b/src/engine/Opcodes.v3 index 2e785e04c..0c987b6ba 100644 --- a/src/engine/Opcodes.v3 +++ b/src/engine/Opcodes.v3 @@ -611,46 +611,46 @@ enum Opcode(prefix: u8, code: u16, mnemonic: string, imms: Array, sig: SWITCH (0x00, 0xE6, "switch", imm.CONT_TAG, null) // fast call instructions - FAST_CALL0 (0x00, 0x27, "fast_call0", imm.FUNC, null), - FAST_CALL1 (0x00, 0xC5, "fast_call1", imm.FUNC, null), - FAST_CALL2 (0x00, 0xC6, "fast_call2", imm.FUNC, null), - FAST_CALL3 (0x00, 0xC7, "fast_call3", imm.FUNC, null), - FAST_CALL4 (0x00, 0xC8, "fast_call4", imm.FUNC, null), - FAST_CALL5 (0x00, 0xC9, "fast_call5", imm.FUNC, null), - FAST_CALL6 (0x00, 0xCA, "fast_call6", imm.FUNC, null), - FAST_CALL7 (0x00, 0xCB, "fast_call7", imm.FUNC, null), - FAST_CALL8 (0x00, 0xCC, "fast_call8", imm.FUNC, null), - FAST_CALL9 (0x00, 0xCD, "fast_call9", imm.FUNC, null), - FAST_CALL10 (0x00, 0xCE, "fast_call10", imm.FUNC, null), - FAST_CALL11 (0x00, 0xCF, "fast_call11", imm.FUNC, null), - FAST_CALL12 (0x00, 0xD7, "fast_call12", imm.FUNC, null), - FAST_CALL13 (0x00, 0xD8, "fast_call13", imm.FUNC, null), - FAST_CALL14 (0x00, 0xD9, "fast_call14", imm.FUNC, null), - FAST_CALL15 (0x00, 0xDA, "fast_call15", imm.FUNC, null), - FAST_CALL16 (0x00, 0xDB, "fast_call16", imm.FUNC, null), - FAST_CALL17 (0x00, 0xDC, "fast_call17", imm.FUNC, null), - FAST_CALL18 (0x00, 0xDD, "fast_call18", imm.FUNC, null), - FAST_CALL19 (0x00, 0xDE, "fast_call19", imm.FUNC, null), - FAST_CALL20 (0x00, 0xDF, "fast_call20", imm.FUNC, null), - FAST_CALL21 (0x00, 0xE7, "fast_call21", imm.FUNC, null), - FAST_CALL22 (0x00, 0xE8, "fast_call22", imm.FUNC, null), - FAST_CALL23 (0x00, 0xE9, "fast_call23", imm.FUNC, null), - FAST_CALL24 (0x00, 0xEA, "fast_call24", imm.FUNC, null), - FAST_CALL25 (0x00, 0xEB, "fast_call25", imm.FUNC, null), - FAST_CALL26 (0x00, 0xEC, "fast_call26", imm.FUNC, null), - FAST_CALL27 (0x00, 0xED, "fast_call27", imm.FUNC, null), - FAST_CALL28 (0x00, 0xEE, "fast_call28", imm.FUNC, null), - FAST_CALL29 (0x00, 0xEF, "fast_call29", imm.FUNC, null), - FAST_CALL30 (0x00, 0xF2, "fast_call30", imm.FUNC, null), - FAST_CALL31 (0x00, 0xF3, "fast_call31", imm.FUNC, null), - FAST_CALL32 (0x00, 0xF4, "fast_call32", imm.FUNC, null), - FAST_CALL33 (0x00, 0xF5, "fast_call33", imm.FUNC, null), - FAST_CALL34 (0x00, 0xF6, "fast_call34", imm.FUNC, null), - FAST_CALL35 (0x00, 0xF7, "fast_call35", imm.FUNC, null), - FAST_CALL36 (0x00, 0xF8, "fast_call36", imm.FUNC, null), - FAST_CALL37 (0x00, 0xF9, "fast_call37", imm.FUNC, null), - FAST_CALL38 (0x00, 0xFA, "fast_call38", imm.FUNC, null), - FAST_CALL39 (0x00, 0x17, "fast_call39", imm.FUNC, null), + FAST_CALL0 (0x00, 0xC5, "fast_call0", imm.FUNC, null), + FAST_CALL1 (0x00, 0xC6, "fast_call1", imm.FUNC, null), + FAST_CALL2 (0x00, 0xC7, "fast_call2", imm.FUNC, null), + FAST_CALL3 (0x00, 0xC8, "fast_call3", imm.FUNC, null), + FAST_CALL4 (0x00, 0xC9, "fast_call4", imm.FUNC, null), + FAST_CALL5 (0x00, 0xCA, "fast_call5", imm.FUNC, null), + FAST_CALL6 (0x00, 0xCB, "fast_call6", imm.FUNC, null), + FAST_CALL7 (0x00, 0xCC, "fast_call7", imm.FUNC, null), + FAST_CALL8 (0x00, 0xCD, "fast_call8", imm.FUNC, null), + FAST_CALL9 (0x00, 0xCE, "fast_call9", imm.FUNC, null), + FAST_CALL10 (0x00, 0xCF, "fast_call10", imm.FUNC, null), + FAST_CALL11 (0x00, 0xD7, "fast_call11", imm.FUNC, null), + FAST_CALL12 (0x00, 0xD8, "fast_call12", imm.FUNC, null), + FAST_CALL13 (0x00, 0xD9, "fast_call13", imm.FUNC, null), + FAST_CALL14 (0x00, 0xDA, "fast_call14", imm.FUNC, null), + FAST_CALL15 (0x00, 0xDB, "fast_call15", imm.FUNC, null), + FAST_CALL16 (0x00, 0xDC, "fast_call16", imm.FUNC, null), + FAST_CALL17 (0x00, 0xDD, "fast_call17", imm.FUNC, null), + FAST_CALL18 (0x00, 0xDE, "fast_call18", imm.FUNC, null), + FAST_CALL19 (0x00, 0xDF, "fast_call19", imm.FUNC, null), + FAST_CALL20 (0x00, 0xE7, "fast_call20", imm.FUNC, null), + FAST_CALL21 (0x00, 0xE8, "fast_call21", imm.FUNC, null), + FAST_CALL22 (0x00, 0xE9, "fast_call22", imm.FUNC, null), + FAST_CALL23 (0x00, 0xEA, "fast_call23", imm.FUNC, null), + FAST_CALL24 (0x00, 0xEB, "fast_call24", imm.FUNC, null), + FAST_CALL25 (0x00, 0xEC, "fast_call25", imm.FUNC, null), + FAST_CALL26 (0x00, 0xED, "fast_call26", imm.FUNC, null), + FAST_CALL27 (0x00, 0xEE, "fast_call27", imm.FUNC, null), + FAST_CALL28 (0x00, 0xEF, "fast_call28", imm.FUNC, null), + FAST_CALL29 (0x00, 0xF2, "fast_call29", imm.FUNC, null), + FAST_CALL30 (0x00, 0xF3, "fast_call30", imm.FUNC, null), + FAST_CALL31 (0x00, 0xF4, "fast_call31", imm.FUNC, null), + FAST_CALL32 (0x00, 0xF5, "fast_call32", imm.FUNC, null), + FAST_CALL33 (0x00, 0xF6, "fast_call33", imm.FUNC, null), + FAST_CALL34 (0x00, 0xF7, "fast_call34", imm.FUNC, null), + FAST_CALL35 (0x00, 0xF8, "fast_call35", imm.FUNC, null), + FAST_CALL36 (0x00, 0xF9, "fast_call36", imm.FUNC, null), + FAST_CALL37 (0x00, 0xFA, "fast_call37", imm.FUNC, null), + FAST_CALL38 (0x00, 0x17, "fast_call38", imm.FUNC, null), + FAST_CALL39 (0x00, 0x27, "fast_call39", imm.FUNC, null), } diff --git a/src/engine/v3/V3Interpreter.v3 b/src/engine/v3/V3Interpreter.v3 index b5ae1b0cd..16de5b3ce 100644 --- a/src/engine/v3/V3Interpreter.v3 +++ b/src/engine/v3/V3Interpreter.v3 @@ -371,7 +371,12 @@ class V3Interpreter extends WasmStack { RETURN => { doReturn(frame.fp, frame.func.sig); } - CALL, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39 => { + CALL, + FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, + FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, + FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, + FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, + FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39 => { var func_index = codeptr.read_uleb32(); var f = frame.func.instance.functions[func_index]; return doCallFunction(f); @@ -1640,7 +1645,12 @@ class V3Interpreter extends WasmStack { // XXX: use read_opcode_and_skip() var opcode = codeptr.read_opcode_but_skip_probe(frame.func.decl); match (opcode) { - CALL, CALL_REF, FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39 => { + CALL, CALL_REF, + FAST_CALL0, FAST_CALL1, FAST_CALL2, FAST_CALL3, FAST_CALL4, FAST_CALL5, FAST_CALL6, FAST_CALL7, + FAST_CALL8, FAST_CALL9, FAST_CALL10, FAST_CALL11, FAST_CALL12, FAST_CALL13, FAST_CALL14, FAST_CALL15, + FAST_CALL16, FAST_CALL17, FAST_CALL18, FAST_CALL19, FAST_CALL20, FAST_CALL21, FAST_CALL22, FAST_CALL23, + FAST_CALL24, FAST_CALL25, FAST_CALL26, FAST_CALL27, FAST_CALL28, FAST_CALL29, FAST_CALL30, FAST_CALL31, + FAST_CALL32, FAST_CALL33, FAST_CALL34, FAST_CALL35, FAST_CALL36, FAST_CALL37, FAST_CALL38, FAST_CALL39 => { codeptr.skip_leb(); frame.pc = codeptr.pos; } diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index abd6ee6af..759e5d46d 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -537,7 +537,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { var tmp = r_scratch; { // Entrypoint for calls coming from V3 ic.header.intV3EntryOffset = w.pos; - //masm.emit_debugger_breakpoint(); // Allocate and initialize interpreter stack frame from incoming V3 args. asm.q.sub_r_i(r_sp, k_frame_size); @@ -1257,9 +1256,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { } def genLocals() { bindHandler(Opcode.DROP); - //masm.emit_debugger_breakpoint(); decrementVsp(); - //masm.emit_debugger_breakpoint(); endHandler(); bindHandler(Opcode.LOCAL_GET); @@ -1323,8 +1320,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { genPopFrameAndRet(); // FAST_CALL - // TODO patch the dispatch table so it goes to the code directly, - // instead of this fast function lookup + // these are placeholders in the dispatch table, will be patched with real handler SPC code bindHandler(Opcode.FAST_CALL0); bindHandler(Opcode.FAST_CALL1); bindHandler(Opcode.FAST_CALL2); @@ -1365,45 +1361,8 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { bindHandler(Opcode.FAST_CALL37); bindHandler(Opcode.FAST_CALL38); bindHandler(Opcode.FAST_CALL39); - masm.emit_intentional_crash(); - //masm.emit_debugger_breakpoint(); - var dispatchLabel = X86_64Label.new(); - // genTagPush(BpTypeCode.I32.code); - // asm.movq_m_i(vsph[0].value, 770); - // incrementVsp(); - - /* TODO What should happen in a FAST_CALL? - * - * Ideally, we've patched the dispatch table with exactly what appears in fast_target_code - * so it instantly jumps there and so we don't have to set up the jump first. - * - * Fast function implementation should include code to skip the original operand as - * part of incrementing pc (will be done over in SPC). - * - * But, we could keep this for a quasi-fast call? - */ - genReadUleb32(r_tmp1); - asm.movq_r_m(r_tmp0, r_instance.plus(offsets.Instance_functions)); - asm.movq_r_m(func_arg, r_tmp0.plusR(r_tmp1, offsets.REF_SIZE, offsets.Array_contents)); - - var tmp = r_tmp2; - asm.movq_r_m(tmp, func_arg.plus(offsets.WasmFunction_decl)); - - //masm.emit_debugger_breakpoint(); - asm.ijmp_m(tmp.plus(offsets.FuncDecl_fast_target_code)); - //asm.icall_m(tmp.plus(offsets.FuncDecl_fast_target_code)); - //asm.invalid(); - - // don't go here - asm.bind(dispatchLabel); - masm.emit_nop(); - masm.emit_nop(); - masm.emit_nop(); - masm.emit_nop(); - masm.emit_nop(); - masm.emit_nop(); - endHandler(); + masm.emit_intentional_crash(); bindHandler(Opcode.CALL); computeCurIpForTrap(-1); @@ -1424,8 +1383,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { var tmp = r_tmp2; asm.movq_r_m(tmp, func_arg.plus(offsets.WasmFunction_decl)); asm.icall_m(tmp.plus(offsets.FuncDecl_target_code)); - // assembly call to target function - // if not compiled, interpreter's entry point } else { asm.call_rel_far(callReentryLabel); } @@ -2825,7 +2782,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { if (FastIntTuning.enableWhammProbeTrampoline) { var pos = w.atEnd().pos; writeDispatchEntry(dispatchTables[0].1, InternalOpcode.BREAK_PROBE.code, pos); - //masm.emit_debugger_breakpoint(); + masm.emit_debugger_breakpoint(); // Compute a pointer to the original code at this pc offset var pc = r_tmp1; // = IP - CODE asm.movq_r_r(pc, r_ip); @@ -4126,7 +4083,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { // Generate a dispatch from the main dispatch table. def genDispatch() { genDispatch0(ip_ptr, if (FeatureDisable.globalProbes, dispatchTables[0].1), true); - //masm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, dispatchTables[0].1, true, ic); } // Generate a load of the next bytecode and a dispatch through the dispatch table. def genDispatch0(ptr: X86_64Addr, table: IcCodeRef, increment: bool) { diff --git a/src/engine/x86-64/X86_64MacroAssembler.v3 b/src/engine/x86-64/X86_64MacroAssembler.v3 index 8e1753b61..d0693c862 100644 --- a/src/engine/x86-64/X86_64MacroAssembler.v3 +++ b/src/engine/x86-64/X86_64MacroAssembler.v3 @@ -55,7 +55,7 @@ class X86_64MacroAssembler extends MacroAssembler { if (Trace.compiler) Trace.OUT.put2(" bind label (+%d) -> @%d", l.create_pos, w.end()).ln(); var label = X86_64MasmLabel.!(l); asm.bind(label.label); - label.offset = label.label.pos; + } def bindLabelTo(l: MasmLabel, offset: int) { if (Trace.compiler) Trace.OUT.put2(" bind label (+%d) -> @%d", l.create_pos, offset).ln(); @@ -1593,25 +1593,11 @@ class X86_64MacroAssembler extends MacroAssembler { asm.pextrq_r_s_i(G(to), X(from), 1); } - // xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; - // r_ip rax - // ip_ptr - // r_dispatch r14 - // r_tmp0 rcx - // r_tmp1 rdx def emit_int_dispatch(opcode: X86_64Gpr, base: X86_64Gpr, r_ip: X86_64Gpr, r_dispatch: X86_64Gpr, ptr: X86_64Addr, table: IcCodeRef, increment: bool, ic: X86_64InterpreterCode) { if (ptr != null) asm.movbzx_r_m(opcode, ptr); if (increment) asm.inc_r(r_ip); match (FastIntTuning.dispatchEntrySize) { - 2 => { - if (table == null) asm.movq_r_r(base, r_dispatch); - else asm.lea(base, table); // RIP-relative LEA - asm.movwsx_r_m(opcode, base.plusR(opcode, 2, 0)); // load 16-bit offset - asm.add_r_r(base, opcode); - //if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; - asm.ijmp_r(base); - } 4 => { if (table == null) { asm.movd_r_m(base, r_dispatch.plusR(opcode, 4, 0)); @@ -1619,21 +1605,11 @@ class X86_64MacroAssembler extends MacroAssembler { var addr = ic.start + table.offset; asm.movd_r_m(base, X86_64Addr.new(null, opcode, 4, int.!(addr - Pointer.NULL))); } - //if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; asm.ijmp_r(base); } - 8 => { - if (table == null) { - //if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; - asm.ijmp_m(r_dispatch.plusR(opcode, 8, 0)); - } else { - var addr = ic.start + table.offset; - //if (dispatchJmpOffset < 0) dispatchJmpOffset = w.pos; - asm.ijmp_m(X86_64Addr.new(null, opcode, 8, int.!(addr - Pointer.NULL))); - } - } + _ => System.error("X86_64MacroAssembler", + Strings.format1("emit_int_dispatch called on unsupported dispatch entry size: %d", FastIntTuning.dispatchEntrySize)); } - } // Reads a 32- or 64-bit unsigned LEB from {rw_ptr} into {w_dest}. diff --git a/src/engine/x86-64/X86_64MasmRegs.v3 b/src/engine/x86-64/X86_64MasmRegs.v3 index 73af95b67..ddb9990aa 100644 --- a/src/engine/x86-64/X86_64MasmRegs.v3 +++ b/src/engine/x86-64/X86_64MasmRegs.v3 @@ -194,4 +194,3 @@ component X86_64MasmRegs { return reg; } } - diff --git a/src/engine/x86-64/X86_64PreGenStubs.v3 b/src/engine/x86-64/X86_64PreGenStubs.v3 index 959c732a0..070a2eae5 100644 --- a/src/engine/x86-64/X86_64PreGenStubs.v3 +++ b/src/engine/x86-64/X86_64PreGenStubs.v3 @@ -25,7 +25,7 @@ layout X86_64PreGenHeader { +24 intV3EntryOffset: i32; // entry into interpreter from V3 caller +28 intSpcEntryOffset: i32; // entry into interpreter from SPC caller +32 intIntEntryOffset: i32; // entry into interpreter from interpreter caller - +36 intSuspendEntryOffset: i32; // entry into interpreter from a suspended child stack + +36 intSuspendEntryOffset: i32; // entry into interpreter from a suspended child stack +40 deoptReentryOffset: i32; // re-enter interpreter from optimized code +44 oobMemoryHandlerOffset: i32; // handler for signals caused by OOB memory access +48 divZeroHandlerOffset: i32; // handler for signals caused by divide by zero @@ -222,7 +222,7 @@ component X86_64PreGenStubs { ic.header.probedDispatchTableOffset, ic.header.fastDispatchTableOffset); - // XXX: PROT_WRITE included to allow runtime dispatch table patching + // PROT_WRITE needed for fast-handler dispatch table patching Mmap.protect(range.start + ic.header.codeStart, u64.!(ic.header.codeEnd - ic.header.codeStart), Mmap.PROT_READ | Mmap.PROT_WRITE | Mmap.PROT_EXEC); // The host call stub is part of interpreter code (TODO: does it need to be?) diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 7bc179062..cbffe0765 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -86,8 +86,6 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.trap_stubs = TRAPS_STUB; } def emitFastDispatch() { - //mmasm.emit_debugger_breakpoint(); - // XXX Restore IP from the interpreter frame slot asm.movq_r_m(r_ip, m_ip); mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); @@ -99,7 +97,6 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { } def saveCallerIVars() { saveIVar(r_ip); - //saveIVar(r_stp); if (!FeatureDisable.stacktraces) saveIVar(r_curpc); } def restoreDispatchTableReg() { @@ -115,8 +112,6 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { } } def restoreCallerIVars() { - //restoreReg(r_vfp); // restored explicitly before this call (emitReturn line 2175) - //restoreReg(r_vsp); // recomputed from r_vfp + result_slots (emit_compute_vsp) restoreReg(r_stp); restoreReg(r_ip); restoreReg(r_eip); @@ -130,13 +125,6 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { asm.q.lea(r_curpc, X86_64Addr.new(r_ip, null, 1, delta - offsets.Array_contents)); asm.q.sub_r_m(r_curpc, m_code); } - def computeCurIpForTrap(delta: int) { - if (!FeatureDisable.stacktraces) computeCurIpFromIp(delta); - } - def computeCurIpFromIp(delta: int) { - def offsets = masm.getOffsets(); - asm.q.lea(r_curpc, X86_64Addr.new(r_ip, null, 1, delta - offsets.Array_contents)); - } private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { var b = pop(), a = popReg(); diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index dcb88c903..c4d235f18 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -79,7 +79,7 @@ component Target { Trace.OUT.ln(); } } - f.fast_target_code = TargetCode(addr); + f.fast_target_code = TargetCode(addr); patchFastCallDispatch(f, addr); Debug.afterCompile(f, u64.view(addr - Pointer.NULL)); } @@ -87,22 +87,19 @@ component Target { if (f.fast_call_idx < 0) return; def opcode = Opcodes.indexToFastCall(f.fast_call_idx); def ic = X86_64PreGenStubs.getInterpreterCode(); - // XXX Patch only fast dispatch tables + // XXX Patching only fast (non-probed?) dispatch tables def fast_offset = ic.header.fastDispatchTableOffset; def entry = ic.start + fast_offset + opcode.code * FastIntTuning.dispatchEntrySize; if (Trace.compiler) { - Trace.OUT.puts("patching dispatch type\n"); - Trace.OUT.put1("start 0x%x\n", u64.view(ic.start)); - Trace.OUT.put1("entry 0x%x\n", u64.view(entry)); - Trace.OUT.put1("addr 0x%x\n", u64.view(addr)); + Trace.OUT.puts("patching dispatch table\n"); + Trace.OUT.put1(" start 0x%x\n", u64.view(ic.start)); + Trace.OUT.put1(" entry 0x%x\n", u64.view(entry)); + Trace.OUT.put1(" addr 0x%x\n", u64.view(addr)); } - // XXX we require 8 entry size because of `addr` position match (FastIntTuning.dispatchEntrySize) { 4 => entry.store(u32.view(addr)); - 8 => entry.store(long.view(addr)); - // 2-byte relative case would need a relative offset + _ => System.error("patchFastCallDispatch", "unsupported dispatchEntrySize"); } - if (Trace.compiler) Trace.OUT.puts("patched successfully\n"); } def pregenIntoFile(filename: string) -> ErrorBuilder { From e2b1009ea370b3cb8e1a6b386ab528f2b2678d5c Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 13:59:44 -0400 Subject: [PATCH 56/91] Remove printing fast function --- src/engine/x86-64/X86_64Target.v3 | 7 ------- test/fastcall/test27_outcall_stackframe.wasm.out | 1 - test/fastcall/test28_trap_mid_function.wasm.out | 1 - test/fastcall/test29_inline_then_outcall_trap.wasm.out | 1 - test/fastcall/test30_inline_depth2_outcall_trap.wasm.out | 1 - test/fastcall/test31_fast_below_spc_trap.wasm.out | 1 - test/fastcall/test32_inline_then_spc_trap.wasm.out | 1 - test/fastcall/test33_fast_self_trap.wasm.out | 1 - test/fastcall/test34_second_outcall_trap.wasm.out | 1 - 9 files changed, 15 deletions(-) diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index c4d235f18..8680363ec 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -274,13 +274,6 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { def onFuncValidationFinish(module: Module, func: FuncDecl, err: ErrorGen) { if (err != null && !err.ok()) return; Target.setUnconditionalInterpreterEntryIfMultiTier(func); - - for (i < module.exports.length) { - def ex = module.exports[i]; - if (ex.1 == func && Strings.startsWith(ex.0, "fast:")) { - System.puts(Strings.format1("fast function %s\n", ex.0)); - } - } } def onNewFunction(wf: WasmFunction, err: ErrorGen) { Target.setUnconditionalInterpreterEntryIfMultiTier(wf.decl); diff --git a/test/fastcall/test27_outcall_stackframe.wasm.out b/test/fastcall/test27_outcall_stackframe.wasm.out index d8e083192..03b309a8d 100644 --- a/test/fastcall/test27_outcall_stackframe.wasm.out +++ b/test/fastcall/test27_outcall_stackframe.wasm.out @@ -1,4 +1,3 @@ -fast function fast:f +3 +3 +1 diff --git a/test/fastcall/test28_trap_mid_function.wasm.out b/test/fastcall/test28_trap_mid_function.wasm.out index 99402ee09..426f1ccbe 100644 --- a/test/fastcall/test28_trap_mid_function.wasm.out +++ b/test/fastcall/test28_trap_mid_function.wasm.out @@ -1,4 +1,3 @@ -fast function fast:f +3 +5 +5 diff --git a/test/fastcall/test29_inline_then_outcall_trap.wasm.out b/test/fastcall/test29_inline_then_outcall_trap.wasm.out index 1701b0c54..ccb36ddcd 100644 --- a/test/fastcall/test29_inline_then_outcall_trap.wasm.out +++ b/test/fastcall/test29_inline_then_outcall_trap.wasm.out @@ -1,4 +1,3 @@ -fast function fast:f +3 +3 +3 diff --git a/test/fastcall/test30_inline_depth2_outcall_trap.wasm.out b/test/fastcall/test30_inline_depth2_outcall_trap.wasm.out index 4b489e512..373191dd1 100644 --- a/test/fastcall/test30_inline_depth2_outcall_trap.wasm.out +++ b/test/fastcall/test30_inline_depth2_outcall_trap.wasm.out @@ -1,4 +1,3 @@ -fast function fast:f +3 +3 +3 diff --git a/test/fastcall/test31_fast_below_spc_trap.wasm.out b/test/fastcall/test31_fast_below_spc_trap.wasm.out index 9c968c01f..8711073c7 100644 --- a/test/fastcall/test31_fast_below_spc_trap.wasm.out +++ b/test/fastcall/test31_fast_below_spc_trap.wasm.out @@ -1,4 +1,3 @@ -fast function fast:f +3 +3 +1 diff --git a/test/fastcall/test32_inline_then_spc_trap.wasm.out b/test/fastcall/test32_inline_then_spc_trap.wasm.out index 76c6217ae..8fcff46c4 100644 --- a/test/fastcall/test32_inline_then_spc_trap.wasm.out +++ b/test/fastcall/test32_inline_then_spc_trap.wasm.out @@ -1,4 +1,3 @@ -fast function fast:f +3 +3 +3 diff --git a/test/fastcall/test33_fast_self_trap.wasm.out b/test/fastcall/test33_fast_self_trap.wasm.out index a99ccedcc..cc78cfeab 100644 --- a/test/fastcall/test33_fast_self_trap.wasm.out +++ b/test/fastcall/test33_fast_self_trap.wasm.out @@ -1,4 +1,3 @@ -fast function fast:f +3 +8 !trap[DIV_BY_ZERO] diff --git a/test/fastcall/test34_second_outcall_trap.wasm.out b/test/fastcall/test34_second_outcall_trap.wasm.out index 9538df828..d90c9528f 100644 --- a/test/fastcall/test34_second_outcall_trap.wasm.out +++ b/test/fastcall/test34_second_outcall_trap.wasm.out @@ -1,4 +1,3 @@ -fast function fast:f +3 +5 +4 From 39f5519b931a46ce90f3a25a24fc5d5e7ae30065 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 14:14:01 -0400 Subject: [PATCH 57/91] Remove (lazy) fastCompile function --- src/engine/x86-64/X86_64Target.v3 | 34 ------------------------------- 1 file changed, 34 deletions(-) diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 8680363ec..90198c993 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -236,7 +236,6 @@ class X86_64ExecutionStrategy extends ExecutionStrategy { } // Compilation methods called directly by stubs. def lazyCompile(wf: WasmFunction) -> SpcResultForStub; - def fastCompile(wf: WasmFunction, ic: X86_64InterpreterCode) -> SpcResultForStub; def tierupCompile(wf: WasmFunction) -> SpcResultForStub; // Tiering may require setting up the whole module. def onTestModule(module: Module) { @@ -284,39 +283,6 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { X86_64WhammTrampoline.makeTrampoline(WhammProbe.!(p), X86_64PreGenStubs.getInterpreterCode()); } - // TODO avoid duplicated function here - def fastCompile(wf: WasmFunction, ic: X86_64InterpreterCode) -> SpcResultForStub { - var module = wf.instance.module; - var code = module.target_module.spc_code; - var compiler = newCompiler(module.filename, true, null); - var masm = X86_64MacroAssembler.!(compiler.masm), w = masm.asm.w; - - // generate code for the function - var success = compiler.gen(module, wf.decl, null); - - // Check for remaining code space - var regionSize = code.mapping.range.size(); - var remaining = regionSize - u64.!(code.codeEnd); - var codeSize = w.atEnd().pos; - if (codeSize > remaining) { - if (Trace.compiler) Trace.OUT.put3("exhausted code space for module (%d of %d bytes remaining, need %d)", - remaining, regionSize, codeSize).ln(); - success = false; - } - - var entrypoint: Pointer; - if (success) { - // Copy code into end of region - entrypoint = code.appendCode(masm); - Target.setFastTargetCode(wf.decl, entrypoint, entrypoint + codeSize); - } else { - // Failed, enter interpreter - var f = wf.decl; - if (Trace.compiler) Trace.OUT.put1("func[%d] FAST compile failed", f.func_index).ln(); - entrypoint = X86_64Spc.setInterpreterFallback(f); - } - return SpcResultForStub(wf, entrypoint, null); - } def fastCompileEntireModule(module: Module, size: u32, interpreter_fallback: bool, err: ErrorGen, ballast: u32) { // ensure entrypoint and lazy compile stubs are generated X86_64PreGenStubs.gen(); From 37c3f849399d79b1d29c6dfd2030689054ea6d37 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 14:30:28 -0400 Subject: [PATCH 58/91] Add guards around FastIntTuning.useFastFunctions --- src/engine/x86-64/X86_64Interpreter.v3 | 46 ++----------------- src/engine/x86-64/X86_64PreGenStubs.v3 | 6 ++- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 14 +++--- src/engine/x86-64/X86_64Target.v3 | 2 +- 4 files changed, 17 insertions(+), 51 deletions(-) diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index 759e5d46d..1d57e39e1 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -1321,48 +1321,10 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { // FAST_CALL // these are placeholders in the dispatch table, will be patched with real handler SPC code - bindHandler(Opcode.FAST_CALL0); - bindHandler(Opcode.FAST_CALL1); - bindHandler(Opcode.FAST_CALL2); - bindHandler(Opcode.FAST_CALL3); - bindHandler(Opcode.FAST_CALL4); - bindHandler(Opcode.FAST_CALL5); - bindHandler(Opcode.FAST_CALL6); - bindHandler(Opcode.FAST_CALL7); - bindHandler(Opcode.FAST_CALL8); - bindHandler(Opcode.FAST_CALL9); - bindHandler(Opcode.FAST_CALL10); - bindHandler(Opcode.FAST_CALL11); - bindHandler(Opcode.FAST_CALL12); - bindHandler(Opcode.FAST_CALL13); - bindHandler(Opcode.FAST_CALL14); - bindHandler(Opcode.FAST_CALL15); - bindHandler(Opcode.FAST_CALL16); - bindHandler(Opcode.FAST_CALL17); - bindHandler(Opcode.FAST_CALL18); - bindHandler(Opcode.FAST_CALL19); - bindHandler(Opcode.FAST_CALL20); - bindHandler(Opcode.FAST_CALL21); - bindHandler(Opcode.FAST_CALL22); - bindHandler(Opcode.FAST_CALL23); - bindHandler(Opcode.FAST_CALL24); - bindHandler(Opcode.FAST_CALL25); - bindHandler(Opcode.FAST_CALL26); - bindHandler(Opcode.FAST_CALL27); - bindHandler(Opcode.FAST_CALL28); - bindHandler(Opcode.FAST_CALL29); - bindHandler(Opcode.FAST_CALL30); - bindHandler(Opcode.FAST_CALL31); - bindHandler(Opcode.FAST_CALL32); - bindHandler(Opcode.FAST_CALL33); - bindHandler(Opcode.FAST_CALL34); - bindHandler(Opcode.FAST_CALL35); - bindHandler(Opcode.FAST_CALL36); - bindHandler(Opcode.FAST_CALL37); - bindHandler(Opcode.FAST_CALL38); - bindHandler(Opcode.FAST_CALL39); - - masm.emit_intentional_crash(); + if (FastIntTuning.useFastFunctions) { + for (op in Opcodes.fast_calls) bindHandler(op); + masm.emit_intentional_crash(); + } bindHandler(Opcode.CALL); computeCurIpForTrap(-1); diff --git a/src/engine/x86-64/X86_64PreGenStubs.v3 b/src/engine/x86-64/X86_64PreGenStubs.v3 index 070a2eae5..79b3a3dc3 100644 --- a/src/engine/x86-64/X86_64PreGenStubs.v3 +++ b/src/engine/x86-64/X86_64PreGenStubs.v3 @@ -222,8 +222,10 @@ component X86_64PreGenStubs { ic.header.probedDispatchTableOffset, ic.header.fastDispatchTableOffset); - // PROT_WRITE needed for fast-handler dispatch table patching - Mmap.protect(range.start + ic.header.codeStart, u64.!(ic.header.codeEnd - ic.header.codeStart), Mmap.PROT_READ | Mmap.PROT_WRITE | Mmap.PROT_EXEC); + var prot = Mmap.PROT_READ | Mmap.PROT_EXEC; + // Fast functions need the dispatch table writable to patch in the handler + if (FastIntTuning.useFastFunctions) prot |= Mmap.PROT_WRITE; + Mmap.protect(range.start + ic.header.codeStart, u64.!(ic.header.codeEnd - ic.header.codeStart), prot); // The host call stub is part of interpreter code (TODO: does it need to be?) hostCallStub.start = ic.start + ic.header.hostCallStubOffset; diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index cbffe0765..96caf4c1b 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -1356,12 +1356,14 @@ class X86_64SpcModuleCode extends X86_64SpcCode { // If the outermost function in the inline_ctx doesn't match the function in the frame, // then we are in a fast handler. In that case, we add it to the inline_ctx. // FIXME wrong if a fast handler is interpreted, calls itself with fast_call, and HW traps - def frame_wf = (p_rsp + X86_64InterpreterFrame.wasm_func.offset).load(); - def arr = Lists.toArray(inline_ctx); - def exec_fl = arr[arr.length - 1]; - if (frame_wf.decl.func_index != exec_fl.func_index) { - def frame_pc = X86_64Interpreter.computePCFromFrame(p_rsp); - inline_ctx = Lists.fromArray(Arrays.append(FuncLoc(frame_wf.decl.func_index, frame_pc), arr)); + if (FastIntTuning.useFastFunctions) { + def frame_wf = (p_rsp + X86_64InterpreterFrame.wasm_func.offset).load(); + def arr = Lists.toArray(inline_ctx); + def exec_fl = arr[arr.length - 1]; + if (frame_wf.decl.func_index != exec_fl.func_index) { + def frame_pc = X86_64Interpreter.computePCFromFrame(p_rsp); + inline_ctx = Lists.fromArray(Arrays.append(FuncLoc(frame_wf.decl.func_index, frame_pc), arr)); + } } // Check on the size of the inline context if (inline_ctx.tail == null) { diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 90198c993..9a1396c4d 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -268,7 +268,7 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { def onModuleFinish(module: Module, size: u32, err: ErrorGen) { disableLazyNameDecodingDuringGC(module); - fastCompileEntireModule(module, size, false, err, 1024); + if (FastIntTuning.useFastFunctions) fastCompileEntireModule(module, size, false, err, 1024); } def onFuncValidationFinish(module: Module, func: FuncDecl, err: ErrorGen) { if (err != null && !err.ok()) return; From 28cd098cbdbcd9eb7ebefa5d83a742c0736ecad7 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 14:33:38 -0400 Subject: [PATCH 59/91] Deduplicate Mmap.reserve --- src/engine/x86-64/Mmap.v3 | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/engine/x86-64/Mmap.v3 b/src/engine/x86-64/Mmap.v3 index cdf21e2ae..61713fdcd 100644 --- a/src/engine/x86-64/Mmap.v3 +++ b/src/engine/x86-64/Mmap.v3 @@ -9,17 +9,12 @@ component Mmap { def PROT_EXEC = LinuxConst.PROT_EXEC; def reserve(size: u64, prot: int) -> Mapping { - var flags = LinuxConst.MAP_PRIVATE | LinuxConst.MAP_ANONYMOUS; - var r = Linux.syscall(LinuxConst.SYS_mmap, (Pointer.NULL, size, prot, flags, 0, 0)); - if (r.0 == -1) return null; - var start = Pointer.NULL + r.0, end = start + i64.view(size); - var range = MemoryRange.new(start, end); - var mapping = Mapping.new(range); - RiGc.registerFinalizer(mapping, range.unmap); - return mapping; + return _reserve(size, prot, LinuxConst.MAP_PRIVATE | LinuxConst.MAP_ANONYMOUS); } def reserve32(size: u64, prot: int) -> Mapping { - var flags = LinuxConst.MAP_PRIVATE | LinuxConst.MAP_ANONYMOUS | 0x40; // 0x40 = MAP_32BIT + return _reserve(size, prot, LinuxConst.MAP_PRIVATE | LinuxConst.MAP_ANONYMOUS | 0x40); // 0x40 = MAP_32BIT + } + private def _reserve(size: u64, prot: int, flags: int) -> Mapping { var r = Linux.syscall(LinuxConst.SYS_mmap, (Pointer.NULL, size, prot, flags, 0, 0)); if (r.0 == -1) return null; var start = Pointer.NULL + r.0, end = start + i64.view(size); From 351ecbb8bc27b6d68ee6379fa78152cb20806148 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 14:51:01 -0400 Subject: [PATCH 60/91] Remove FAST_SPC_EXEC_ENV --- src/engine/compiler/SinglePassCompiler.v3 | 15 ++--- src/engine/x86-64/X86_64MasmRegs.v3 | 65 +++++++++---------- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 2 +- 3 files changed, 37 insertions(+), 45 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 747553022..ebf6b3cd3 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -78,9 +78,6 @@ def KIND_REF = SpcConsts.KIND_REF; def KIND_REF_U64 = SpcConsts.KIND_REF_U64; def KIND_CONT = SpcConsts.KIND_CONT; -// Unlike frame.frameSize, where it is 0 for fast contexts. These are always the -// true frame size (for stack reconstruction methods). -def FRAME_SIZE = X86_64InterpreterFrame.size; // Compiles Wasm bytecode to machine code in a single pass via a MacroAssembler. class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAlloc, extensions: Extension.set, limits: Limits, fast: bool) extends BytecodeVisitor { @@ -1014,7 +1011,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl resolver.emitMoves(); state.sp = count; // adjust frame - masm.emit_addw_r_i(regs.sp, frame.frameSize); + if (!fast) masm.emit_addw_r_i(regs.sp, frame.frameSize); } def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, tailCall: bool) { var sig = SigDecl.!(module.heaptypes[sig_index]); @@ -2200,7 +2197,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def emitTrapReturn(label: MasmLabel, reason: TrapReason) { if (label != null) masm.bindLabel(label); masm.emit_mov_r_trap(regs.ret_throw, reason); - masm.emit_addw_r_i(regs.sp, frame.frameSize); + if (!fast) masm.emit_addw_r_i(regs.sp, frame.frameSize); masm.emit_ret(); } def newTrapLabel(reason: TrapReason) -> MasmLabel { @@ -2255,7 +2252,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_v3_Instance_functions_r_r(func_reg, inst_reg); // Pre-allocate stack space for all reconstructed frames at once. - def total_space = (frames.length - 1) * (FRAME_SIZE + 8); + def total_space = (frames.length - 1) * (frame.frameSize + 8); masm.emit_subw_r_i(regs.sp, total_space); // Process the inlined frames (skip the outermost which already exists on native stack) @@ -2275,9 +2272,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Use inlined frame stub IP as return address for all reconstructed frames def return_addr = getSpcInlinedFrameIp(); - def frame_offset = offset * (FRAME_SIZE + 8); + def frame_offset = offset * (frame.frameSize + 8); // Write inlined frame stub IP as return address - def retaddr_slot = MasmAddr(regs.sp, frame_offset + FRAME_SIZE); + def retaddr_slot = MasmAddr(regs.sp, frame_offset + frame.frameSize); masm.emit_mov_m_l(retaddr_slot, return_addr); // get functions[func_index] and save into frame @@ -2338,7 +2335,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (space > 0) { if (fast) { // reload VFP from the deepest inlined frame - masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot.plus(space - FRAME_SIZE - 8)); + masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot.plus(space - frame.frameSize - 8)); masm.emit_addw_r_i(regs.sp, space); restoreCallerIVars(); diff --git a/src/engine/x86-64/X86_64MasmRegs.v3 b/src/engine/x86-64/X86_64MasmRegs.v3 index ddb9990aa..e47023488 100644 --- a/src/engine/x86-64/X86_64MasmRegs.v3 +++ b/src/engine/x86-64/X86_64MasmRegs.v3 @@ -88,34 +88,33 @@ component X86_64MasmRegs { return config; })(); - // Build the SPC, fast-SPC, and INT execution environments together. - private def t = (fun -> (SpcExecEnv, SpcExecEnv, IntExecEnv) { + // Build both the SPC and INT execution environments together. + private def t = (fun -> (SpcExecEnv, IntExecEnv) { var xspc = SpcExecEnv.new(); - var xfast = SpcExecEnv.new(); var xint = IntExecEnv.new(); - xint.sp = xspc.sp = xfast.sp = RSP; - xint.func_arg = xspc.func_arg = xfast.func_arg = RDX; // cache of frame (callee-restore) - xint.vsp = xspc.vsp = xfast.vsp = RSI; - xint.vfp = xspc.vfp = xfast.vfp = R11; - xint.mem0_base = xspc.mem0_base = xfast.mem0_base = R10; // cache of frame (callee-restore) - xint.instance = xspc.instance = xfast.instance = RDI; // cache of frame (callee-restore) - xint.runtime_arg0 = xspc.runtime_arg0 = xfast.runtime_arg0 = RSI; - xint.runtime_arg1 = xspc.runtime_arg1 = xfast.runtime_arg1 = RDX; - xint.runtime_arg2 = xspc.runtime_arg2 = xfast.runtime_arg2 = RCX; - xint.runtime_arg3 = xspc.runtime_arg3 = xfast.runtime_arg3 = R8; - xint.runtime_arg4 = xspc.runtime_arg4 = xfast.runtime_arg4 = R9; - xint.ret_throw = xspc.ret_throw = xfast.ret_throw = RAX; - xint.runtime_ret0 = xspc.runtime_ret0 = xfast.runtime_ret0 = RAX; - xint.runtime_ret1 = xspc.runtime_ret1 = xfast.runtime_ret1 = RDX; - xint.scratch = xspc.scratch = xfast.scratch = RBP; + xint.sp = xspc.sp = RSP; + xint.func_arg = xspc.func_arg = RDX; + xint.vsp = xspc.vsp = RSI; + xint.vfp = xspc.vfp = R11; + xint.mem0_base = xspc.mem0_base = R10; + xint.instance = xspc.instance = RDI; + xint.runtime_arg0 = xspc.runtime_arg0 = RSI; + xint.runtime_arg1 = xspc.runtime_arg1 = RDX; + xint.runtime_arg2 = xspc.runtime_arg2 = RCX; + xint.runtime_arg3 = xspc.runtime_arg3 = R8; + xint.runtime_arg4 = xspc.runtime_arg4 = R9; + xint.ret_throw = xspc.ret_throw = RAX; + xint.runtime_ret0 = xspc.runtime_ret0 = RAX; + xint.runtime_ret1 = xspc.runtime_ret1 = RDX; + xint.scratch = xspc.scratch = RBP; xint.curpc = R15; xint.stp = RBX; xint.ip = RAX; xint.func_decl = R12; xint.eip = R13; - xint.dispatch = R14; // cache of field (see how it is saved/stored in interpreter) + xint.dispatch = R14; xint.xmm0 = XMM0; xint.xmm1 = XMM1; xint.xmm2 = XMM2; @@ -128,32 +127,29 @@ component X86_64MasmRegs { def m = MasmAddr(xspc.sp, _); - xint.accessor_slot = xspc.accessor_slot = xfast.accessor_slot = m(X86_64InterpreterFrame.accessor.offset); - xint.instance_slot = xspc.instance_slot = xfast.instance_slot = m(X86_64InterpreterFrame.instance.offset); - xint.mem0_base_slot = xspc.mem0_base_slot = xfast.mem0_base_slot = m(X86_64InterpreterFrame.mem0_base.offset); - xint.pc_slot = xspc.pc_slot = xfast.pc_slot = m(X86_64InterpreterFrame.curpc.offset); - xint.vfp_slot = xspc.vfp_slot = xfast.vfp_slot = m(X86_64InterpreterFrame.vfp.offset); - xint.vsp_slot = xspc.vsp_slot = xfast.vsp_slot = m(X86_64InterpreterFrame.vsp.offset); - xint.wasm_func_slot = xspc.wasm_func_slot = xfast.wasm_func_slot = m(X86_64InterpreterFrame.wasm_func.offset); - xint.ip_slot = xspc.inlined_mem0_base_slot = xfast.inlined_mem0_base_slot = m(X86_64InterpreterFrame.ip.offset); - xint.stp_slot = xspc.inlined_instance_slot = xfast.inlined_instance_slot = m(X86_64InterpreterFrame.stp.offset); + xint.accessor_slot = xspc.accessor_slot = m(X86_64InterpreterFrame.accessor.offset); + xint.instance_slot = xspc.instance_slot = m(X86_64InterpreterFrame.instance.offset); + xint.mem0_base_slot = xspc.mem0_base_slot = m(X86_64InterpreterFrame.mem0_base.offset); + xint.pc_slot = xspc.pc_slot = m(X86_64InterpreterFrame.curpc.offset); + xint.vfp_slot = xspc.vfp_slot = m(X86_64InterpreterFrame.vfp.offset); + xint.vsp_slot = xspc.vsp_slot = m(X86_64InterpreterFrame.vsp.offset); + xint.wasm_func_slot = xspc.wasm_func_slot = m(X86_64InterpreterFrame.wasm_func.offset); + xint.ip_slot = xspc.inlined_mem0_base_slot = m(X86_64InterpreterFrame.ip.offset); + xint.stp_slot = xspc.inlined_instance_slot = m(X86_64InterpreterFrame.stp.offset); xint.func_decl_slot = m(X86_64InterpreterFrame.func_decl.offset); xint.code_slot = m(X86_64InterpreterFrame.code.offset); xint.eip_slot = m(X86_64InterpreterFrame.eip.offset); xint.frameSize = xspc.frameSize = X86_64InterpreterFrame.size; - xfast.frameSize = 0; - return (xspc, xfast, xint); + return (xspc, xint); })(); // The execution environment for single-pass compilation contexts. def SPC_EXEC_ENV = t.0; - // The execution environment for fast single-pass compilation contexts. - def FAST_SPC_EXEC_ENV = t.1; // The execution environment for interpreter compilation contexts. - def INT_EXEC_ENV = t.2; + def INT_EXEC_ENV = t.1; // A register allocator for single-pass compilation contexts. def SPC_ALLOC = (fun -> RegAlloc { @@ -167,8 +163,7 @@ component X86_64MasmRegs { // A register allocator for interpreter contexts. def INT_ALLOC = (fun -> RegAlloc { var pools = [ - RegPool32.new([RCX, RDX, R8, R9]), // could use callee-restore (but put at end) - // if callee-restore registers are used, have to emit a restore at the end + RegPool32.new([RCX, RDX, R8, R9]), // TODO also use non-saved restore-only registers RegPool32.new([XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14]) ]; return RegAlloc.new(CONFIG.poolMap, pools, null); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 96caf4c1b..96f96b4ae 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -80,7 +80,7 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { var ic: X86_64InterpreterCode; new(ic, extensions: Extension.set, limits: Limits, config: RegConfig, fast: bool) - super(if(fast, X86_64MasmRegs.FAST_SPC_EXEC_ENV, X86_64MasmRegs.SPC_EXEC_ENV), mmasm, + super(X86_64MasmRegs.SPC_EXEC_ENV, mmasm, if(fast, X86_64MasmRegs.INT_ALLOC.copy(), X86_64MasmRegs.SPC_ALLOC.copy()), extensions, limits, fast) { mmasm.trap_stubs = TRAPS_STUB; From c2b27da17b25f0d63e8a7f62c74be6d8afea6d84 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 15:44:11 -0400 Subject: [PATCH 61/91] Rename _reserve to reserve_ --- src/engine/x86-64/Mmap.v3 | 6 +++--- src/monitors/.WhammMonitor.v3.swp | Bin 0 -> 1024 bytes 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 src/monitors/.WhammMonitor.v3.swp diff --git a/src/engine/x86-64/Mmap.v3 b/src/engine/x86-64/Mmap.v3 index 61713fdcd..1d66af365 100644 --- a/src/engine/x86-64/Mmap.v3 +++ b/src/engine/x86-64/Mmap.v3 @@ -9,12 +9,12 @@ component Mmap { def PROT_EXEC = LinuxConst.PROT_EXEC; def reserve(size: u64, prot: int) -> Mapping { - return _reserve(size, prot, LinuxConst.MAP_PRIVATE | LinuxConst.MAP_ANONYMOUS); + return reserve_(size, prot, LinuxConst.MAP_PRIVATE | LinuxConst.MAP_ANONYMOUS); } def reserve32(size: u64, prot: int) -> Mapping { - return _reserve(size, prot, LinuxConst.MAP_PRIVATE | LinuxConst.MAP_ANONYMOUS | 0x40); // 0x40 = MAP_32BIT + return reserve_(size, prot, LinuxConst.MAP_PRIVATE | LinuxConst.MAP_ANONYMOUS | 0x40); // 0x40 = MAP_32BIT } - private def _reserve(size: u64, prot: int, flags: int) -> Mapping { + private def reserve_(size: u64, prot: int, flags: int) -> Mapping { var r = Linux.syscall(LinuxConst.SYS_mmap, (Pointer.NULL, size, prot, flags, 0, 0)); if (r.0 == -1) return null; var start = Pointer.NULL + r.0, end = start + i64.view(size); diff --git a/src/monitors/.WhammMonitor.v3.swp b/src/monitors/.WhammMonitor.v3.swp new file mode 100644 index 0000000000000000000000000000000000000000..e88663d1be844a4a7ce71706a30dc406af157a18 GIT binary patch literal 1024 zcmYc?$V<%2S1{KzVn6|X2@DLmi6tc&spTl**f`~hrP-;)8Hw2Bkj26?5_5BX^Yb!G Y@{9D!jFF{A*`pya8UnNrflzcS0LqmRMF0Q* literal 0 HcmV?d00001 From cd863dcc7dc672468f5324bf9f4f38e366af22b8 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 16:03:50 -0400 Subject: [PATCH 62/91] Add more tests from CLAUDE --- test/fastcall/test35_br_table.wasm | Bin 0 -> 118 bytes test/fastcall/test35_br_table.wasm.exit | 1 + test/fastcall/test35_br_table.wasm.flags | 1 + test/fastcall/test35_br_table.wat | 38 + test/fastcall/test36_select.wasm | Bin 0 -> 95 bytes test/fastcall/test36_select.wasm.exit | 1 + test/fastcall/test36_select.wasm.flags | 1 + test/fastcall/test36_select.wat | 30 + .../fastcall/test37_div_rem_continuation.wasm | Bin 0 -> 92 bytes .../test37_div_rem_continuation.wasm.exit | 1 + .../test37_div_rem_continuation.wasm.flags | 1 + test/fastcall/test37_div_rem_continuation.wat | 28 + ...st38_caller_branches_around_fast_call.wasm | Bin 0 -> 117 bytes ...caller_branches_around_fast_call.wasm.exit | 1 + ...aller_branches_around_fast_call.wasm.flags | 1 + ...est38_caller_branches_around_fast_call.wat | 48 + test/fastcall/test39_memory_grow.wasm | Bin 0 -> 75 bytes test/fastcall/test39_memory_grow.wasm.exit | 1 + test/fastcall/test39_memory_grow.wasm.flags | 1 + test/fastcall/test39_memory_grow.wat | 14 + test/fastcall/test40_table_overflow.wasm | Bin 0 -> 1230 bytes test/fastcall/test40_table_overflow.wasm.exit | 1 + .../fastcall/test40_table_overflow.wasm.flags | 1 + test/fastcall/test40_table_overflow.wat | 93 + test/fastcall/test41_inline_loop.wasm | Bin 0 -> 101 bytes test/fastcall/test41_inline_loop.wasm.exit | 1 + test/fastcall/test41_inline_loop.wasm.flags | 1 + test/fastcall/test41_inline_loop.wat | 34 + test/fastcall/test42_inline_memory.wasm | Bin 0 -> 93 bytes test/fastcall/test42_inline_memory.wasm.exit | 1 + test/fastcall/test42_inline_memory.wasm.flags | 1 + test/fastcall/test42_inline_memory.wat | 21 + test/fastcall/test43_inline_global.wasm | Bin 0 -> 93 bytes test/fastcall/test43_inline_global.wasm.exit | 1 + test/fastcall/test43_inline_global.wasm.flags | 1 + test/fastcall/test43_inline_global.wat | 25 + test/fastcall/test44_inline_depth3.wasm | Bin 0 -> 93 bytes test/fastcall/test44_inline_depth3.wasm.exit | 1 + test/fastcall/test44_inline_depth3.wasm.flags | 1 + test/fastcall/test44_inline_depth3.wat | 24 + test/fastcall/test45_large_handler.wasm | Bin 0 -> 197 bytes test/fastcall/test45_large_handler.wasm.exit | 1 + test/fastcall/test45_large_handler.wasm.flags | 1 + test/fastcall/test45_large_handler.wat | 57 + test/fastcall/test46_many_callsites.wasm | Bin 0 -> 674 bytes test/fastcall/test46_many_callsites.wasm.exit | 1 + .../fastcall/test46_many_callsites.wasm.flags | 1 + test/fastcall/test46_many_callsites.wat | 112 + .../test47_large_caller_branches.wasm | Bin 0 -> 385 bytes .../test47_large_caller_branches.wasm.exit | 1 + .../test47_large_caller_branches.wasm.flags | 1 + .../fastcall/test47_large_caller_branches.wat | 76 + test/fastcall/test48_large_inline.wasm | Bin 0 -> 206 bytes test/fastcall/test48_large_inline.wasm.exit | 1 + test/fastcall/test48_large_inline.wasm.flags | 1 + test/fastcall/test48_large_inline.wat | 47 + test/fastcall/test49_leb2_func_index.wasm | Bin 0 -> 587 bytes .../fastcall/test49_leb2_func_index.wasm.exit | 1 + .../test49_leb2_func_index.wasm.flags | 1 + test/fastcall/test49_leb2_func_index.wat | 140 + test/fastcall/test50_leb3_func_index.wasm | Bin 0 -> 65618 bytes .../fastcall/test50_leb3_func_index.wasm.exit | 1 + .../test50_leb3_func_index.wasm.flags | 1 + test/fastcall/test50_leb3_func_index.wat | 16396 ++++++++++++++++ test/fastcall/test51_mixed_calls_flat.wasm | Bin 0 -> 358 bytes .../test51_mixed_calls_flat.wasm.exit | 1 + .../test51_mixed_calls_flat.wasm.flags | 1 + test/fastcall/test51_mixed_calls_flat.wat | 73 + test/fastcall/test52_mixed_calls_nested.wasm | Bin 0 -> 319 bytes .../test52_mixed_calls_nested.wasm.exit | 1 + .../test52_mixed_calls_nested.wasm.flags | 1 + test/fastcall/test52_mixed_calls_nested.wat | 74 + 72 files changed, 17366 insertions(+) create mode 100644 test/fastcall/test35_br_table.wasm create mode 100644 test/fastcall/test35_br_table.wasm.exit create mode 100644 test/fastcall/test35_br_table.wasm.flags create mode 100644 test/fastcall/test35_br_table.wat create mode 100644 test/fastcall/test36_select.wasm create mode 100644 test/fastcall/test36_select.wasm.exit create mode 100644 test/fastcall/test36_select.wasm.flags create mode 100644 test/fastcall/test36_select.wat create mode 100644 test/fastcall/test37_div_rem_continuation.wasm create mode 100644 test/fastcall/test37_div_rem_continuation.wasm.exit create mode 100644 test/fastcall/test37_div_rem_continuation.wasm.flags create mode 100644 test/fastcall/test37_div_rem_continuation.wat create mode 100644 test/fastcall/test38_caller_branches_around_fast_call.wasm create mode 100644 test/fastcall/test38_caller_branches_around_fast_call.wasm.exit create mode 100644 test/fastcall/test38_caller_branches_around_fast_call.wasm.flags create mode 100644 test/fastcall/test38_caller_branches_around_fast_call.wat create mode 100644 test/fastcall/test39_memory_grow.wasm create mode 100644 test/fastcall/test39_memory_grow.wasm.exit create mode 100644 test/fastcall/test39_memory_grow.wasm.flags create mode 100644 test/fastcall/test39_memory_grow.wat create mode 100644 test/fastcall/test40_table_overflow.wasm create mode 100644 test/fastcall/test40_table_overflow.wasm.exit create mode 100644 test/fastcall/test40_table_overflow.wasm.flags create mode 100644 test/fastcall/test40_table_overflow.wat create mode 100644 test/fastcall/test41_inline_loop.wasm create mode 100644 test/fastcall/test41_inline_loop.wasm.exit create mode 100644 test/fastcall/test41_inline_loop.wasm.flags create mode 100644 test/fastcall/test41_inline_loop.wat create mode 100644 test/fastcall/test42_inline_memory.wasm create mode 100644 test/fastcall/test42_inline_memory.wasm.exit create mode 100644 test/fastcall/test42_inline_memory.wasm.flags create mode 100644 test/fastcall/test42_inline_memory.wat create mode 100644 test/fastcall/test43_inline_global.wasm create mode 100644 test/fastcall/test43_inline_global.wasm.exit create mode 100644 test/fastcall/test43_inline_global.wasm.flags create mode 100644 test/fastcall/test43_inline_global.wat create mode 100644 test/fastcall/test44_inline_depth3.wasm create mode 100644 test/fastcall/test44_inline_depth3.wasm.exit create mode 100644 test/fastcall/test44_inline_depth3.wasm.flags create mode 100644 test/fastcall/test44_inline_depth3.wat create mode 100644 test/fastcall/test45_large_handler.wasm create mode 100644 test/fastcall/test45_large_handler.wasm.exit create mode 100644 test/fastcall/test45_large_handler.wasm.flags create mode 100644 test/fastcall/test45_large_handler.wat create mode 100644 test/fastcall/test46_many_callsites.wasm create mode 100644 test/fastcall/test46_many_callsites.wasm.exit create mode 100644 test/fastcall/test46_many_callsites.wasm.flags create mode 100644 test/fastcall/test46_many_callsites.wat create mode 100644 test/fastcall/test47_large_caller_branches.wasm create mode 100644 test/fastcall/test47_large_caller_branches.wasm.exit create mode 100644 test/fastcall/test47_large_caller_branches.wasm.flags create mode 100644 test/fastcall/test47_large_caller_branches.wat create mode 100644 test/fastcall/test48_large_inline.wasm create mode 100644 test/fastcall/test48_large_inline.wasm.exit create mode 100644 test/fastcall/test48_large_inline.wasm.flags create mode 100644 test/fastcall/test48_large_inline.wat create mode 100644 test/fastcall/test49_leb2_func_index.wasm create mode 100644 test/fastcall/test49_leb2_func_index.wasm.exit create mode 100644 test/fastcall/test49_leb2_func_index.wasm.flags create mode 100644 test/fastcall/test49_leb2_func_index.wat create mode 100644 test/fastcall/test50_leb3_func_index.wasm create mode 100644 test/fastcall/test50_leb3_func_index.wasm.exit create mode 100644 test/fastcall/test50_leb3_func_index.wasm.flags create mode 100644 test/fastcall/test50_leb3_func_index.wat create mode 100644 test/fastcall/test51_mixed_calls_flat.wasm create mode 100644 test/fastcall/test51_mixed_calls_flat.wasm.exit create mode 100644 test/fastcall/test51_mixed_calls_flat.wasm.flags create mode 100644 test/fastcall/test51_mixed_calls_flat.wat create mode 100644 test/fastcall/test52_mixed_calls_nested.wasm create mode 100644 test/fastcall/test52_mixed_calls_nested.wasm.exit create mode 100644 test/fastcall/test52_mixed_calls_nested.wasm.flags create mode 100644 test/fastcall/test52_mixed_calls_nested.wat diff --git a/test/fastcall/test35_br_table.wasm b/test/fastcall/test35_br_table.wasm new file mode 100644 index 0000000000000000000000000000000000000000..353257c70dabaaa49ed0be181fef8e9466e21bb3 GIT binary patch literal 118 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mW@2Dumtf*eODrz2O35rPNGwUtU|?X$P0Y*# zs&r(MVPJ9qK?MdrW(GzkCT>SAer`t*AeQ6jR$_2u5MXfRa(83|QX=j}j!ZyW4oE)+ Ii31tj0H!q)jQ{`u literal 0 HcmV?d00001 diff --git a/test/fastcall/test35_br_table.wasm.exit b/test/fastcall/test35_br_table.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test35_br_table.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test35_br_table.wasm.flags b/test/fastcall/test35_br_table.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test35_br_table.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test35_br_table.wat b/test/fastcall/test35_br_table.wat new file mode 100644 index 000000000..a72972a41 --- /dev/null +++ b/test/fastcall/test35_br_table.wat @@ -0,0 +1,38 @@ +;; Fast handler uses br_table: maps 0->10, 1->20, 2->30, else->0. +(module + (func $dispatch (export "fast:dispatch") (param $n i32) (result i32) + (block $b2 + (block $b1 + (block $b0 + local.get $n + br_table $b0 $b1 $b2 $b2) + i32.const 10 + return) + i32.const 20 + return) + i32.const 30 + return) + (func (export "main") (result i32) + i32.const 0 + call $dispatch + i32.const 10 + i32.ne + + i32.const 1 + call $dispatch + i32.const 20 + i32.ne + i32.or + + i32.const 2 + call $dispatch + i32.const 30 + i32.ne + i32.or + + i32.const 99 + call $dispatch + i32.const 30 + i32.ne + i32.or) +) diff --git a/test/fastcall/test36_select.wasm b/test/fastcall/test36_select.wasm new file mode 100644 index 0000000000000000000000000000000000000000..8719ddd4063941e9261578e2b00003751ab57aa9 GIT binary patch literal 95 zcmZQbEY4+QU|?Y6W=deHuV<`JU|_6gW@chwWEW=QNJ}g(vC2)XU|?X$P0Y+=VC2$c r;$cu=P+$aMFKKRh21j;BW&t4S?#SfG31o1(7df&zvI1GG?nT@H@Zt{M literal 0 HcmV?d00001 diff --git a/test/fastcall/test36_select.wasm.exit b/test/fastcall/test36_select.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test36_select.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test36_select.wasm.flags b/test/fastcall/test36_select.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test36_select.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test36_select.wat b/test/fastcall/test36_select.wat new file mode 100644 index 000000000..ed5642c7e --- /dev/null +++ b/test/fastcall/test36_select.wat @@ -0,0 +1,30 @@ +;; Fast handler uses select: branchless conditional. +(module + (func $max (export "fast:max") (param $a i32) (param $b i32) (result i32) + local.get $a + local.get $b + local.get $a + local.get $b + i32.gt_s + select) + (func (export "main") (result i32) + i32.const 7 + i32.const 3 + call $max + i32.const 7 + i32.ne + + i32.const 2 + i32.const 9 + call $max + i32.const 9 + i32.ne + i32.or + + i32.const 5 + i32.const 5 + call $max + i32.const 5 + i32.ne + i32.or) +) diff --git a/test/fastcall/test37_div_rem_continuation.wasm b/test/fastcall/test37_div_rem_continuation.wasm new file mode 100644 index 0000000000000000000000000000000000000000..35b730f0eb924fc1bf4d1d00c76601f0298ab6fe GIT binary patch literal 92 zcmWl~u?|2m6a~=xUWr5#VG>(A_z7DlztIjPL`&3UdA}~sau9MP0HoQo2#E)YQVgmF rZq|^WDV=u=$M!Bj5yO^1^~gQ37#K>H|1PTx8?|c<*SWHVD`))yH0=;0 literal 0 HcmV?d00001 diff --git a/test/fastcall/test37_div_rem_continuation.wasm.exit b/test/fastcall/test37_div_rem_continuation.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test37_div_rem_continuation.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test37_div_rem_continuation.wasm.flags b/test/fastcall/test37_div_rem_continuation.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test37_div_rem_continuation.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test37_div_rem_continuation.wat b/test/fastcall/test37_div_rem_continuation.wat new file mode 100644 index 000000000..f206454c0 --- /dev/null +++ b/test/fastcall/test37_div_rem_continuation.wat @@ -0,0 +1,28 @@ +;; Fast handler uses div and rem (clobbers RAX/RDX), then continues with more work. +;; Tests that r_ip (RAX) and other clobbered registers are correctly handled +;; when arithmetic that clobbers the same hardware registers as interpreter ivars +;; is followed by further computation before the fast epilogue. +(module + (func $normalize (export "fast:normalize") (param $x i32) (param $mod i32) (result i32) + ;; compute (x / mod) + (x % mod) + (local $q i32) + (local $r i32) + local.get $x + local.get $mod + i32.div_u + local.set $q + local.get $x + local.get $mod + i32.rem_u + local.set $r + local.get $q + local.get $r + i32.add) + (func (export "main") (result i32) + ;; normalize(17, 5) = 3 + 2 = 5 + i32.const 17 + i32.const 5 + call $normalize + i32.const 5 + i32.ne) +) diff --git a/test/fastcall/test38_caller_branches_around_fast_call.wasm b/test/fastcall/test38_caller_branches_around_fast_call.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a7171a4550402951c8f2af2d1dca8765ec22f399 GIT binary patch literal 117 zcmZ9C%?dz36ot>ZSB(s%ya2DkhK1}rgGs4TW5a%4on&SC{lJ}p0GP?b$hd$}RX|fo ty1Dae{jmZ`aQ=9vQ4DGf+-*mR(rf>a&IMoDAcwUzN;LSI`M1GL_69HW5G()y literal 0 HcmV?d00001 diff --git a/test/fastcall/test38_caller_branches_around_fast_call.wasm.exit b/test/fastcall/test38_caller_branches_around_fast_call.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test38_caller_branches_around_fast_call.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test38_caller_branches_around_fast_call.wasm.flags b/test/fastcall/test38_caller_branches_around_fast_call.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test38_caller_branches_around_fast_call.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test38_caller_branches_around_fast_call.wat b/test/fastcall/test38_caller_branches_around_fast_call.wat new file mode 100644 index 000000000..0bcd63794 --- /dev/null +++ b/test/fastcall/test38_caller_branches_around_fast_call.wat @@ -0,0 +1,48 @@ +;; Interpreter caller executes branches both before and after a fast call. +;; This stresses r_stp: the interpreter must have an up-to-date sidetable +;; pointer after returning from the fast handler so that subsequent branches +;; in the caller use the correct sidetable entry. +(module + (func $inc (export "fast:inc") (param i32) (result i32) + local.get 0 + i32.const 1 + i32.add) + (func (export "main") (result i32) + (local $i i32) + (local $sum i32) + ;; Loop 1: branches before the fast call accumulates in $i + block $b1 + loop $l1 + local.get $i + i32.const 3 + i32.ge_s + br_if $b1 + local.get $i + i32.const 1 + i32.add + local.set $i + br $l1 + end + end + ;; Fast call + local.get $i + call $inc ;; $i = 3, returns 4 + local.set $i + ;; Loop 2: branches after the fast call, r_stp must be valid here + block $b2 + loop $l2 + local.get $i + i32.const 7 + i32.ge_s + br_if $b2 + local.get $i + i32.const 1 + i32.add + local.set $i + br $l2 + end + end + local.get $i + i32.const 7 + i32.ne) +) diff --git a/test/fastcall/test39_memory_grow.wasm b/test/fastcall/test39_memory_grow.wasm new file mode 100644 index 0000000000000000000000000000000000000000..dde44b81e1478c9c688c67fc4fa9fa638b07dc0b GIT binary patch literal 75 zcmZQbEY4+QU|?WmWlUgTtY>CsVqjopW@KPwmtzu6ODrz2N-xSUk59}?iBHZ*P0nUu cV98C)%wu5W5@2FuaAb5~;AUqK05aUU0qk%M5C8xG literal 0 HcmV?d00001 diff --git a/test/fastcall/test39_memory_grow.wasm.exit b/test/fastcall/test39_memory_grow.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test39_memory_grow.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test39_memory_grow.wasm.flags b/test/fastcall/test39_memory_grow.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test39_memory_grow.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test39_memory_grow.wat b/test/fastcall/test39_memory_grow.wat new file mode 100644 index 000000000..fa5eaaaa2 --- /dev/null +++ b/test/fastcall/test39_memory_grow.wat @@ -0,0 +1,14 @@ +;; Fast handler calls memory.grow, which is an expensive runtime out-call that +;; reloads r_mem0_base. Tests that the fast epilogue's restoreCallerIVars +;; correctly reloads all interpreter registers after a call that mutates memory. +(module + (memory 1) + (func $grow_and_check (export "fast:grow_and_check") (result i32) + ;; grow by 1 page, return old size (should be 1) + i32.const 1 + memory.grow) + (func (export "main") (result i32) + call $grow_and_check + i32.const 1 + i32.ne) +) diff --git a/test/fastcall/test40_table_overflow.wasm b/test/fastcall/test40_table_overflow.wasm new file mode 100644 index 0000000000000000000000000000000000000000..77539c58a9a9446424a94810158dd0c46a61f8b3 GIT binary patch literal 1230 zcma*lH%&ujiqx4F{Q z!};yS05Gm~GKon}Fo}J?xlR7}jPqe{oXh#`{o&#RQ~*PTu&4+&6(dD$k*0RYPD2iK@#2w1w9u@I`s(3_=41Lta01YujQ;g6OW3Vt|ntVk}0Oh%u((7Bg{&xwywdJYXpvu_9w1>(tBn`4xBW zXL{pcj7M|zervHdn_|;!hIQC1n`2$pWAki*EwUxH%vRVcTVv~NgKe@cw#|0fF56@K z?0_AzBX-PA*eN?>=j?)AvMYAY-d(+K%b4U5<=Z*06Wm|~OR$BMkQOq6BV>h~;0m6Q z7YagAC<$euB29JAI^CI literal 0 HcmV?d00001 diff --git a/test/fastcall/test40_table_overflow.wasm.exit b/test/fastcall/test40_table_overflow.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test40_table_overflow.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test40_table_overflow.wasm.flags b/test/fastcall/test40_table_overflow.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test40_table_overflow.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test40_table_overflow.wat b/test/fastcall/test40_table_overflow.wat new file mode 100644 index 000000000..3d9ea8f46 --- /dev/null +++ b/test/fastcall/test40_table_overflow.wat @@ -0,0 +1,93 @@ +;; 41 functions exported with fast: names; the 41st exceeds FAST_CALL_OPCODES (40). +;; The 41st function must fall back to a regular call rather than crashing. +;; All 41 calls must produce correct results. +(module + (func $f0 (export "fast:f0") (param i32) (result i32) local.get 0 i32.const 1 i32.add) + (func $f1 (export "fast:f1") (param i32) (result i32) local.get 0 i32.const 2 i32.add) + (func $f2 (export "fast:f2") (param i32) (result i32) local.get 0 i32.const 3 i32.add) + (func $f3 (export "fast:f3") (param i32) (result i32) local.get 0 i32.const 4 i32.add) + (func $f4 (export "fast:f4") (param i32) (result i32) local.get 0 i32.const 5 i32.add) + (func $f5 (export "fast:f5") (param i32) (result i32) local.get 0 i32.const 6 i32.add) + (func $f6 (export "fast:f6") (param i32) (result i32) local.get 0 i32.const 7 i32.add) + (func $f7 (export "fast:f7") (param i32) (result i32) local.get 0 i32.const 8 i32.add) + (func $f8 (export "fast:f8") (param i32) (result i32) local.get 0 i32.const 9 i32.add) + (func $f9 (export "fast:f9") (param i32) (result i32) local.get 0 i32.const 10 i32.add) + (func $f10 (export "fast:f10") (param i32) (result i32) local.get 0 i32.const 11 i32.add) + (func $f11 (export "fast:f11") (param i32) (result i32) local.get 0 i32.const 12 i32.add) + (func $f12 (export "fast:f12") (param i32) (result i32) local.get 0 i32.const 13 i32.add) + (func $f13 (export "fast:f13") (param i32) (result i32) local.get 0 i32.const 14 i32.add) + (func $f14 (export "fast:f14") (param i32) (result i32) local.get 0 i32.const 15 i32.add) + (func $f15 (export "fast:f15") (param i32) (result i32) local.get 0 i32.const 16 i32.add) + (func $f16 (export "fast:f16") (param i32) (result i32) local.get 0 i32.const 17 i32.add) + (func $f17 (export "fast:f17") (param i32) (result i32) local.get 0 i32.const 18 i32.add) + (func $f18 (export "fast:f18") (param i32) (result i32) local.get 0 i32.const 19 i32.add) + (func $f19 (export "fast:f19") (param i32) (result i32) local.get 0 i32.const 20 i32.add) + (func $f20 (export "fast:f20") (param i32) (result i32) local.get 0 i32.const 21 i32.add) + (func $f21 (export "fast:f21") (param i32) (result i32) local.get 0 i32.const 22 i32.add) + (func $f22 (export "fast:f22") (param i32) (result i32) local.get 0 i32.const 23 i32.add) + (func $f23 (export "fast:f23") (param i32) (result i32) local.get 0 i32.const 24 i32.add) + (func $f24 (export "fast:f24") (param i32) (result i32) local.get 0 i32.const 25 i32.add) + (func $f25 (export "fast:f25") (param i32) (result i32) local.get 0 i32.const 26 i32.add) + (func $f26 (export "fast:f26") (param i32) (result i32) local.get 0 i32.const 27 i32.add) + (func $f27 (export "fast:f27") (param i32) (result i32) local.get 0 i32.const 28 i32.add) + (func $f28 (export "fast:f28") (param i32) (result i32) local.get 0 i32.const 29 i32.add) + (func $f29 (export "fast:f29") (param i32) (result i32) local.get 0 i32.const 30 i32.add) + (func $f30 (export "fast:f30") (param i32) (result i32) local.get 0 i32.const 31 i32.add) + (func $f31 (export "fast:f31") (param i32) (result i32) local.get 0 i32.const 32 i32.add) + (func $f32 (export "fast:f32") (param i32) (result i32) local.get 0 i32.const 33 i32.add) + (func $f33 (export "fast:f33") (param i32) (result i32) local.get 0 i32.const 34 i32.add) + (func $f34 (export "fast:f34") (param i32) (result i32) local.get 0 i32.const 35 i32.add) + (func $f35 (export "fast:f35") (param i32) (result i32) local.get 0 i32.const 36 i32.add) + (func $f36 (export "fast:f36") (param i32) (result i32) local.get 0 i32.const 37 i32.add) + (func $f37 (export "fast:f37") (param i32) (result i32) local.get 0 i32.const 38 i32.add) + (func $f38 (export "fast:f38") (param i32) (result i32) local.get 0 i32.const 39 i32.add) + (func $f39 (export "fast:f39") (param i32) (result i32) local.get 0 i32.const 40 i32.add) + ;; 41st: no slot available, must fall back to normal call + (func $f40 (export "fast:f40") (param i32) (result i32) local.get 0 i32.const 41 i32.add) + (func (export "main") (result i32) + (local $acc i32) + i32.const 0 call $f0 local.get $acc i32.add local.set $acc + i32.const 0 call $f1 local.get $acc i32.add local.set $acc + i32.const 0 call $f2 local.get $acc i32.add local.set $acc + i32.const 0 call $f3 local.get $acc i32.add local.set $acc + i32.const 0 call $f4 local.get $acc i32.add local.set $acc + i32.const 0 call $f5 local.get $acc i32.add local.set $acc + i32.const 0 call $f6 local.get $acc i32.add local.set $acc + i32.const 0 call $f7 local.get $acc i32.add local.set $acc + i32.const 0 call $f8 local.get $acc i32.add local.set $acc + i32.const 0 call $f9 local.get $acc i32.add local.set $acc + i32.const 0 call $f10 local.get $acc i32.add local.set $acc + i32.const 0 call $f11 local.get $acc i32.add local.set $acc + i32.const 0 call $f12 local.get $acc i32.add local.set $acc + i32.const 0 call $f13 local.get $acc i32.add local.set $acc + i32.const 0 call $f14 local.get $acc i32.add local.set $acc + i32.const 0 call $f15 local.get $acc i32.add local.set $acc + i32.const 0 call $f16 local.get $acc i32.add local.set $acc + i32.const 0 call $f17 local.get $acc i32.add local.set $acc + i32.const 0 call $f18 local.get $acc i32.add local.set $acc + i32.const 0 call $f19 local.get $acc i32.add local.set $acc + i32.const 0 call $f20 local.get $acc i32.add local.set $acc + i32.const 0 call $f21 local.get $acc i32.add local.set $acc + i32.const 0 call $f22 local.get $acc i32.add local.set $acc + i32.const 0 call $f23 local.get $acc i32.add local.set $acc + i32.const 0 call $f24 local.get $acc i32.add local.set $acc + i32.const 0 call $f25 local.get $acc i32.add local.set $acc + i32.const 0 call $f26 local.get $acc i32.add local.set $acc + i32.const 0 call $f27 local.get $acc i32.add local.set $acc + i32.const 0 call $f28 local.get $acc i32.add local.set $acc + i32.const 0 call $f29 local.get $acc i32.add local.set $acc + i32.const 0 call $f30 local.get $acc i32.add local.set $acc + i32.const 0 call $f31 local.get $acc i32.add local.set $acc + i32.const 0 call $f32 local.get $acc i32.add local.set $acc + i32.const 0 call $f33 local.get $acc i32.add local.set $acc + i32.const 0 call $f34 local.get $acc i32.add local.set $acc + i32.const 0 call $f35 local.get $acc i32.add local.set $acc + i32.const 0 call $f36 local.get $acc i32.add local.set $acc + i32.const 0 call $f37 local.get $acc i32.add local.set $acc + i32.const 0 call $f38 local.get $acc i32.add local.set $acc + i32.const 0 call $f39 local.get $acc i32.add local.set $acc + i32.const 0 call $f40 local.get $acc i32.add local.set $acc + local.get $acc + i32.const 861 ;; 1+2+3+...+41 = 861 + i32.ne) +) diff --git a/test/fastcall/test41_inline_loop.wasm b/test/fastcall/test41_inline_loop.wasm new file mode 100644 index 0000000000000000000000000000000000000000..7e3aab54d4e49c697a39497ca507e536e0236864 GIT binary patch literal 101 zcmWN_y$(Py7zNOKTR+i{gg2;o2ZKo`i-%~JCJ0OIeRalj5YkNmG|DqGdob%l|4|RB uiXpvA1dBTy50shpL}s<>)xu%#Xz6&4{KacT3lU4HV9`SwxU#1!H~9bph7CXf literal 0 HcmV?d00001 diff --git a/test/fastcall/test41_inline_loop.wasm.exit b/test/fastcall/test41_inline_loop.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test41_inline_loop.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test41_inline_loop.wasm.flags b/test/fastcall/test41_inline_loop.wasm.flags new file mode 100644 index 000000000..15e24ecd1 --- /dev/null +++ b/test/fastcall/test41_inline_loop.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=1 diff --git a/test/fastcall/test41_inline_loop.wat b/test/fastcall/test41_inline_loop.wat new file mode 100644 index 000000000..5b61106a1 --- /dev/null +++ b/test/fastcall/test41_inline_loop.wat @@ -0,0 +1,34 @@ +;; Fast handler inlines a callee that contains a loop. +;; Tests that backward branches inside an inlined function within a fast handler +;; work correctly (loop/br_if in inlined context). +(module + (func $count_down (param $n i32) (result i32) + ;; returns the count of iterations: loops from n down to 0 + (local $acc i32) + block $break + loop $cont + local.get $n + i32.const 0 + i32.le_s + br_if $break + local.get $acc + i32.const 1 + i32.add + local.set $acc + local.get $n + i32.const 1 + i32.sub + local.set $n + br $cont + end + end + local.get $acc) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $count_down) + (func (export "main") (result i32) + i32.const 5 + call $f + i32.const 5 + i32.ne) +) diff --git a/test/fastcall/test42_inline_memory.wasm b/test/fastcall/test42_inline_memory.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a3e4ee9f462e2e0297c2521e11b172ae8023a695 GIT binary patch literal 93 zcmWl~D-M7#5Cy>ZcKH;VkaB}27{UP%xGJvEnkEP^;Cpqz%plz-0nllbQdlB?z@n9c oQY*oBlqRS9*)mw2>9`>Mqys!WSNWO+)*u)U2iqYmj$zsD3!#Gyf&c&j literal 0 HcmV?d00001 diff --git a/test/fastcall/test42_inline_memory.wasm.exit b/test/fastcall/test42_inline_memory.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test42_inline_memory.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test42_inline_memory.wasm.flags b/test/fastcall/test42_inline_memory.wasm.flags new file mode 100644 index 000000000..15e24ecd1 --- /dev/null +++ b/test/fastcall/test42_inline_memory.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=1 diff --git a/test/fastcall/test42_inline_memory.wat b/test/fastcall/test42_inline_memory.wat new file mode 100644 index 000000000..5481bf122 --- /dev/null +++ b/test/fastcall/test42_inline_memory.wat @@ -0,0 +1,21 @@ +;; Fast handler inlines a callee that accesses linear memory. +;; Tests that r_mem0_base is correctly available inside an inlined function +;; within a fast-compiled handler. +(module + (memory 1) + (func $store_and_load (param $addr i32) (param $val i32) (result i32) + local.get $addr + local.get $val + i32.store + local.get $addr + i32.load) + (func $f (export "fast:f") (param i32) (result i32) + i32.const 8 + local.get 0 + call $store_and_load) + (func (export "main") (result i32) + i32.const 42 + call $f + i32.const 42 + i32.ne) +) diff --git a/test/fastcall/test43_inline_global.wasm b/test/fastcall/test43_inline_global.wasm new file mode 100644 index 0000000000000000000000000000000000000000..24accb4c85d44d3061a13016e2a2d082b9c22196 GIT binary patch literal 93 zcmWNFy$ygM5JtZP#Dpt^4NNo+VMoOp(2!_?h1j#YSG^yU-Ut9Wm1)q(prMVHVXbro m&q3K*`gc~4Y2|vL+@Tp8R@}RQt(XS~MCU2G6eq!wUj6}VdJJ{| literal 0 HcmV?d00001 diff --git a/test/fastcall/test43_inline_global.wasm.exit b/test/fastcall/test43_inline_global.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test43_inline_global.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test43_inline_global.wasm.flags b/test/fastcall/test43_inline_global.wasm.flags new file mode 100644 index 000000000..15e24ecd1 --- /dev/null +++ b/test/fastcall/test43_inline_global.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=1 diff --git a/test/fastcall/test43_inline_global.wat b/test/fastcall/test43_inline_global.wat new file mode 100644 index 000000000..782aeecff --- /dev/null +++ b/test/fastcall/test43_inline_global.wat @@ -0,0 +1,25 @@ +;; Fast handler inlines a callee that reads and writes a global. +;; Tests that global access works inside an inlined function within a fast handler. +(module + (global $g (mut i32) (i32.const 0)) + (func $bump (param $n i32) (result i32) + global.get $g + local.get $n + i32.add + global.set $g + global.get $g) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $bump) + (func (export "main") (result i32) + i32.const 10 + call $f + i32.const 10 + i32.ne + + i32.const 5 + call $f + i32.const 15 + i32.ne + i32.or) +) diff --git a/test/fastcall/test44_inline_depth3.wasm b/test/fastcall/test44_inline_depth3.wasm new file mode 100644 index 0000000000000000000000000000000000000000..23bdbc936f4b6d6231f2c06f83947befdc1f1a0b GIT binary patch literal 93 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mV+D#ZFtQ6Wv85#zmsq7SFtg+)X67-laOtqJ lGbk`PGG=je0BHdrgfJKd7`fR%B23(z431m^%#M8S+yGSA3dsNf literal 0 HcmV?d00001 diff --git a/test/fastcall/test44_inline_depth3.wasm.exit b/test/fastcall/test44_inline_depth3.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test44_inline_depth3.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test44_inline_depth3.wasm.flags b/test/fastcall/test44_inline_depth3.wasm.flags new file mode 100644 index 000000000..a0d56bcb0 --- /dev/null +++ b/test/fastcall/test44_inline_depth3.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=3 diff --git a/test/fastcall/test44_inline_depth3.wat b/test/fastcall/test44_inline_depth3.wat new file mode 100644 index 000000000..204fdf1ca --- /dev/null +++ b/test/fastcall/test44_inline_depth3.wat @@ -0,0 +1,24 @@ +;; Fast handler with inline-max-depth=3: A->B->C->D all inlined. +;; Tests that a chain of three inlined calls works inside a fast-compiled function. +(module + (func $add1 (param i32) (result i32) + local.get 0 + i32.const 1 + i32.add) + (func $add2 (param i32) (result i32) + local.get 0 + call $add1 + call $add1) + (func $add4 (param i32) (result i32) + local.get 0 + call $add2 + call $add2) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $add4) + (func (export "main") (result i32) + i32.const 10 + call $f ;; 10 + 4 = 14 + i32.const 14 + i32.ne) +) diff --git a/test/fastcall/test45_large_handler.wasm b/test/fastcall/test45_large_handler.wasm new file mode 100644 index 0000000000000000000000000000000000000000..97cdc7026a22480b5fc7e76901ee18c64ad59388 GIT binary patch literal 197 zcmWlPu?@m76h!aaPC{&h=xEPtP{kEg%#a9ygh>D?P$F-@j%L#x7bV&W6%`J7z`EF7^)JB)g=~dij`SV z(f@&!K+Sp^wAuaLdTYte!QmON|O}4hjVlhd()NopV=nb acc=50 + ;; loop i=1: acc += 50-47=3 => acc=53 + ;; loop i=2: acc += 50-94=-44 => acc=9 + ;; loop i=3: acc += 50-141=-91 => acc=-82 => clamped to 0 + ;; final: 0 + 50 + 47 = 97 + i32.const 3 i32.const 4 i32.const 5 + call $compute + i32.const 97 + i32.ne) +) diff --git a/test/fastcall/test46_many_callsites.wasm b/test/fastcall/test46_many_callsites.wasm new file mode 100644 index 0000000000000000000000000000000000000000..ca076cf9a1abbaf4755c20e606a4dbc9c00980b5 GIT binary patch literal 674 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mW@2Du7iQu}ODrz2%FIh j&Y-~H$e6|bjD?Z0-jP8O$Q2kRM?-)HA>jCg!JQibpFS;c literal 0 HcmV?d00001 diff --git a/test/fastcall/test46_many_callsites.wasm.exit b/test/fastcall/test46_many_callsites.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test46_many_callsites.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test46_many_callsites.wasm.flags b/test/fastcall/test46_many_callsites.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test46_many_callsites.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test46_many_callsites.wat b/test/fastcall/test46_many_callsites.wat new file mode 100644 index 000000000..ad2562c7d --- /dev/null +++ b/test/fastcall/test46_many_callsites.wat @@ -0,0 +1,112 @@ +;; Stress test: single interpreter caller with many distinct fast-call sites. +;; The same fast function is called from 100 different call sites (not a loop), +;; stressing the interpreter's dispatch and r_ip bookkeeping across many +;; sequential fast calls in one large interpreter function body. +(module + (func $inc (export "fast:inc") (param i32) (result i32) + local.get 0 i32.const 1 i32.add) + (func (export "main") (result i32) + (local $x i32) + i32.const 0 local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x call $inc local.set $x + local.get $x i32.const 100 i32.ne) +) diff --git a/test/fastcall/test47_large_caller_branches.wasm b/test/fastcall/test47_large_caller_branches.wasm new file mode 100644 index 0000000000000000000000000000000000000000..292d70367be3f1a0688094baf39dd825000f06d8 GIT binary patch literal 385 zcmZQbEY4+QU|?Y6VoG4FXRJ?PV610mW@2Du7h&Q|ODrz2N=!*HVqjp&P0Y*#syffa z#Ll3=;K-E4eT0dTsh-J!*#XGq^5bPxU{qibV8~JgQjUySiVQpq+}u!U5&Y6}_@y=Q hOB>;rw!trbi~+y=1p@N72*^LdC9lBfI8Vc!8vuL6F&qE@ literal 0 HcmV?d00001 diff --git a/test/fastcall/test47_large_caller_branches.wasm.exit b/test/fastcall/test47_large_caller_branches.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test47_large_caller_branches.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test47_large_caller_branches.wasm.flags b/test/fastcall/test47_large_caller_branches.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test47_large_caller_branches.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test47_large_caller_branches.wat b/test/fastcall/test47_large_caller_branches.wat new file mode 100644 index 000000000..5022c62cd --- /dev/null +++ b/test/fastcall/test47_large_caller_branches.wat @@ -0,0 +1,76 @@ +;; Stress test: large interpreter caller with many branches interspersed with fast calls. +;; Each iteration: branch to check loop condition, fast call, branch again. +;; This maximally exercises r_stp: every fast call is surrounded by branches that +;; advance the sidetable pointer, so a stale r_stp after any fast call will +;; cause the next branch to use the wrong sidetable entry. +(module + (func $add2 (export "fast:add2") (param i32) (result i32) + local.get 0 i32.const 2 i32.add) + (func (export "main") (result i32) + (local $i i32) + (local $acc i32) + ;; 10 independent block/loop pairs each containing a branch before and after + ;; a fast call, so r_stp must be correct at each of the 20 branch points. + block $b0 loop $l0 + local.get $i i32.const 10 i32.ge_s br_if $b0 + local.get $acc local.get $i call $add2 i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l0 + end end + block $b1 loop $l1 + local.get $i i32.const 20 i32.ge_s br_if $b1 + local.get $acc local.get $i call $add2 i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l1 + end end + block $b2 loop $l2 + local.get $i i32.const 30 i32.ge_s br_if $b2 + local.get $acc local.get $i call $add2 i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l2 + end end + block $b3 loop $l3 + local.get $i i32.const 40 i32.ge_s br_if $b3 + local.get $acc local.get $i call $add2 i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l3 + end end + block $b4 loop $l4 + local.get $i i32.const 50 i32.ge_s br_if $b4 + local.get $acc local.get $i call $add2 i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l4 + end end + block $b5 loop $l5 + local.get $i i32.const 60 i32.ge_s br_if $b5 + local.get $acc local.get $i call $add2 i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l5 + end end + block $b6 loop $l6 + local.get $i i32.const 70 i32.ge_s br_if $b6 + local.get $acc local.get $i call $add2 i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l6 + end end + block $b7 loop $l7 + local.get $i i32.const 80 i32.ge_s br_if $b7 + local.get $acc local.get $i call $add2 i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l7 + end end + block $b8 loop $l8 + local.get $i i32.const 90 i32.ge_s br_if $b8 + local.get $acc local.get $i call $add2 i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l8 + end end + block $b9 loop $l9 + local.get $i i32.const 100 i32.ge_s br_if $b9 + local.get $acc local.get $i call $add2 i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l9 + end end + ;; acc = sum of (i+2) for i in 0..99 = sum(i,0..99) + 200 = 4950 + 200 = 5150 + local.get $acc i32.const 5150 i32.ne) +) diff --git a/test/fastcall/test48_large_inline.wasm b/test/fastcall/test48_large_inline.wasm new file mode 100644 index 0000000000000000000000000000000000000000..b86e323f995f5e2ccde547da45213afc1daa814e GIT binary patch literal 206 zcmYk0I}XA?3`A}3X0soV;0E?JsInCuXGoezn1m+uTXP9c!@)3J3hPOuHzUKetq1^^ zX~c$Y1Z>Vb3;HvKdD>o=8PKoO{Rxym=-!CAF;rAR1F4X~sW^jI@r+E1bnMtK61d}_ z(pQi~gBv(ie>);)?m0bFvIVx34p7S9v5R{z+FDweR3+|I>qjjC7*0^KeR0D2#cTNi DJ6;?b literal 0 HcmV?d00001 diff --git a/test/fastcall/test48_large_inline.wasm.exit b/test/fastcall/test48_large_inline.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test48_large_inline.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test48_large_inline.wasm.flags b/test/fastcall/test48_large_inline.wasm.flags new file mode 100644 index 000000000..15e24ecd1 --- /dev/null +++ b/test/fastcall/test48_large_inline.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true --inline-max-depth=1 diff --git a/test/fastcall/test48_large_inline.wat b/test/fastcall/test48_large_inline.wat new file mode 100644 index 000000000..3f3031d97 --- /dev/null +++ b/test/fastcall/test48_large_inline.wat @@ -0,0 +1,47 @@ +;; Stress test: fast handler inlines a callee with a large body. +;; The inlined function uses many locals, multiple loops, and heavy arithmetic, +;; stressing slot allocation and register pressure inside the inlined context. +(module + (func $heavy (param $n i32) (result i32) + (local $a i32) (local $b i32) (local $c i32) (local $d i32) + (local $e i32) (local $f i32) (local $g i32) (local $h i32) + (local $i i32) (local $acc i32) + ;; initialize locals from n + local.get $n i32.const 1 i32.add local.set $a + local.get $n i32.const 2 i32.add local.set $b + local.get $n i32.const 3 i32.add local.set $c + local.get $n i32.const 4 i32.add local.set $d + local.get $a local.get $b i32.mul local.set $e + local.get $c local.get $d i32.mul local.set $f + local.get $e local.get $f i32.add local.set $g + ;; loop 1: sum g down by subtracting i each iteration + i32.const 0 local.set $i + block $b1 loop $l1 + local.get $i i32.const 4 i32.ge_s br_if $b1 + local.get $acc local.get $g local.get $i i32.sub i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $l1 + end end + ;; loop 2: accumulate h = a*i + b for i in 0..3 + i32.const 0 local.set $i + i32.const 0 local.set $h + block $b2 loop $l2 + local.get $i i32.const 4 i32.ge_s br_if $b2 + local.get $h local.get $a local.get $i i32.mul local.get $b i32.add i32.add local.set $h + local.get $i i32.const 1 i32.add local.set $i + br $l2 + end end + local.get $acc local.get $h i32.add) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 + call $heavy) + (func (export "main") (result i32) + ;; heavy(2): a=3,b=4,c=5,d=6, e=12,f=30, g=42 + ;; loop1: acc += 42+41+40+39 = 162 + ;; loop2: h += (3*0+4)+(3*1+4)+(3*2+4)+(3*3+4) = 4+7+10+13 = 34 + ;; result: 162+34 = 196 + i32.const 2 + call $f + i32.const 196 + i32.ne) +) diff --git a/test/fastcall/test49_leb2_func_index.wasm b/test/fastcall/test49_leb2_func_index.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a854aec6b0bc5f4ce545a68aee98fd2ddfe0f03e GIT binary patch literal 587 zcmZQbEY4+QU|?Y6WlmsVNMNjItWRKItY>avYyt@nC}3n_7iMBhODrz2N@HkXWXVm; o%wuR|= 128). +;; emitFastPrologue computes fast_operand_size from the function index; +;; a 2-byte LEB would be mishandled if the loop is off by one. +(module + (func $dummy0) + (func $dummy1) + (func $dummy2) + (func $dummy3) + (func $dummy4) + (func $dummy5) + (func $dummy6) + (func $dummy7) + (func $dummy8) + (func $dummy9) + (func $dummy10) + (func $dummy11) + (func $dummy12) + (func $dummy13) + (func $dummy14) + (func $dummy15) + (func $dummy16) + (func $dummy17) + (func $dummy18) + (func $dummy19) + (func $dummy20) + (func $dummy21) + (func $dummy22) + (func $dummy23) + (func $dummy24) + (func $dummy25) + (func $dummy26) + (func $dummy27) + (func $dummy28) + (func $dummy29) + (func $dummy30) + (func $dummy31) + (func $dummy32) + (func $dummy33) + (func $dummy34) + (func $dummy35) + (func $dummy36) + (func $dummy37) + (func $dummy38) + (func $dummy39) + (func $dummy40) + (func $dummy41) + (func $dummy42) + (func $dummy43) + (func $dummy44) + (func $dummy45) + (func $dummy46) + (func $dummy47) + (func $dummy48) + (func $dummy49) + (func $dummy50) + (func $dummy51) + (func $dummy52) + (func $dummy53) + (func $dummy54) + (func $dummy55) + (func $dummy56) + (func $dummy57) + (func $dummy58) + (func $dummy59) + (func $dummy60) + (func $dummy61) + (func $dummy62) + (func $dummy63) + (func $dummy64) + (func $dummy65) + (func $dummy66) + (func $dummy67) + (func $dummy68) + (func $dummy69) + (func $dummy70) + (func $dummy71) + (func $dummy72) + (func $dummy73) + (func $dummy74) + (func $dummy75) + (func $dummy76) + (func $dummy77) + (func $dummy78) + (func $dummy79) + (func $dummy80) + (func $dummy81) + (func $dummy82) + (func $dummy83) + (func $dummy84) + (func $dummy85) + (func $dummy86) + (func $dummy87) + (func $dummy88) + (func $dummy89) + (func $dummy90) + (func $dummy91) + (func $dummy92) + (func $dummy93) + (func $dummy94) + (func $dummy95) + (func $dummy96) + (func $dummy97) + (func $dummy98) + (func $dummy99) + (func $dummy100) + (func $dummy101) + (func $dummy102) + (func $dummy103) + (func $dummy104) + (func $dummy105) + (func $dummy106) + (func $dummy107) + (func $dummy108) + (func $dummy109) + (func $dummy110) + (func $dummy111) + (func $dummy112) + (func $dummy113) + (func $dummy114) + (func $dummy115) + (func $dummy116) + (func $dummy117) + (func $dummy118) + (func $dummy119) + (func $dummy120) + (func $dummy121) + (func $dummy122) + (func $dummy123) + (func $dummy124) + (func $dummy125) + (func $dummy126) + (func $dummy127) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 i32.const 1 i32.add) + (func (export "main") (result i32) + i32.const 41 + call $f + i32.const 42 + i32.ne) +) diff --git a/test/fastcall/test50_leb3_func_index.wasm b/test/fastcall/test50_leb3_func_index.wasm new file mode 100644 index 0000000000000000000000000000000000000000..1510de667c9d0fc2c9dfed4ad5fa0bf51106c94e GIT binary patch literal 65618 zcmeI)u?fOp6a?V+5>YS+HuknUf?X=tNSc5`Y_!j>;0&&-PLbw2uDk9V;G(~e84 zTz^Xa`v<6^Q33=A5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk i1PBlyK!5-N0t5&UATYbYD)!OlwP~U~Y)i@Zcy7KTCsCFF literal 0 HcmV?d00001 diff --git a/test/fastcall/test50_leb3_func_index.wasm.exit b/test/fastcall/test50_leb3_func_index.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test50_leb3_func_index.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test50_leb3_func_index.wasm.flags b/test/fastcall/test50_leb3_func_index.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test50_leb3_func_index.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test50_leb3_func_index.wat b/test/fastcall/test50_leb3_func_index.wat new file mode 100644 index 000000000..c5a9c93c6 --- /dev/null +++ b/test/fastcall/test50_leb3_func_index.wat @@ -0,0 +1,16396 @@ +;; Stress test: fast function with a 3-byte LEB-encoded function index (>= 16384). +;; emitFastPrologue computes fast_operand_size from the function index; +;; a 3-byte LEB would be mishandled if the loop is off by one. +(module + (func $dummy0) + (func $dummy1) + (func $dummy2) + (func $dummy3) + (func $dummy4) + (func $dummy5) + (func $dummy6) + (func $dummy7) + (func $dummy8) + (func $dummy9) + (func $dummy10) + (func $dummy11) + (func $dummy12) + (func $dummy13) + (func $dummy14) + (func $dummy15) + (func $dummy16) + (func $dummy17) + (func $dummy18) + (func $dummy19) + (func $dummy20) + (func $dummy21) + (func $dummy22) + (func $dummy23) + (func $dummy24) + (func $dummy25) + (func $dummy26) + (func $dummy27) + (func $dummy28) + (func $dummy29) + (func $dummy30) + (func $dummy31) + (func $dummy32) + (func $dummy33) + (func $dummy34) + (func $dummy35) + (func $dummy36) + (func $dummy37) + (func $dummy38) + (func $dummy39) + (func $dummy40) + (func $dummy41) + (func $dummy42) + (func $dummy43) + (func $dummy44) + (func $dummy45) + (func $dummy46) + (func $dummy47) + (func $dummy48) + (func $dummy49) + (func $dummy50) + (func $dummy51) + (func $dummy52) + (func $dummy53) + (func $dummy54) + (func $dummy55) + (func $dummy56) + (func $dummy57) + (func $dummy58) + (func $dummy59) + (func $dummy60) + (func $dummy61) + (func $dummy62) + (func $dummy63) + (func $dummy64) + (func $dummy65) + (func $dummy66) + (func $dummy67) + (func $dummy68) + (func $dummy69) + (func $dummy70) + (func $dummy71) + (func $dummy72) + (func $dummy73) + (func $dummy74) + (func $dummy75) + (func $dummy76) + (func $dummy77) + (func $dummy78) + (func $dummy79) + (func $dummy80) + (func $dummy81) + (func $dummy82) + (func $dummy83) + (func $dummy84) + (func $dummy85) + (func $dummy86) + (func $dummy87) + (func $dummy88) + (func $dummy89) + (func $dummy90) + (func $dummy91) + (func $dummy92) + (func $dummy93) + (func $dummy94) + (func $dummy95) + (func $dummy96) + (func $dummy97) + (func $dummy98) + (func $dummy99) + (func $dummy100) + (func $dummy101) + (func $dummy102) + (func $dummy103) + (func $dummy104) + (func $dummy105) + (func $dummy106) + (func $dummy107) + (func $dummy108) + (func $dummy109) + (func $dummy110) + (func $dummy111) + (func $dummy112) + (func $dummy113) + (func $dummy114) + (func $dummy115) + (func $dummy116) + (func $dummy117) + (func $dummy118) + (func $dummy119) + (func $dummy120) + (func $dummy121) + (func $dummy122) + (func $dummy123) + (func $dummy124) + (func $dummy125) + (func $dummy126) + (func $dummy127) + (func $dummy128) + (func $dummy129) + (func $dummy130) + (func $dummy131) + (func $dummy132) + (func $dummy133) + (func $dummy134) + (func $dummy135) + (func $dummy136) + (func $dummy137) + (func $dummy138) + (func $dummy139) + (func $dummy140) + (func $dummy141) + (func $dummy142) + (func $dummy143) + (func $dummy144) + (func $dummy145) + (func $dummy146) + (func $dummy147) + (func $dummy148) + (func $dummy149) + (func $dummy150) + (func $dummy151) + (func $dummy152) + (func $dummy153) + (func $dummy154) + (func $dummy155) + (func $dummy156) + (func $dummy157) + (func $dummy158) + (func $dummy159) + (func $dummy160) + (func $dummy161) + (func $dummy162) + (func $dummy163) + (func $dummy164) + (func $dummy165) + (func $dummy166) + (func $dummy167) + (func $dummy168) + (func $dummy169) + (func $dummy170) + (func $dummy171) + (func $dummy172) + (func $dummy173) + (func $dummy174) + (func $dummy175) + (func $dummy176) + (func $dummy177) + (func $dummy178) + (func $dummy179) + (func $dummy180) + (func $dummy181) + (func $dummy182) + (func $dummy183) + (func $dummy184) + (func $dummy185) + (func $dummy186) + (func $dummy187) + (func $dummy188) + (func $dummy189) + (func $dummy190) + (func $dummy191) + (func $dummy192) + (func $dummy193) + (func $dummy194) + (func $dummy195) + (func $dummy196) + (func $dummy197) + (func $dummy198) + (func $dummy199) + (func $dummy200) + (func $dummy201) + (func $dummy202) + (func $dummy203) + (func $dummy204) + (func $dummy205) + (func $dummy206) + (func $dummy207) + (func $dummy208) + (func $dummy209) + (func $dummy210) + (func $dummy211) + (func $dummy212) + (func $dummy213) + (func $dummy214) + (func $dummy215) + (func $dummy216) + (func $dummy217) + (func $dummy218) + (func $dummy219) + (func $dummy220) + (func $dummy221) + (func $dummy222) + (func $dummy223) + (func $dummy224) + (func $dummy225) + (func $dummy226) + (func $dummy227) + (func $dummy228) + (func $dummy229) + (func $dummy230) + (func $dummy231) + (func $dummy232) + (func $dummy233) + (func $dummy234) + (func $dummy235) + (func $dummy236) + (func $dummy237) + (func $dummy238) + (func $dummy239) + (func $dummy240) + (func $dummy241) + (func $dummy242) + (func $dummy243) + (func $dummy244) + (func $dummy245) + (func $dummy246) + (func $dummy247) + (func $dummy248) + (func $dummy249) + (func $dummy250) + (func $dummy251) + (func $dummy252) + (func $dummy253) + (func $dummy254) + (func $dummy255) + (func $dummy256) + (func $dummy257) + (func $dummy258) + (func $dummy259) + (func $dummy260) + (func $dummy261) + (func $dummy262) + (func $dummy263) + (func $dummy264) + (func $dummy265) + (func $dummy266) + (func $dummy267) + (func $dummy268) + (func $dummy269) + (func $dummy270) + (func $dummy271) + (func $dummy272) + (func $dummy273) + (func $dummy274) + (func $dummy275) + (func $dummy276) + (func $dummy277) + (func $dummy278) + (func $dummy279) + (func $dummy280) + (func $dummy281) + (func $dummy282) + (func $dummy283) + (func $dummy284) + (func $dummy285) + (func $dummy286) + (func $dummy287) + (func $dummy288) + (func $dummy289) + (func $dummy290) + (func $dummy291) + (func $dummy292) + (func $dummy293) + (func $dummy294) + (func $dummy295) + (func $dummy296) + (func $dummy297) + (func $dummy298) + (func $dummy299) + (func $dummy300) + (func $dummy301) + (func $dummy302) + (func $dummy303) + (func $dummy304) + (func $dummy305) + (func $dummy306) + (func $dummy307) + (func $dummy308) + (func $dummy309) + (func $dummy310) + (func $dummy311) + (func $dummy312) + (func $dummy313) + (func $dummy314) + (func $dummy315) + (func $dummy316) + (func $dummy317) + (func $dummy318) + (func $dummy319) + (func $dummy320) + (func $dummy321) + (func $dummy322) + (func $dummy323) + (func $dummy324) + (func $dummy325) + (func $dummy326) + (func $dummy327) + (func $dummy328) + (func $dummy329) + (func $dummy330) + (func $dummy331) + (func $dummy332) + (func $dummy333) + (func $dummy334) + (func $dummy335) + (func $dummy336) + (func $dummy337) + (func $dummy338) + (func $dummy339) + (func $dummy340) + (func $dummy341) + (func $dummy342) + (func $dummy343) + (func $dummy344) + (func $dummy345) + (func $dummy346) + (func $dummy347) + (func $dummy348) + (func $dummy349) + (func $dummy350) + (func $dummy351) + (func $dummy352) + (func $dummy353) + (func $dummy354) + (func $dummy355) + (func $dummy356) + (func $dummy357) + (func $dummy358) + (func $dummy359) + (func $dummy360) + (func $dummy361) + (func $dummy362) + (func $dummy363) + (func $dummy364) + (func $dummy365) + (func $dummy366) + (func $dummy367) + (func $dummy368) + (func $dummy369) + (func $dummy370) + (func $dummy371) + (func $dummy372) + (func $dummy373) + (func $dummy374) + (func $dummy375) + (func $dummy376) + (func $dummy377) + (func $dummy378) + (func $dummy379) + (func $dummy380) + (func $dummy381) + (func $dummy382) + (func $dummy383) + (func $dummy384) + (func $dummy385) + (func $dummy386) + (func $dummy387) + (func $dummy388) + (func $dummy389) + (func $dummy390) + (func $dummy391) + (func $dummy392) + (func $dummy393) + (func $dummy394) + (func $dummy395) + (func $dummy396) + (func $dummy397) + (func $dummy398) + (func $dummy399) + (func $dummy400) + (func $dummy401) + (func $dummy402) + (func $dummy403) + (func $dummy404) + (func $dummy405) + (func $dummy406) + (func $dummy407) + (func $dummy408) + (func $dummy409) + (func $dummy410) + (func $dummy411) + (func $dummy412) + (func $dummy413) + (func $dummy414) + (func $dummy415) + (func $dummy416) + (func $dummy417) + (func $dummy418) + (func $dummy419) + (func $dummy420) + (func $dummy421) + (func $dummy422) + (func $dummy423) + (func $dummy424) + (func $dummy425) + (func $dummy426) + (func $dummy427) + (func $dummy428) + (func $dummy429) + (func $dummy430) + (func $dummy431) + (func $dummy432) + (func $dummy433) + (func $dummy434) + (func $dummy435) + (func $dummy436) + (func $dummy437) + (func $dummy438) + (func $dummy439) + (func $dummy440) + (func $dummy441) + (func $dummy442) + (func $dummy443) + (func $dummy444) + (func $dummy445) + (func $dummy446) + (func $dummy447) + (func $dummy448) + (func $dummy449) + (func $dummy450) + (func $dummy451) + (func $dummy452) + (func $dummy453) + (func $dummy454) + (func $dummy455) + (func $dummy456) + (func $dummy457) + (func $dummy458) + (func $dummy459) + (func $dummy460) + (func $dummy461) + (func $dummy462) + (func $dummy463) + (func $dummy464) + (func $dummy465) + (func $dummy466) + (func $dummy467) + (func $dummy468) + (func $dummy469) + (func $dummy470) + (func $dummy471) + (func $dummy472) + (func $dummy473) + (func $dummy474) + (func $dummy475) + (func $dummy476) + (func $dummy477) + (func $dummy478) + (func $dummy479) + (func $dummy480) + (func $dummy481) + (func $dummy482) + (func $dummy483) + (func $dummy484) + (func $dummy485) + (func $dummy486) + (func $dummy487) + (func $dummy488) + (func $dummy489) + (func $dummy490) + (func $dummy491) + (func $dummy492) + (func $dummy493) + (func $dummy494) + (func $dummy495) + (func $dummy496) + (func $dummy497) + (func $dummy498) + (func $dummy499) + (func $dummy500) + (func $dummy501) + (func $dummy502) + (func $dummy503) + (func $dummy504) + (func $dummy505) + (func $dummy506) + (func $dummy507) + (func $dummy508) + (func $dummy509) + (func $dummy510) + (func $dummy511) + (func $dummy512) + (func $dummy513) + (func $dummy514) + (func $dummy515) + (func $dummy516) + (func $dummy517) + (func $dummy518) + (func $dummy519) + (func $dummy520) + (func $dummy521) + (func $dummy522) + (func $dummy523) + (func $dummy524) + (func $dummy525) + (func $dummy526) + (func $dummy527) + (func $dummy528) + (func $dummy529) + (func $dummy530) + (func $dummy531) + (func $dummy532) + (func $dummy533) + (func $dummy534) + (func $dummy535) + (func $dummy536) + (func $dummy537) + (func $dummy538) + (func $dummy539) + (func $dummy540) + (func $dummy541) + (func $dummy542) + (func $dummy543) + (func $dummy544) + (func $dummy545) + (func $dummy546) + (func $dummy547) + (func $dummy548) + (func $dummy549) + (func $dummy550) + (func $dummy551) + (func $dummy552) + (func $dummy553) + (func $dummy554) + (func $dummy555) + (func $dummy556) + (func $dummy557) + (func $dummy558) + (func $dummy559) + (func $dummy560) + (func $dummy561) + (func $dummy562) + (func $dummy563) + (func $dummy564) + (func $dummy565) + (func $dummy566) + (func $dummy567) + (func $dummy568) + (func $dummy569) + (func $dummy570) + (func $dummy571) + (func $dummy572) + (func $dummy573) + (func $dummy574) + (func $dummy575) + (func $dummy576) + (func $dummy577) + (func $dummy578) + (func $dummy579) + (func $dummy580) + (func $dummy581) + (func $dummy582) + (func $dummy583) + (func $dummy584) + (func $dummy585) + (func $dummy586) + (func $dummy587) + (func $dummy588) + (func $dummy589) + (func $dummy590) + (func $dummy591) + (func $dummy592) + (func $dummy593) + (func $dummy594) + (func $dummy595) + (func $dummy596) + (func $dummy597) + (func $dummy598) + (func $dummy599) + (func $dummy600) + (func $dummy601) + (func $dummy602) + (func $dummy603) + (func $dummy604) + (func $dummy605) + (func $dummy606) + (func $dummy607) + (func $dummy608) + (func $dummy609) + (func $dummy610) + (func $dummy611) + (func $dummy612) + (func $dummy613) + (func $dummy614) + (func $dummy615) + (func $dummy616) + (func $dummy617) + (func $dummy618) + (func $dummy619) + (func $dummy620) + (func $dummy621) + (func $dummy622) + (func $dummy623) + (func $dummy624) + (func $dummy625) + (func $dummy626) + (func $dummy627) + (func $dummy628) + (func $dummy629) + (func $dummy630) + (func $dummy631) + (func $dummy632) + (func $dummy633) + (func $dummy634) + (func $dummy635) + (func $dummy636) + (func $dummy637) + (func $dummy638) + (func $dummy639) + (func $dummy640) + (func $dummy641) + (func $dummy642) + (func $dummy643) + (func $dummy644) + (func $dummy645) + (func $dummy646) + (func $dummy647) + (func $dummy648) + (func $dummy649) + (func $dummy650) + (func $dummy651) + (func $dummy652) + (func $dummy653) + (func $dummy654) + (func $dummy655) + (func $dummy656) + (func $dummy657) + (func $dummy658) + (func $dummy659) + (func $dummy660) + (func $dummy661) + (func $dummy662) + (func $dummy663) + (func $dummy664) + (func $dummy665) + (func $dummy666) + (func $dummy667) + (func $dummy668) + (func $dummy669) + (func $dummy670) + (func $dummy671) + (func $dummy672) + (func $dummy673) + (func $dummy674) + (func $dummy675) + (func $dummy676) + (func $dummy677) + (func $dummy678) + (func $dummy679) + (func $dummy680) + (func $dummy681) + (func $dummy682) + (func $dummy683) + (func $dummy684) + (func $dummy685) + (func $dummy686) + (func $dummy687) + (func $dummy688) + (func $dummy689) + (func $dummy690) + (func $dummy691) + (func $dummy692) + (func $dummy693) + (func $dummy694) + (func $dummy695) + (func $dummy696) + (func $dummy697) + (func $dummy698) + (func $dummy699) + (func $dummy700) + (func $dummy701) + (func $dummy702) + (func $dummy703) + (func $dummy704) + (func $dummy705) + (func $dummy706) + (func $dummy707) + (func $dummy708) + (func $dummy709) + (func $dummy710) + (func $dummy711) + (func $dummy712) + (func $dummy713) + (func $dummy714) + (func $dummy715) + (func $dummy716) + (func $dummy717) + (func $dummy718) + (func $dummy719) + (func $dummy720) + (func $dummy721) + (func $dummy722) + (func $dummy723) + (func $dummy724) + (func $dummy725) + (func $dummy726) + (func $dummy727) + (func $dummy728) + (func $dummy729) + (func $dummy730) + (func $dummy731) + (func $dummy732) + (func $dummy733) + (func $dummy734) + (func $dummy735) + (func $dummy736) + (func $dummy737) + (func $dummy738) + (func $dummy739) + (func $dummy740) + (func $dummy741) + (func $dummy742) + (func $dummy743) + (func $dummy744) + (func $dummy745) + (func $dummy746) + (func $dummy747) + (func $dummy748) + (func $dummy749) + (func $dummy750) + (func $dummy751) + (func $dummy752) + (func $dummy753) + (func $dummy754) + (func $dummy755) + (func $dummy756) + (func $dummy757) + (func $dummy758) + (func $dummy759) + (func $dummy760) + (func $dummy761) + (func $dummy762) + (func $dummy763) + (func $dummy764) + (func $dummy765) + (func $dummy766) + (func $dummy767) + (func $dummy768) + (func $dummy769) + (func $dummy770) + (func $dummy771) + (func $dummy772) + (func $dummy773) + (func $dummy774) + (func $dummy775) + (func $dummy776) + (func $dummy777) + (func $dummy778) + (func $dummy779) + (func $dummy780) + (func $dummy781) + (func $dummy782) + (func $dummy783) + (func $dummy784) + (func $dummy785) + (func $dummy786) + (func $dummy787) + (func $dummy788) + (func $dummy789) + (func $dummy790) + (func $dummy791) + (func $dummy792) + (func $dummy793) + (func $dummy794) + (func $dummy795) + (func $dummy796) + (func $dummy797) + (func $dummy798) + (func $dummy799) + (func $dummy800) + (func $dummy801) + (func $dummy802) + (func $dummy803) + (func $dummy804) + (func $dummy805) + (func $dummy806) + (func $dummy807) + (func $dummy808) + (func $dummy809) + (func $dummy810) + (func $dummy811) + (func $dummy812) + (func $dummy813) + (func $dummy814) + (func $dummy815) + (func $dummy816) + (func $dummy817) + (func $dummy818) + (func $dummy819) + (func $dummy820) + (func $dummy821) + (func $dummy822) + (func $dummy823) + (func $dummy824) + (func $dummy825) + (func $dummy826) + (func $dummy827) + (func $dummy828) + (func $dummy829) + (func $dummy830) + (func $dummy831) + (func $dummy832) + (func $dummy833) + (func $dummy834) + (func $dummy835) + (func $dummy836) + (func $dummy837) + (func $dummy838) + (func $dummy839) + (func $dummy840) + (func $dummy841) + (func $dummy842) + (func $dummy843) + (func $dummy844) + (func $dummy845) + (func $dummy846) + (func $dummy847) + (func $dummy848) + (func $dummy849) + (func $dummy850) + (func $dummy851) + (func $dummy852) + (func $dummy853) + (func $dummy854) + (func $dummy855) + (func $dummy856) + (func $dummy857) + (func $dummy858) + (func $dummy859) + (func $dummy860) + (func $dummy861) + (func $dummy862) + (func $dummy863) + (func $dummy864) + (func $dummy865) + (func $dummy866) + (func $dummy867) + (func $dummy868) + (func $dummy869) + (func $dummy870) + (func $dummy871) + (func $dummy872) + (func $dummy873) + (func $dummy874) + (func $dummy875) + (func $dummy876) + (func $dummy877) + (func $dummy878) + (func $dummy879) + (func $dummy880) + (func $dummy881) + (func $dummy882) + (func $dummy883) + (func $dummy884) + (func $dummy885) + (func $dummy886) + (func $dummy887) + (func $dummy888) + (func $dummy889) + (func $dummy890) + (func $dummy891) + (func $dummy892) + (func $dummy893) + (func $dummy894) + (func $dummy895) + (func $dummy896) + (func $dummy897) + (func $dummy898) + (func $dummy899) + (func $dummy900) + (func $dummy901) + (func $dummy902) + (func $dummy903) + (func $dummy904) + (func $dummy905) + (func $dummy906) + (func $dummy907) + (func $dummy908) + (func $dummy909) + (func $dummy910) + (func $dummy911) + (func $dummy912) + (func $dummy913) + (func $dummy914) + (func $dummy915) + (func $dummy916) + (func $dummy917) + (func $dummy918) + (func $dummy919) + (func $dummy920) + (func $dummy921) + (func $dummy922) + (func $dummy923) + (func $dummy924) + (func $dummy925) + (func $dummy926) + (func $dummy927) + (func $dummy928) + (func $dummy929) + (func $dummy930) + (func $dummy931) + (func $dummy932) + (func $dummy933) + (func $dummy934) + (func $dummy935) + (func $dummy936) + (func $dummy937) + (func $dummy938) + (func $dummy939) + (func $dummy940) + (func $dummy941) + (func $dummy942) + (func $dummy943) + (func $dummy944) + (func $dummy945) + (func $dummy946) + (func $dummy947) + (func $dummy948) + (func $dummy949) + (func $dummy950) + (func $dummy951) + (func $dummy952) + (func $dummy953) + (func $dummy954) + (func $dummy955) + (func $dummy956) + (func $dummy957) + (func $dummy958) + (func $dummy959) + (func $dummy960) + (func $dummy961) + (func $dummy962) + (func $dummy963) + (func $dummy964) + (func $dummy965) + (func $dummy966) + (func $dummy967) + (func $dummy968) + (func $dummy969) + (func $dummy970) + (func $dummy971) + (func $dummy972) + (func $dummy973) + (func $dummy974) + (func $dummy975) + (func $dummy976) + (func $dummy977) + (func $dummy978) + (func $dummy979) + (func $dummy980) + (func $dummy981) + (func $dummy982) + (func $dummy983) + (func $dummy984) + (func $dummy985) + (func $dummy986) + (func $dummy987) + (func $dummy988) + (func $dummy989) + (func $dummy990) + (func $dummy991) + (func $dummy992) + (func $dummy993) + (func $dummy994) + (func $dummy995) + (func $dummy996) + (func $dummy997) + (func $dummy998) + (func $dummy999) + (func $dummy1000) + (func $dummy1001) + (func $dummy1002) + (func $dummy1003) + (func $dummy1004) + (func $dummy1005) + (func $dummy1006) + (func $dummy1007) + (func $dummy1008) + (func $dummy1009) + (func $dummy1010) + (func $dummy1011) + (func $dummy1012) + (func $dummy1013) + (func $dummy1014) + (func $dummy1015) + (func $dummy1016) + (func $dummy1017) + (func $dummy1018) + (func $dummy1019) + (func $dummy1020) + (func $dummy1021) + (func $dummy1022) + (func $dummy1023) + (func $dummy1024) + (func $dummy1025) + (func $dummy1026) + (func $dummy1027) + (func $dummy1028) + (func $dummy1029) + (func $dummy1030) + (func $dummy1031) + (func $dummy1032) + (func $dummy1033) + (func $dummy1034) + (func $dummy1035) + (func $dummy1036) + (func $dummy1037) + (func $dummy1038) + (func $dummy1039) + (func $dummy1040) + (func $dummy1041) + (func $dummy1042) + (func $dummy1043) + (func $dummy1044) + (func $dummy1045) + (func $dummy1046) + (func $dummy1047) + (func $dummy1048) + (func $dummy1049) + (func $dummy1050) + (func $dummy1051) + (func $dummy1052) + (func $dummy1053) + (func $dummy1054) + (func $dummy1055) + (func $dummy1056) + (func $dummy1057) + (func $dummy1058) + (func $dummy1059) + (func $dummy1060) + (func $dummy1061) + (func $dummy1062) + (func $dummy1063) + (func $dummy1064) + (func $dummy1065) + (func $dummy1066) + (func $dummy1067) + (func $dummy1068) + (func $dummy1069) + (func $dummy1070) + (func $dummy1071) + (func $dummy1072) + (func $dummy1073) + (func $dummy1074) + (func $dummy1075) + (func $dummy1076) + (func $dummy1077) + (func $dummy1078) + (func $dummy1079) + (func $dummy1080) + (func $dummy1081) + (func $dummy1082) + (func $dummy1083) + (func $dummy1084) + (func $dummy1085) + (func $dummy1086) + (func $dummy1087) + (func $dummy1088) + (func $dummy1089) + (func $dummy1090) + (func $dummy1091) + (func $dummy1092) + (func $dummy1093) + (func $dummy1094) + (func $dummy1095) + (func $dummy1096) + (func $dummy1097) + (func $dummy1098) + (func $dummy1099) + (func $dummy1100) + (func $dummy1101) + (func $dummy1102) + (func $dummy1103) + (func $dummy1104) + (func $dummy1105) + (func $dummy1106) + (func $dummy1107) + (func $dummy1108) + (func $dummy1109) + (func $dummy1110) + (func $dummy1111) + (func $dummy1112) + (func $dummy1113) + (func $dummy1114) + (func $dummy1115) + (func $dummy1116) + (func $dummy1117) + (func $dummy1118) + (func $dummy1119) + (func $dummy1120) + (func $dummy1121) + (func $dummy1122) + (func $dummy1123) + (func $dummy1124) + (func $dummy1125) + (func $dummy1126) + (func $dummy1127) + (func $dummy1128) + (func $dummy1129) + (func $dummy1130) + (func $dummy1131) + (func $dummy1132) + (func $dummy1133) + (func $dummy1134) + (func $dummy1135) + (func $dummy1136) + (func $dummy1137) + (func $dummy1138) + (func $dummy1139) + (func $dummy1140) + (func $dummy1141) + (func $dummy1142) + (func $dummy1143) + (func $dummy1144) + (func $dummy1145) + (func $dummy1146) + (func $dummy1147) + (func $dummy1148) + (func $dummy1149) + (func $dummy1150) + (func $dummy1151) + (func $dummy1152) + (func $dummy1153) + (func $dummy1154) + (func $dummy1155) + (func $dummy1156) + (func $dummy1157) + (func $dummy1158) + (func $dummy1159) + (func $dummy1160) + (func $dummy1161) + (func $dummy1162) + (func $dummy1163) + (func $dummy1164) + (func $dummy1165) + (func $dummy1166) + (func $dummy1167) + (func $dummy1168) + (func $dummy1169) + (func $dummy1170) + (func $dummy1171) + (func $dummy1172) + (func $dummy1173) + (func $dummy1174) + (func $dummy1175) + (func $dummy1176) + (func $dummy1177) + (func $dummy1178) + (func $dummy1179) + (func $dummy1180) + (func $dummy1181) + (func $dummy1182) + (func $dummy1183) + (func $dummy1184) + (func $dummy1185) + (func $dummy1186) + (func $dummy1187) + (func $dummy1188) + (func $dummy1189) + (func $dummy1190) + (func $dummy1191) + (func $dummy1192) + (func $dummy1193) + (func $dummy1194) + (func $dummy1195) + (func $dummy1196) + (func $dummy1197) + (func $dummy1198) + (func $dummy1199) + (func $dummy1200) + (func $dummy1201) + (func $dummy1202) + (func $dummy1203) + (func $dummy1204) + (func $dummy1205) + (func $dummy1206) + (func $dummy1207) + (func $dummy1208) + (func $dummy1209) + (func $dummy1210) + (func $dummy1211) + (func $dummy1212) + (func $dummy1213) + (func $dummy1214) + (func $dummy1215) + (func $dummy1216) + (func $dummy1217) + (func $dummy1218) + (func $dummy1219) + (func $dummy1220) + (func $dummy1221) + (func $dummy1222) + (func $dummy1223) + (func $dummy1224) + (func $dummy1225) + (func $dummy1226) + (func $dummy1227) + (func $dummy1228) + (func $dummy1229) + (func $dummy1230) + (func $dummy1231) + (func $dummy1232) + (func $dummy1233) + (func $dummy1234) + (func $dummy1235) + (func $dummy1236) + (func $dummy1237) + (func $dummy1238) + (func $dummy1239) + (func $dummy1240) + (func $dummy1241) + (func $dummy1242) + (func $dummy1243) + (func $dummy1244) + (func $dummy1245) + (func $dummy1246) + (func $dummy1247) + (func $dummy1248) + (func $dummy1249) + (func $dummy1250) + (func $dummy1251) + (func $dummy1252) + (func $dummy1253) + (func $dummy1254) + (func $dummy1255) + (func $dummy1256) + (func $dummy1257) + (func $dummy1258) + (func $dummy1259) + (func $dummy1260) + (func $dummy1261) + (func $dummy1262) + (func $dummy1263) + (func $dummy1264) + (func $dummy1265) + (func $dummy1266) + (func $dummy1267) + (func $dummy1268) + (func $dummy1269) + (func $dummy1270) + (func $dummy1271) + (func $dummy1272) + (func $dummy1273) + (func $dummy1274) + (func $dummy1275) + (func $dummy1276) + (func $dummy1277) + (func $dummy1278) + (func $dummy1279) + (func $dummy1280) + (func $dummy1281) + (func $dummy1282) + (func $dummy1283) + (func $dummy1284) + (func $dummy1285) + (func $dummy1286) + (func $dummy1287) + (func $dummy1288) + (func $dummy1289) + (func $dummy1290) + (func $dummy1291) + (func $dummy1292) + (func $dummy1293) + (func $dummy1294) + (func $dummy1295) + (func $dummy1296) + (func $dummy1297) + (func $dummy1298) + (func $dummy1299) + (func $dummy1300) + (func $dummy1301) + (func $dummy1302) + (func $dummy1303) + (func $dummy1304) + (func $dummy1305) + (func $dummy1306) + (func $dummy1307) + (func $dummy1308) + (func $dummy1309) + (func $dummy1310) + (func $dummy1311) + (func $dummy1312) + (func $dummy1313) + (func $dummy1314) + (func $dummy1315) + (func $dummy1316) + (func $dummy1317) + (func $dummy1318) + (func $dummy1319) + (func $dummy1320) + (func $dummy1321) + (func $dummy1322) + (func $dummy1323) + (func $dummy1324) + (func $dummy1325) + (func $dummy1326) + (func $dummy1327) + (func $dummy1328) + (func $dummy1329) + (func $dummy1330) + (func $dummy1331) + (func $dummy1332) + (func $dummy1333) + (func $dummy1334) + (func $dummy1335) + (func $dummy1336) + (func $dummy1337) + (func $dummy1338) + (func $dummy1339) + (func $dummy1340) + (func $dummy1341) + (func $dummy1342) + (func $dummy1343) + (func $dummy1344) + (func $dummy1345) + (func $dummy1346) + (func $dummy1347) + (func $dummy1348) + (func $dummy1349) + (func $dummy1350) + (func $dummy1351) + (func $dummy1352) + (func $dummy1353) + (func $dummy1354) + (func $dummy1355) + (func $dummy1356) + (func $dummy1357) + (func $dummy1358) + (func $dummy1359) + (func $dummy1360) + (func $dummy1361) + (func $dummy1362) + (func $dummy1363) + (func $dummy1364) + (func $dummy1365) + (func $dummy1366) + (func $dummy1367) + (func $dummy1368) + (func $dummy1369) + (func $dummy1370) + (func $dummy1371) + (func $dummy1372) + (func $dummy1373) + (func $dummy1374) + (func $dummy1375) + (func $dummy1376) + (func $dummy1377) + (func $dummy1378) + (func $dummy1379) + (func $dummy1380) + (func $dummy1381) + (func $dummy1382) + (func $dummy1383) + (func $dummy1384) + (func $dummy1385) + (func $dummy1386) + (func $dummy1387) + (func $dummy1388) + (func $dummy1389) + (func $dummy1390) + (func $dummy1391) + (func $dummy1392) + (func $dummy1393) + (func $dummy1394) + (func $dummy1395) + (func $dummy1396) + (func $dummy1397) + (func $dummy1398) + (func $dummy1399) + (func $dummy1400) + (func $dummy1401) + (func $dummy1402) + (func $dummy1403) + (func $dummy1404) + (func $dummy1405) + (func $dummy1406) + (func $dummy1407) + (func $dummy1408) + (func $dummy1409) + (func $dummy1410) + (func $dummy1411) + (func $dummy1412) + (func $dummy1413) + (func $dummy1414) + (func $dummy1415) + (func $dummy1416) + (func $dummy1417) + (func $dummy1418) + (func $dummy1419) + (func $dummy1420) + (func $dummy1421) + (func $dummy1422) + (func $dummy1423) + (func $dummy1424) + (func $dummy1425) + (func $dummy1426) + (func $dummy1427) + (func $dummy1428) + (func $dummy1429) + (func $dummy1430) + (func $dummy1431) + (func $dummy1432) + (func $dummy1433) + (func $dummy1434) + (func $dummy1435) + (func $dummy1436) + (func $dummy1437) + (func $dummy1438) + (func $dummy1439) + (func $dummy1440) + (func $dummy1441) + (func $dummy1442) + (func $dummy1443) + (func $dummy1444) + (func $dummy1445) + (func $dummy1446) + (func $dummy1447) + (func $dummy1448) + (func $dummy1449) + (func $dummy1450) + (func $dummy1451) + (func $dummy1452) + (func $dummy1453) + (func $dummy1454) + (func $dummy1455) + (func $dummy1456) + (func $dummy1457) + (func $dummy1458) + (func $dummy1459) + (func $dummy1460) + (func $dummy1461) + (func $dummy1462) + (func $dummy1463) + (func $dummy1464) + (func $dummy1465) + (func $dummy1466) + (func $dummy1467) + (func $dummy1468) + (func $dummy1469) + (func $dummy1470) + (func $dummy1471) + (func $dummy1472) + (func $dummy1473) + (func $dummy1474) + (func $dummy1475) + (func $dummy1476) + (func $dummy1477) + (func $dummy1478) + (func $dummy1479) + (func $dummy1480) + (func $dummy1481) + (func $dummy1482) + (func $dummy1483) + (func $dummy1484) + (func $dummy1485) + (func $dummy1486) + (func $dummy1487) + (func $dummy1488) + (func $dummy1489) + (func $dummy1490) + (func $dummy1491) + (func $dummy1492) + (func $dummy1493) + (func $dummy1494) + (func $dummy1495) + (func $dummy1496) + (func $dummy1497) + (func $dummy1498) + (func $dummy1499) + (func $dummy1500) + (func $dummy1501) + (func $dummy1502) + (func $dummy1503) + (func $dummy1504) + (func $dummy1505) + (func $dummy1506) + (func $dummy1507) + (func $dummy1508) + (func $dummy1509) + (func $dummy1510) + (func $dummy1511) + (func $dummy1512) + (func $dummy1513) + (func $dummy1514) + (func $dummy1515) + (func $dummy1516) + (func $dummy1517) + (func $dummy1518) + (func $dummy1519) + (func $dummy1520) + (func $dummy1521) + (func $dummy1522) + (func $dummy1523) + (func $dummy1524) + (func $dummy1525) + (func $dummy1526) + (func $dummy1527) + (func $dummy1528) + (func $dummy1529) + (func $dummy1530) + (func $dummy1531) + (func $dummy1532) + (func $dummy1533) + (func $dummy1534) + (func $dummy1535) + (func $dummy1536) + (func $dummy1537) + (func $dummy1538) + (func $dummy1539) + (func $dummy1540) + (func $dummy1541) + (func $dummy1542) + (func $dummy1543) + (func $dummy1544) + (func $dummy1545) + (func $dummy1546) + (func $dummy1547) + (func $dummy1548) + (func $dummy1549) + (func $dummy1550) + (func $dummy1551) + (func $dummy1552) + (func $dummy1553) + (func $dummy1554) + (func $dummy1555) + (func $dummy1556) + (func $dummy1557) + (func $dummy1558) + (func $dummy1559) + (func $dummy1560) + (func $dummy1561) + (func $dummy1562) + (func $dummy1563) + (func $dummy1564) + (func $dummy1565) + (func $dummy1566) + (func $dummy1567) + (func $dummy1568) + (func $dummy1569) + (func $dummy1570) + (func $dummy1571) + (func $dummy1572) + (func $dummy1573) + (func $dummy1574) + (func $dummy1575) + (func $dummy1576) + (func $dummy1577) + (func $dummy1578) + (func $dummy1579) + (func $dummy1580) + (func $dummy1581) + (func $dummy1582) + (func $dummy1583) + (func $dummy1584) + (func $dummy1585) + (func $dummy1586) + (func $dummy1587) + (func $dummy1588) + (func $dummy1589) + (func $dummy1590) + (func $dummy1591) + (func $dummy1592) + (func $dummy1593) + (func $dummy1594) + (func $dummy1595) + (func $dummy1596) + (func $dummy1597) + (func $dummy1598) + (func $dummy1599) + (func $dummy1600) + (func $dummy1601) + (func $dummy1602) + (func $dummy1603) + (func $dummy1604) + (func $dummy1605) + (func $dummy1606) + (func $dummy1607) + (func $dummy1608) + (func $dummy1609) + (func $dummy1610) + (func $dummy1611) + (func $dummy1612) + (func $dummy1613) + (func $dummy1614) + (func $dummy1615) + (func $dummy1616) + (func $dummy1617) + (func $dummy1618) + (func $dummy1619) + (func $dummy1620) + (func $dummy1621) + (func $dummy1622) + (func $dummy1623) + (func $dummy1624) + (func $dummy1625) + (func $dummy1626) + (func $dummy1627) + (func $dummy1628) + (func $dummy1629) + (func $dummy1630) + (func $dummy1631) + (func $dummy1632) + (func $dummy1633) + (func $dummy1634) + (func $dummy1635) + (func $dummy1636) + (func $dummy1637) + (func $dummy1638) + (func $dummy1639) + (func $dummy1640) + (func $dummy1641) + (func $dummy1642) + (func $dummy1643) + (func $dummy1644) + (func $dummy1645) + (func $dummy1646) + (func $dummy1647) + (func $dummy1648) + (func $dummy1649) + (func $dummy1650) + (func $dummy1651) + (func $dummy1652) + (func $dummy1653) + (func $dummy1654) + (func $dummy1655) + (func $dummy1656) + (func $dummy1657) + (func $dummy1658) + (func $dummy1659) + (func $dummy1660) + (func $dummy1661) + (func $dummy1662) + (func $dummy1663) + (func $dummy1664) + (func $dummy1665) + (func $dummy1666) + (func $dummy1667) + (func $dummy1668) + (func $dummy1669) + (func $dummy1670) + (func $dummy1671) + (func $dummy1672) + (func $dummy1673) + (func $dummy1674) + (func $dummy1675) + (func $dummy1676) + (func $dummy1677) + (func $dummy1678) + (func $dummy1679) + (func $dummy1680) + (func $dummy1681) + (func $dummy1682) + (func $dummy1683) + (func $dummy1684) + (func $dummy1685) + (func $dummy1686) + (func $dummy1687) + (func $dummy1688) + (func $dummy1689) + (func $dummy1690) + (func $dummy1691) + (func $dummy1692) + (func $dummy1693) + (func $dummy1694) + (func $dummy1695) + (func $dummy1696) + (func $dummy1697) + (func $dummy1698) + (func $dummy1699) + (func $dummy1700) + (func $dummy1701) + (func $dummy1702) + (func $dummy1703) + (func $dummy1704) + (func $dummy1705) + (func $dummy1706) + (func $dummy1707) + (func $dummy1708) + (func $dummy1709) + (func $dummy1710) + (func $dummy1711) + (func $dummy1712) + (func $dummy1713) + (func $dummy1714) + (func $dummy1715) + (func $dummy1716) + (func $dummy1717) + (func $dummy1718) + (func $dummy1719) + (func $dummy1720) + (func $dummy1721) + (func $dummy1722) + (func $dummy1723) + (func $dummy1724) + (func $dummy1725) + (func $dummy1726) + (func $dummy1727) + (func $dummy1728) + (func $dummy1729) + (func $dummy1730) + (func $dummy1731) + (func $dummy1732) + (func $dummy1733) + (func $dummy1734) + (func $dummy1735) + (func $dummy1736) + (func $dummy1737) + (func $dummy1738) + (func $dummy1739) + (func $dummy1740) + (func $dummy1741) + (func $dummy1742) + (func $dummy1743) + (func $dummy1744) + (func $dummy1745) + (func $dummy1746) + (func $dummy1747) + (func $dummy1748) + (func $dummy1749) + (func $dummy1750) + (func $dummy1751) + (func $dummy1752) + (func $dummy1753) + (func $dummy1754) + (func $dummy1755) + (func $dummy1756) + (func $dummy1757) + (func $dummy1758) + (func $dummy1759) + (func $dummy1760) + (func $dummy1761) + (func $dummy1762) + (func $dummy1763) + (func $dummy1764) + (func $dummy1765) + (func $dummy1766) + (func $dummy1767) + (func $dummy1768) + (func $dummy1769) + (func $dummy1770) + (func $dummy1771) + (func $dummy1772) + (func $dummy1773) + (func $dummy1774) + (func $dummy1775) + (func $dummy1776) + (func $dummy1777) + (func $dummy1778) + (func $dummy1779) + (func $dummy1780) + (func $dummy1781) + (func $dummy1782) + (func $dummy1783) + (func $dummy1784) + (func $dummy1785) + (func $dummy1786) + (func $dummy1787) + (func $dummy1788) + (func $dummy1789) + (func $dummy1790) + (func $dummy1791) + (func $dummy1792) + (func $dummy1793) + (func $dummy1794) + (func $dummy1795) + (func $dummy1796) + (func $dummy1797) + (func $dummy1798) + (func $dummy1799) + (func $dummy1800) + (func $dummy1801) + (func $dummy1802) + (func $dummy1803) + (func $dummy1804) + (func $dummy1805) + (func $dummy1806) + (func $dummy1807) + (func $dummy1808) + (func $dummy1809) + (func $dummy1810) + (func $dummy1811) + (func $dummy1812) + (func $dummy1813) + (func $dummy1814) + (func $dummy1815) + (func $dummy1816) + (func $dummy1817) + (func $dummy1818) + (func $dummy1819) + (func $dummy1820) + (func $dummy1821) + (func $dummy1822) + (func $dummy1823) + (func $dummy1824) + (func $dummy1825) + (func $dummy1826) + (func $dummy1827) + (func $dummy1828) + (func $dummy1829) + (func $dummy1830) + (func $dummy1831) + (func $dummy1832) + (func $dummy1833) + (func $dummy1834) + (func $dummy1835) + (func $dummy1836) + (func $dummy1837) + (func $dummy1838) + (func $dummy1839) + (func $dummy1840) + (func $dummy1841) + (func $dummy1842) + (func $dummy1843) + (func $dummy1844) + (func $dummy1845) + (func $dummy1846) + (func $dummy1847) + (func $dummy1848) + (func $dummy1849) + (func $dummy1850) + (func $dummy1851) + (func $dummy1852) + (func $dummy1853) + (func $dummy1854) + (func $dummy1855) + (func $dummy1856) + (func $dummy1857) + (func $dummy1858) + (func $dummy1859) + (func $dummy1860) + (func $dummy1861) + (func $dummy1862) + (func $dummy1863) + (func $dummy1864) + (func $dummy1865) + (func $dummy1866) + (func $dummy1867) + (func $dummy1868) + (func $dummy1869) + (func $dummy1870) + (func $dummy1871) + (func $dummy1872) + (func $dummy1873) + (func $dummy1874) + (func $dummy1875) + (func $dummy1876) + (func $dummy1877) + (func $dummy1878) + (func $dummy1879) + (func $dummy1880) + (func $dummy1881) + (func $dummy1882) + (func $dummy1883) + (func $dummy1884) + (func $dummy1885) + (func $dummy1886) + (func $dummy1887) + (func $dummy1888) + (func $dummy1889) + (func $dummy1890) + (func $dummy1891) + (func $dummy1892) + (func $dummy1893) + (func $dummy1894) + (func $dummy1895) + (func $dummy1896) + (func $dummy1897) + (func $dummy1898) + (func $dummy1899) + (func $dummy1900) + (func $dummy1901) + (func $dummy1902) + (func $dummy1903) + (func $dummy1904) + (func $dummy1905) + (func $dummy1906) + (func $dummy1907) + (func $dummy1908) + (func $dummy1909) + (func $dummy1910) + (func $dummy1911) + (func $dummy1912) + (func $dummy1913) + (func $dummy1914) + (func $dummy1915) + (func $dummy1916) + (func $dummy1917) + (func $dummy1918) + (func $dummy1919) + (func $dummy1920) + (func $dummy1921) + (func $dummy1922) + (func $dummy1923) + (func $dummy1924) + (func $dummy1925) + (func $dummy1926) + (func $dummy1927) + (func $dummy1928) + (func $dummy1929) + (func $dummy1930) + (func $dummy1931) + (func $dummy1932) + (func $dummy1933) + (func $dummy1934) + (func $dummy1935) + (func $dummy1936) + (func $dummy1937) + (func $dummy1938) + (func $dummy1939) + (func $dummy1940) + (func $dummy1941) + (func $dummy1942) + (func $dummy1943) + (func $dummy1944) + (func $dummy1945) + (func $dummy1946) + (func $dummy1947) + (func $dummy1948) + (func $dummy1949) + (func $dummy1950) + (func $dummy1951) + (func $dummy1952) + (func $dummy1953) + (func $dummy1954) + (func $dummy1955) + (func $dummy1956) + (func $dummy1957) + (func $dummy1958) + (func $dummy1959) + (func $dummy1960) + (func $dummy1961) + (func $dummy1962) + (func $dummy1963) + (func $dummy1964) + (func $dummy1965) + (func $dummy1966) + (func $dummy1967) + (func $dummy1968) + (func $dummy1969) + (func $dummy1970) + (func $dummy1971) + (func $dummy1972) + (func $dummy1973) + (func $dummy1974) + (func $dummy1975) + (func $dummy1976) + (func $dummy1977) + (func $dummy1978) + (func $dummy1979) + (func $dummy1980) + (func $dummy1981) + (func $dummy1982) + (func $dummy1983) + (func $dummy1984) + (func $dummy1985) + (func $dummy1986) + (func $dummy1987) + (func $dummy1988) + (func $dummy1989) + (func $dummy1990) + (func $dummy1991) + (func $dummy1992) + (func $dummy1993) + (func $dummy1994) + (func $dummy1995) + (func $dummy1996) + (func $dummy1997) + (func $dummy1998) + (func $dummy1999) + (func $dummy2000) + (func $dummy2001) + (func $dummy2002) + (func $dummy2003) + (func $dummy2004) + (func $dummy2005) + (func $dummy2006) + (func $dummy2007) + (func $dummy2008) + (func $dummy2009) + (func $dummy2010) + (func $dummy2011) + (func $dummy2012) + (func $dummy2013) + (func $dummy2014) + (func $dummy2015) + (func $dummy2016) + (func $dummy2017) + (func $dummy2018) + (func $dummy2019) + (func $dummy2020) + (func $dummy2021) + (func $dummy2022) + (func $dummy2023) + (func $dummy2024) + (func $dummy2025) + (func $dummy2026) + (func $dummy2027) + (func $dummy2028) + (func $dummy2029) + (func $dummy2030) + (func $dummy2031) + (func $dummy2032) + (func $dummy2033) + (func $dummy2034) + (func $dummy2035) + (func $dummy2036) + (func $dummy2037) + (func $dummy2038) + (func $dummy2039) + (func $dummy2040) + (func $dummy2041) + (func $dummy2042) + (func $dummy2043) + (func $dummy2044) + (func $dummy2045) + (func $dummy2046) + (func $dummy2047) + (func $dummy2048) + (func $dummy2049) + (func $dummy2050) + (func $dummy2051) + (func $dummy2052) + (func $dummy2053) + (func $dummy2054) + (func $dummy2055) + (func $dummy2056) + (func $dummy2057) + (func $dummy2058) + (func $dummy2059) + (func $dummy2060) + (func $dummy2061) + (func $dummy2062) + (func $dummy2063) + (func $dummy2064) + (func $dummy2065) + (func $dummy2066) + (func $dummy2067) + (func $dummy2068) + (func $dummy2069) + (func $dummy2070) + (func $dummy2071) + (func $dummy2072) + (func $dummy2073) + (func $dummy2074) + (func $dummy2075) + (func $dummy2076) + (func $dummy2077) + (func $dummy2078) + (func $dummy2079) + (func $dummy2080) + (func $dummy2081) + (func $dummy2082) + (func $dummy2083) + (func $dummy2084) + (func $dummy2085) + (func $dummy2086) + (func $dummy2087) + (func $dummy2088) + (func $dummy2089) + (func $dummy2090) + (func $dummy2091) + (func $dummy2092) + (func $dummy2093) + (func $dummy2094) + (func $dummy2095) + (func $dummy2096) + (func $dummy2097) + (func $dummy2098) + (func $dummy2099) + (func $dummy2100) + (func $dummy2101) + (func $dummy2102) + (func $dummy2103) + (func $dummy2104) + (func $dummy2105) + (func $dummy2106) + (func $dummy2107) + (func $dummy2108) + (func $dummy2109) + (func $dummy2110) + (func $dummy2111) + (func $dummy2112) + (func $dummy2113) + (func $dummy2114) + (func $dummy2115) + (func $dummy2116) + (func $dummy2117) + (func $dummy2118) + (func $dummy2119) + (func $dummy2120) + (func $dummy2121) + (func $dummy2122) + (func $dummy2123) + (func $dummy2124) + (func $dummy2125) + (func $dummy2126) + (func $dummy2127) + (func $dummy2128) + (func $dummy2129) + (func $dummy2130) + (func $dummy2131) + (func $dummy2132) + (func $dummy2133) + (func $dummy2134) + (func $dummy2135) + (func $dummy2136) + (func $dummy2137) + (func $dummy2138) + (func $dummy2139) + (func $dummy2140) + (func $dummy2141) + (func $dummy2142) + (func $dummy2143) + (func $dummy2144) + (func $dummy2145) + (func $dummy2146) + (func $dummy2147) + (func $dummy2148) + (func $dummy2149) + (func $dummy2150) + (func $dummy2151) + (func $dummy2152) + (func $dummy2153) + (func $dummy2154) + (func $dummy2155) + (func $dummy2156) + (func $dummy2157) + (func $dummy2158) + (func $dummy2159) + (func $dummy2160) + (func $dummy2161) + (func $dummy2162) + (func $dummy2163) + (func $dummy2164) + (func $dummy2165) + (func $dummy2166) + (func $dummy2167) + (func $dummy2168) + (func $dummy2169) + (func $dummy2170) + (func $dummy2171) + (func $dummy2172) + (func $dummy2173) + (func $dummy2174) + (func $dummy2175) + (func $dummy2176) + (func $dummy2177) + (func $dummy2178) + (func $dummy2179) + (func $dummy2180) + (func $dummy2181) + (func $dummy2182) + (func $dummy2183) + (func $dummy2184) + (func $dummy2185) + (func $dummy2186) + (func $dummy2187) + (func $dummy2188) + (func $dummy2189) + (func $dummy2190) + (func $dummy2191) + (func $dummy2192) + (func $dummy2193) + (func $dummy2194) + (func $dummy2195) + (func $dummy2196) + (func $dummy2197) + (func $dummy2198) + (func $dummy2199) + (func $dummy2200) + (func $dummy2201) + (func $dummy2202) + (func $dummy2203) + (func $dummy2204) + (func $dummy2205) + (func $dummy2206) + (func $dummy2207) + (func $dummy2208) + (func $dummy2209) + (func $dummy2210) + (func $dummy2211) + (func $dummy2212) + (func $dummy2213) + (func $dummy2214) + (func $dummy2215) + (func $dummy2216) + (func $dummy2217) + (func $dummy2218) + (func $dummy2219) + (func $dummy2220) + (func $dummy2221) + (func $dummy2222) + (func $dummy2223) + (func $dummy2224) + (func $dummy2225) + (func $dummy2226) + (func $dummy2227) + (func $dummy2228) + (func $dummy2229) + (func $dummy2230) + (func $dummy2231) + (func $dummy2232) + (func $dummy2233) + (func $dummy2234) + (func $dummy2235) + (func $dummy2236) + (func $dummy2237) + (func $dummy2238) + (func $dummy2239) + (func $dummy2240) + (func $dummy2241) + (func $dummy2242) + (func $dummy2243) + (func $dummy2244) + (func $dummy2245) + (func $dummy2246) + (func $dummy2247) + (func $dummy2248) + (func $dummy2249) + (func $dummy2250) + (func $dummy2251) + (func $dummy2252) + (func $dummy2253) + (func $dummy2254) + (func $dummy2255) + (func $dummy2256) + (func $dummy2257) + (func $dummy2258) + (func $dummy2259) + (func $dummy2260) + (func $dummy2261) + (func $dummy2262) + (func $dummy2263) + (func $dummy2264) + (func $dummy2265) + (func $dummy2266) + (func $dummy2267) + (func $dummy2268) + (func $dummy2269) + (func $dummy2270) + (func $dummy2271) + (func $dummy2272) + (func $dummy2273) + (func $dummy2274) + (func $dummy2275) + (func $dummy2276) + (func $dummy2277) + (func $dummy2278) + (func $dummy2279) + (func $dummy2280) + (func $dummy2281) + (func $dummy2282) + (func $dummy2283) + (func $dummy2284) + (func $dummy2285) + (func $dummy2286) + (func $dummy2287) + (func $dummy2288) + (func $dummy2289) + (func $dummy2290) + (func $dummy2291) + (func $dummy2292) + (func $dummy2293) + (func $dummy2294) + (func $dummy2295) + (func $dummy2296) + (func $dummy2297) + (func $dummy2298) + (func $dummy2299) + (func $dummy2300) + (func $dummy2301) + (func $dummy2302) + (func $dummy2303) + (func $dummy2304) + (func $dummy2305) + (func $dummy2306) + (func $dummy2307) + (func $dummy2308) + (func $dummy2309) + (func $dummy2310) + (func $dummy2311) + (func $dummy2312) + (func $dummy2313) + (func $dummy2314) + (func $dummy2315) + (func $dummy2316) + (func $dummy2317) + (func $dummy2318) + (func $dummy2319) + (func $dummy2320) + (func $dummy2321) + (func $dummy2322) + (func $dummy2323) + (func $dummy2324) + (func $dummy2325) + (func $dummy2326) + (func $dummy2327) + (func $dummy2328) + (func $dummy2329) + (func $dummy2330) + (func $dummy2331) + (func $dummy2332) + (func $dummy2333) + (func $dummy2334) + (func $dummy2335) + (func $dummy2336) + (func $dummy2337) + (func $dummy2338) + (func $dummy2339) + (func $dummy2340) + (func $dummy2341) + (func $dummy2342) + (func $dummy2343) + (func $dummy2344) + (func $dummy2345) + (func $dummy2346) + (func $dummy2347) + (func $dummy2348) + (func $dummy2349) + (func $dummy2350) + (func $dummy2351) + (func $dummy2352) + (func $dummy2353) + (func $dummy2354) + (func $dummy2355) + (func $dummy2356) + (func $dummy2357) + (func $dummy2358) + (func $dummy2359) + (func $dummy2360) + (func $dummy2361) + (func $dummy2362) + (func $dummy2363) + (func $dummy2364) + (func $dummy2365) + (func $dummy2366) + (func $dummy2367) + (func $dummy2368) + (func $dummy2369) + (func $dummy2370) + (func $dummy2371) + (func $dummy2372) + (func $dummy2373) + (func $dummy2374) + (func $dummy2375) + (func $dummy2376) + (func $dummy2377) + (func $dummy2378) + (func $dummy2379) + (func $dummy2380) + (func $dummy2381) + (func $dummy2382) + (func $dummy2383) + (func $dummy2384) + (func $dummy2385) + (func $dummy2386) + (func $dummy2387) + (func $dummy2388) + (func $dummy2389) + (func $dummy2390) + (func $dummy2391) + (func $dummy2392) + (func $dummy2393) + (func $dummy2394) + (func $dummy2395) + (func $dummy2396) + (func $dummy2397) + (func $dummy2398) + (func $dummy2399) + (func $dummy2400) + (func $dummy2401) + (func $dummy2402) + (func $dummy2403) + (func $dummy2404) + (func $dummy2405) + (func $dummy2406) + (func $dummy2407) + (func $dummy2408) + (func $dummy2409) + (func $dummy2410) + (func $dummy2411) + (func $dummy2412) + (func $dummy2413) + (func $dummy2414) + (func $dummy2415) + (func $dummy2416) + (func $dummy2417) + (func $dummy2418) + (func $dummy2419) + (func $dummy2420) + (func $dummy2421) + (func $dummy2422) + (func $dummy2423) + (func $dummy2424) + (func $dummy2425) + (func $dummy2426) + (func $dummy2427) + (func $dummy2428) + (func $dummy2429) + (func $dummy2430) + (func $dummy2431) + (func $dummy2432) + (func $dummy2433) + (func $dummy2434) + (func $dummy2435) + (func $dummy2436) + (func $dummy2437) + (func $dummy2438) + (func $dummy2439) + (func $dummy2440) + (func $dummy2441) + (func $dummy2442) + (func $dummy2443) + (func $dummy2444) + (func $dummy2445) + (func $dummy2446) + (func $dummy2447) + (func $dummy2448) + (func $dummy2449) + (func $dummy2450) + (func $dummy2451) + (func $dummy2452) + (func $dummy2453) + (func $dummy2454) + (func $dummy2455) + (func $dummy2456) + (func $dummy2457) + (func $dummy2458) + (func $dummy2459) + (func $dummy2460) + (func $dummy2461) + (func $dummy2462) + (func $dummy2463) + (func $dummy2464) + (func $dummy2465) + (func $dummy2466) + (func $dummy2467) + (func $dummy2468) + (func $dummy2469) + (func $dummy2470) + (func $dummy2471) + (func $dummy2472) + (func $dummy2473) + (func $dummy2474) + (func $dummy2475) + (func $dummy2476) + (func $dummy2477) + (func $dummy2478) + (func $dummy2479) + (func $dummy2480) + (func $dummy2481) + (func $dummy2482) + (func $dummy2483) + (func $dummy2484) + (func $dummy2485) + (func $dummy2486) + (func $dummy2487) + (func $dummy2488) + (func $dummy2489) + (func $dummy2490) + (func $dummy2491) + (func $dummy2492) + (func $dummy2493) + (func $dummy2494) + (func $dummy2495) + (func $dummy2496) + (func $dummy2497) + (func $dummy2498) + (func $dummy2499) + (func $dummy2500) + (func $dummy2501) + (func $dummy2502) + (func $dummy2503) + (func $dummy2504) + (func $dummy2505) + (func $dummy2506) + (func $dummy2507) + (func $dummy2508) + (func $dummy2509) + (func $dummy2510) + (func $dummy2511) + (func $dummy2512) + (func $dummy2513) + (func $dummy2514) + (func $dummy2515) + (func $dummy2516) + (func $dummy2517) + (func $dummy2518) + (func $dummy2519) + (func $dummy2520) + (func $dummy2521) + (func $dummy2522) + (func $dummy2523) + (func $dummy2524) + (func $dummy2525) + (func $dummy2526) + (func $dummy2527) + (func $dummy2528) + (func $dummy2529) + (func $dummy2530) + (func $dummy2531) + (func $dummy2532) + (func $dummy2533) + (func $dummy2534) + (func $dummy2535) + (func $dummy2536) + (func $dummy2537) + (func $dummy2538) + (func $dummy2539) + (func $dummy2540) + (func $dummy2541) + (func $dummy2542) + (func $dummy2543) + (func $dummy2544) + (func $dummy2545) + (func $dummy2546) + (func $dummy2547) + (func $dummy2548) + (func $dummy2549) + (func $dummy2550) + (func $dummy2551) + (func $dummy2552) + (func $dummy2553) + (func $dummy2554) + (func $dummy2555) + (func $dummy2556) + (func $dummy2557) + (func $dummy2558) + (func $dummy2559) + (func $dummy2560) + (func $dummy2561) + (func $dummy2562) + (func $dummy2563) + (func $dummy2564) + (func $dummy2565) + (func $dummy2566) + (func $dummy2567) + (func $dummy2568) + (func $dummy2569) + (func $dummy2570) + (func $dummy2571) + (func $dummy2572) + (func $dummy2573) + (func $dummy2574) + (func $dummy2575) + (func $dummy2576) + (func $dummy2577) + (func $dummy2578) + (func $dummy2579) + (func $dummy2580) + (func $dummy2581) + (func $dummy2582) + (func $dummy2583) + (func $dummy2584) + (func $dummy2585) + (func $dummy2586) + (func $dummy2587) + (func $dummy2588) + (func $dummy2589) + (func $dummy2590) + (func $dummy2591) + (func $dummy2592) + (func $dummy2593) + (func $dummy2594) + (func $dummy2595) + (func $dummy2596) + (func $dummy2597) + (func $dummy2598) + (func $dummy2599) + (func $dummy2600) + (func $dummy2601) + (func $dummy2602) + (func $dummy2603) + (func $dummy2604) + (func $dummy2605) + (func $dummy2606) + (func $dummy2607) + (func $dummy2608) + (func $dummy2609) + (func $dummy2610) + (func $dummy2611) + (func $dummy2612) + (func $dummy2613) + (func $dummy2614) + (func $dummy2615) + (func $dummy2616) + (func $dummy2617) + (func $dummy2618) + (func $dummy2619) + (func $dummy2620) + (func $dummy2621) + (func $dummy2622) + (func $dummy2623) + (func $dummy2624) + (func $dummy2625) + (func $dummy2626) + (func $dummy2627) + (func $dummy2628) + (func $dummy2629) + (func $dummy2630) + (func $dummy2631) + (func $dummy2632) + (func $dummy2633) + (func $dummy2634) + (func $dummy2635) + (func $dummy2636) + (func $dummy2637) + (func $dummy2638) + (func $dummy2639) + (func $dummy2640) + (func $dummy2641) + (func $dummy2642) + (func $dummy2643) + (func $dummy2644) + (func $dummy2645) + (func $dummy2646) + (func $dummy2647) + (func $dummy2648) + (func $dummy2649) + (func $dummy2650) + (func $dummy2651) + (func $dummy2652) + (func $dummy2653) + (func $dummy2654) + (func $dummy2655) + (func $dummy2656) + (func $dummy2657) + (func $dummy2658) + (func $dummy2659) + (func $dummy2660) + (func $dummy2661) + (func $dummy2662) + (func $dummy2663) + (func $dummy2664) + (func $dummy2665) + (func $dummy2666) + (func $dummy2667) + (func $dummy2668) + (func $dummy2669) + (func $dummy2670) + (func $dummy2671) + (func $dummy2672) + (func $dummy2673) + (func $dummy2674) + (func $dummy2675) + (func $dummy2676) + (func $dummy2677) + (func $dummy2678) + (func $dummy2679) + (func $dummy2680) + (func $dummy2681) + (func $dummy2682) + (func $dummy2683) + (func $dummy2684) + (func $dummy2685) + (func $dummy2686) + (func $dummy2687) + (func $dummy2688) + (func $dummy2689) + (func $dummy2690) + (func $dummy2691) + (func $dummy2692) + (func $dummy2693) + (func $dummy2694) + (func $dummy2695) + (func $dummy2696) + (func $dummy2697) + (func $dummy2698) + (func $dummy2699) + (func $dummy2700) + (func $dummy2701) + (func $dummy2702) + (func $dummy2703) + (func $dummy2704) + (func $dummy2705) + (func $dummy2706) + (func $dummy2707) + (func $dummy2708) + (func $dummy2709) + (func $dummy2710) + (func $dummy2711) + (func $dummy2712) + (func $dummy2713) + (func $dummy2714) + (func $dummy2715) + (func $dummy2716) + (func $dummy2717) + (func $dummy2718) + (func $dummy2719) + (func $dummy2720) + (func $dummy2721) + (func $dummy2722) + (func $dummy2723) + (func $dummy2724) + (func $dummy2725) + (func $dummy2726) + (func $dummy2727) + (func $dummy2728) + (func $dummy2729) + (func $dummy2730) + (func $dummy2731) + (func $dummy2732) + (func $dummy2733) + (func $dummy2734) + (func $dummy2735) + (func $dummy2736) + (func $dummy2737) + (func $dummy2738) + (func $dummy2739) + (func $dummy2740) + (func $dummy2741) + (func $dummy2742) + (func $dummy2743) + (func $dummy2744) + (func $dummy2745) + (func $dummy2746) + (func $dummy2747) + (func $dummy2748) + (func $dummy2749) + (func $dummy2750) + (func $dummy2751) + (func $dummy2752) + (func $dummy2753) + (func $dummy2754) + (func $dummy2755) + (func $dummy2756) + (func $dummy2757) + (func $dummy2758) + (func $dummy2759) + (func $dummy2760) + (func $dummy2761) + (func $dummy2762) + (func $dummy2763) + (func $dummy2764) + (func $dummy2765) + (func $dummy2766) + (func $dummy2767) + (func $dummy2768) + (func $dummy2769) + (func $dummy2770) + (func $dummy2771) + (func $dummy2772) + (func $dummy2773) + (func $dummy2774) + (func $dummy2775) + (func $dummy2776) + (func $dummy2777) + (func $dummy2778) + (func $dummy2779) + (func $dummy2780) + (func $dummy2781) + (func $dummy2782) + (func $dummy2783) + (func $dummy2784) + (func $dummy2785) + (func $dummy2786) + (func $dummy2787) + (func $dummy2788) + (func $dummy2789) + (func $dummy2790) + (func $dummy2791) + (func $dummy2792) + (func $dummy2793) + (func $dummy2794) + (func $dummy2795) + (func $dummy2796) + (func $dummy2797) + (func $dummy2798) + (func $dummy2799) + (func $dummy2800) + (func $dummy2801) + (func $dummy2802) + (func $dummy2803) + (func $dummy2804) + (func $dummy2805) + (func $dummy2806) + (func $dummy2807) + (func $dummy2808) + (func $dummy2809) + (func $dummy2810) + (func $dummy2811) + (func $dummy2812) + (func $dummy2813) + (func $dummy2814) + (func $dummy2815) + (func $dummy2816) + (func $dummy2817) + (func $dummy2818) + (func $dummy2819) + (func $dummy2820) + (func $dummy2821) + (func $dummy2822) + (func $dummy2823) + (func $dummy2824) + (func $dummy2825) + (func $dummy2826) + (func $dummy2827) + (func $dummy2828) + (func $dummy2829) + (func $dummy2830) + (func $dummy2831) + (func $dummy2832) + (func $dummy2833) + (func $dummy2834) + (func $dummy2835) + (func $dummy2836) + (func $dummy2837) + (func $dummy2838) + (func $dummy2839) + (func $dummy2840) + (func $dummy2841) + (func $dummy2842) + (func $dummy2843) + (func $dummy2844) + (func $dummy2845) + (func $dummy2846) + (func $dummy2847) + (func $dummy2848) + (func $dummy2849) + (func $dummy2850) + (func $dummy2851) + (func $dummy2852) + (func $dummy2853) + (func $dummy2854) + (func $dummy2855) + (func $dummy2856) + (func $dummy2857) + (func $dummy2858) + (func $dummy2859) + (func $dummy2860) + (func $dummy2861) + (func $dummy2862) + (func $dummy2863) + (func $dummy2864) + (func $dummy2865) + (func $dummy2866) + (func $dummy2867) + (func $dummy2868) + (func $dummy2869) + (func $dummy2870) + (func $dummy2871) + (func $dummy2872) + (func $dummy2873) + (func $dummy2874) + (func $dummy2875) + (func $dummy2876) + (func $dummy2877) + (func $dummy2878) + (func $dummy2879) + (func $dummy2880) + (func $dummy2881) + (func $dummy2882) + (func $dummy2883) + (func $dummy2884) + (func $dummy2885) + (func $dummy2886) + (func $dummy2887) + (func $dummy2888) + (func $dummy2889) + (func $dummy2890) + (func $dummy2891) + (func $dummy2892) + (func $dummy2893) + (func $dummy2894) + (func $dummy2895) + (func $dummy2896) + (func $dummy2897) + (func $dummy2898) + (func $dummy2899) + (func $dummy2900) + (func $dummy2901) + (func $dummy2902) + (func $dummy2903) + (func $dummy2904) + (func $dummy2905) + (func $dummy2906) + (func $dummy2907) + (func $dummy2908) + (func $dummy2909) + (func $dummy2910) + (func $dummy2911) + (func $dummy2912) + (func $dummy2913) + (func $dummy2914) + (func $dummy2915) + (func $dummy2916) + (func $dummy2917) + (func $dummy2918) + (func $dummy2919) + (func $dummy2920) + (func $dummy2921) + (func $dummy2922) + (func $dummy2923) + (func $dummy2924) + (func $dummy2925) + (func $dummy2926) + (func $dummy2927) + (func $dummy2928) + (func $dummy2929) + (func $dummy2930) + (func $dummy2931) + (func $dummy2932) + (func $dummy2933) + (func $dummy2934) + (func $dummy2935) + (func $dummy2936) + (func $dummy2937) + (func $dummy2938) + (func $dummy2939) + (func $dummy2940) + (func $dummy2941) + (func $dummy2942) + (func $dummy2943) + (func $dummy2944) + (func $dummy2945) + (func $dummy2946) + (func $dummy2947) + (func $dummy2948) + (func $dummy2949) + (func $dummy2950) + (func $dummy2951) + (func $dummy2952) + (func $dummy2953) + (func $dummy2954) + (func $dummy2955) + (func $dummy2956) + (func $dummy2957) + (func $dummy2958) + (func $dummy2959) + (func $dummy2960) + (func $dummy2961) + (func $dummy2962) + (func $dummy2963) + (func $dummy2964) + (func $dummy2965) + (func $dummy2966) + (func $dummy2967) + (func $dummy2968) + (func $dummy2969) + (func $dummy2970) + (func $dummy2971) + (func $dummy2972) + (func $dummy2973) + (func $dummy2974) + (func $dummy2975) + (func $dummy2976) + (func $dummy2977) + (func $dummy2978) + (func $dummy2979) + (func $dummy2980) + (func $dummy2981) + (func $dummy2982) + (func $dummy2983) + (func $dummy2984) + (func $dummy2985) + (func $dummy2986) + (func $dummy2987) + (func $dummy2988) + (func $dummy2989) + (func $dummy2990) + (func $dummy2991) + (func $dummy2992) + (func $dummy2993) + (func $dummy2994) + (func $dummy2995) + (func $dummy2996) + (func $dummy2997) + (func $dummy2998) + (func $dummy2999) + (func $dummy3000) + (func $dummy3001) + (func $dummy3002) + (func $dummy3003) + (func $dummy3004) + (func $dummy3005) + (func $dummy3006) + (func $dummy3007) + (func $dummy3008) + (func $dummy3009) + (func $dummy3010) + (func $dummy3011) + (func $dummy3012) + (func $dummy3013) + (func $dummy3014) + (func $dummy3015) + (func $dummy3016) + (func $dummy3017) + (func $dummy3018) + (func $dummy3019) + (func $dummy3020) + (func $dummy3021) + (func $dummy3022) + (func $dummy3023) + (func $dummy3024) + (func $dummy3025) + (func $dummy3026) + (func $dummy3027) + (func $dummy3028) + (func $dummy3029) + (func $dummy3030) + (func $dummy3031) + (func $dummy3032) + (func $dummy3033) + (func $dummy3034) + (func $dummy3035) + (func $dummy3036) + (func $dummy3037) + (func $dummy3038) + (func $dummy3039) + (func $dummy3040) + (func $dummy3041) + (func $dummy3042) + (func $dummy3043) + (func $dummy3044) + (func $dummy3045) + (func $dummy3046) + (func $dummy3047) + (func $dummy3048) + (func $dummy3049) + (func $dummy3050) + (func $dummy3051) + (func $dummy3052) + (func $dummy3053) + (func $dummy3054) + (func $dummy3055) + (func $dummy3056) + (func $dummy3057) + (func $dummy3058) + (func $dummy3059) + (func $dummy3060) + (func $dummy3061) + (func $dummy3062) + (func $dummy3063) + (func $dummy3064) + (func $dummy3065) + (func $dummy3066) + (func $dummy3067) + (func $dummy3068) + (func $dummy3069) + (func $dummy3070) + (func $dummy3071) + (func $dummy3072) + (func $dummy3073) + (func $dummy3074) + (func $dummy3075) + (func $dummy3076) + (func $dummy3077) + (func $dummy3078) + (func $dummy3079) + (func $dummy3080) + (func $dummy3081) + (func $dummy3082) + (func $dummy3083) + (func $dummy3084) + (func $dummy3085) + (func $dummy3086) + (func $dummy3087) + (func $dummy3088) + (func $dummy3089) + (func $dummy3090) + (func $dummy3091) + (func $dummy3092) + (func $dummy3093) + (func $dummy3094) + (func $dummy3095) + (func $dummy3096) + (func $dummy3097) + (func $dummy3098) + (func $dummy3099) + (func $dummy3100) + (func $dummy3101) + (func $dummy3102) + (func $dummy3103) + (func $dummy3104) + (func $dummy3105) + (func $dummy3106) + (func $dummy3107) + (func $dummy3108) + (func $dummy3109) + (func $dummy3110) + (func $dummy3111) + (func $dummy3112) + (func $dummy3113) + (func $dummy3114) + (func $dummy3115) + (func $dummy3116) + (func $dummy3117) + (func $dummy3118) + (func $dummy3119) + (func $dummy3120) + (func $dummy3121) + (func $dummy3122) + (func $dummy3123) + (func $dummy3124) + (func $dummy3125) + (func $dummy3126) + (func $dummy3127) + (func $dummy3128) + (func $dummy3129) + (func $dummy3130) + (func $dummy3131) + (func $dummy3132) + (func $dummy3133) + (func $dummy3134) + (func $dummy3135) + (func $dummy3136) + (func $dummy3137) + (func $dummy3138) + (func $dummy3139) + (func $dummy3140) + (func $dummy3141) + (func $dummy3142) + (func $dummy3143) + (func $dummy3144) + (func $dummy3145) + (func $dummy3146) + (func $dummy3147) + (func $dummy3148) + (func $dummy3149) + (func $dummy3150) + (func $dummy3151) + (func $dummy3152) + (func $dummy3153) + (func $dummy3154) + (func $dummy3155) + (func $dummy3156) + (func $dummy3157) + (func $dummy3158) + (func $dummy3159) + (func $dummy3160) + (func $dummy3161) + (func $dummy3162) + (func $dummy3163) + (func $dummy3164) + (func $dummy3165) + (func $dummy3166) + (func $dummy3167) + (func $dummy3168) + (func $dummy3169) + (func $dummy3170) + (func $dummy3171) + (func $dummy3172) + (func $dummy3173) + (func $dummy3174) + (func $dummy3175) + (func $dummy3176) + (func $dummy3177) + (func $dummy3178) + (func $dummy3179) + (func $dummy3180) + (func $dummy3181) + (func $dummy3182) + (func $dummy3183) + (func $dummy3184) + (func $dummy3185) + (func $dummy3186) + (func $dummy3187) + (func $dummy3188) + (func $dummy3189) + (func $dummy3190) + (func $dummy3191) + (func $dummy3192) + (func $dummy3193) + (func $dummy3194) + (func $dummy3195) + (func $dummy3196) + (func $dummy3197) + (func $dummy3198) + (func $dummy3199) + (func $dummy3200) + (func $dummy3201) + (func $dummy3202) + (func $dummy3203) + (func $dummy3204) + (func $dummy3205) + (func $dummy3206) + (func $dummy3207) + (func $dummy3208) + (func $dummy3209) + (func $dummy3210) + (func $dummy3211) + (func $dummy3212) + (func $dummy3213) + (func $dummy3214) + (func $dummy3215) + (func $dummy3216) + (func $dummy3217) + (func $dummy3218) + (func $dummy3219) + (func $dummy3220) + (func $dummy3221) + (func $dummy3222) + (func $dummy3223) + (func $dummy3224) + (func $dummy3225) + (func $dummy3226) + (func $dummy3227) + (func $dummy3228) + (func $dummy3229) + (func $dummy3230) + (func $dummy3231) + (func $dummy3232) + (func $dummy3233) + (func $dummy3234) + (func $dummy3235) + (func $dummy3236) + (func $dummy3237) + (func $dummy3238) + (func $dummy3239) + (func $dummy3240) + (func $dummy3241) + (func $dummy3242) + (func $dummy3243) + (func $dummy3244) + (func $dummy3245) + (func $dummy3246) + (func $dummy3247) + (func $dummy3248) + (func $dummy3249) + (func $dummy3250) + (func $dummy3251) + (func $dummy3252) + (func $dummy3253) + (func $dummy3254) + (func $dummy3255) + (func $dummy3256) + (func $dummy3257) + (func $dummy3258) + (func $dummy3259) + (func $dummy3260) + (func $dummy3261) + (func $dummy3262) + (func $dummy3263) + (func $dummy3264) + (func $dummy3265) + (func $dummy3266) + (func $dummy3267) + (func $dummy3268) + (func $dummy3269) + (func $dummy3270) + (func $dummy3271) + (func $dummy3272) + (func $dummy3273) + (func $dummy3274) + (func $dummy3275) + (func $dummy3276) + (func $dummy3277) + (func $dummy3278) + (func $dummy3279) + (func $dummy3280) + (func $dummy3281) + (func $dummy3282) + (func $dummy3283) + (func $dummy3284) + (func $dummy3285) + (func $dummy3286) + (func $dummy3287) + (func $dummy3288) + (func $dummy3289) + (func $dummy3290) + (func $dummy3291) + (func $dummy3292) + (func $dummy3293) + (func $dummy3294) + (func $dummy3295) + (func $dummy3296) + (func $dummy3297) + (func $dummy3298) + (func $dummy3299) + (func $dummy3300) + (func $dummy3301) + (func $dummy3302) + (func $dummy3303) + (func $dummy3304) + (func $dummy3305) + (func $dummy3306) + (func $dummy3307) + (func $dummy3308) + (func $dummy3309) + (func $dummy3310) + (func $dummy3311) + (func $dummy3312) + (func $dummy3313) + (func $dummy3314) + (func $dummy3315) + (func $dummy3316) + (func $dummy3317) + (func $dummy3318) + (func $dummy3319) + (func $dummy3320) + (func $dummy3321) + (func $dummy3322) + (func $dummy3323) + (func $dummy3324) + (func $dummy3325) + (func $dummy3326) + (func $dummy3327) + (func $dummy3328) + (func $dummy3329) + (func $dummy3330) + (func $dummy3331) + (func $dummy3332) + (func $dummy3333) + (func $dummy3334) + (func $dummy3335) + (func $dummy3336) + (func $dummy3337) + (func $dummy3338) + (func $dummy3339) + (func $dummy3340) + (func $dummy3341) + (func $dummy3342) + (func $dummy3343) + (func $dummy3344) + (func $dummy3345) + (func $dummy3346) + (func $dummy3347) + (func $dummy3348) + (func $dummy3349) + (func $dummy3350) + (func $dummy3351) + (func $dummy3352) + (func $dummy3353) + (func $dummy3354) + (func $dummy3355) + (func $dummy3356) + (func $dummy3357) + (func $dummy3358) + (func $dummy3359) + (func $dummy3360) + (func $dummy3361) + (func $dummy3362) + (func $dummy3363) + (func $dummy3364) + (func $dummy3365) + (func $dummy3366) + (func $dummy3367) + (func $dummy3368) + (func $dummy3369) + (func $dummy3370) + (func $dummy3371) + (func $dummy3372) + (func $dummy3373) + (func $dummy3374) + (func $dummy3375) + (func $dummy3376) + (func $dummy3377) + (func $dummy3378) + (func $dummy3379) + (func $dummy3380) + (func $dummy3381) + (func $dummy3382) + (func $dummy3383) + (func $dummy3384) + (func $dummy3385) + (func $dummy3386) + (func $dummy3387) + (func $dummy3388) + (func $dummy3389) + (func $dummy3390) + (func $dummy3391) + (func $dummy3392) + (func $dummy3393) + (func $dummy3394) + (func $dummy3395) + (func $dummy3396) + (func $dummy3397) + (func $dummy3398) + (func $dummy3399) + (func $dummy3400) + (func $dummy3401) + (func $dummy3402) + (func $dummy3403) + (func $dummy3404) + (func $dummy3405) + (func $dummy3406) + (func $dummy3407) + (func $dummy3408) + (func $dummy3409) + (func $dummy3410) + (func $dummy3411) + (func $dummy3412) + (func $dummy3413) + (func $dummy3414) + (func $dummy3415) + (func $dummy3416) + (func $dummy3417) + (func $dummy3418) + (func $dummy3419) + (func $dummy3420) + (func $dummy3421) + (func $dummy3422) + (func $dummy3423) + (func $dummy3424) + (func $dummy3425) + (func $dummy3426) + (func $dummy3427) + (func $dummy3428) + (func $dummy3429) + (func $dummy3430) + (func $dummy3431) + (func $dummy3432) + (func $dummy3433) + (func $dummy3434) + (func $dummy3435) + (func $dummy3436) + (func $dummy3437) + (func $dummy3438) + (func $dummy3439) + (func $dummy3440) + (func $dummy3441) + (func $dummy3442) + (func $dummy3443) + (func $dummy3444) + (func $dummy3445) + (func $dummy3446) + (func $dummy3447) + (func $dummy3448) + (func $dummy3449) + (func $dummy3450) + (func $dummy3451) + (func $dummy3452) + (func $dummy3453) + (func $dummy3454) + (func $dummy3455) + (func $dummy3456) + (func $dummy3457) + (func $dummy3458) + (func $dummy3459) + (func $dummy3460) + (func $dummy3461) + (func $dummy3462) + (func $dummy3463) + (func $dummy3464) + (func $dummy3465) + (func $dummy3466) + (func $dummy3467) + (func $dummy3468) + (func $dummy3469) + (func $dummy3470) + (func $dummy3471) + (func $dummy3472) + (func $dummy3473) + (func $dummy3474) + (func $dummy3475) + (func $dummy3476) + (func $dummy3477) + (func $dummy3478) + (func $dummy3479) + (func $dummy3480) + (func $dummy3481) + (func $dummy3482) + (func $dummy3483) + (func $dummy3484) + (func $dummy3485) + (func $dummy3486) + (func $dummy3487) + (func $dummy3488) + (func $dummy3489) + (func $dummy3490) + (func $dummy3491) + (func $dummy3492) + (func $dummy3493) + (func $dummy3494) + (func $dummy3495) + (func $dummy3496) + (func $dummy3497) + (func $dummy3498) + (func $dummy3499) + (func $dummy3500) + (func $dummy3501) + (func $dummy3502) + (func $dummy3503) + (func $dummy3504) + (func $dummy3505) + (func $dummy3506) + (func $dummy3507) + (func $dummy3508) + (func $dummy3509) + (func $dummy3510) + (func $dummy3511) + (func $dummy3512) + (func $dummy3513) + (func $dummy3514) + (func $dummy3515) + (func $dummy3516) + (func $dummy3517) + (func $dummy3518) + (func $dummy3519) + (func $dummy3520) + (func $dummy3521) + (func $dummy3522) + (func $dummy3523) + (func $dummy3524) + (func $dummy3525) + (func $dummy3526) + (func $dummy3527) + (func $dummy3528) + (func $dummy3529) + (func $dummy3530) + (func $dummy3531) + (func $dummy3532) + (func $dummy3533) + (func $dummy3534) + (func $dummy3535) + (func $dummy3536) + (func $dummy3537) + (func $dummy3538) + (func $dummy3539) + (func $dummy3540) + (func $dummy3541) + (func $dummy3542) + (func $dummy3543) + (func $dummy3544) + (func $dummy3545) + (func $dummy3546) + (func $dummy3547) + (func $dummy3548) + (func $dummy3549) + (func $dummy3550) + (func $dummy3551) + (func $dummy3552) + (func $dummy3553) + (func $dummy3554) + (func $dummy3555) + (func $dummy3556) + (func $dummy3557) + (func $dummy3558) + (func $dummy3559) + (func $dummy3560) + (func $dummy3561) + (func $dummy3562) + (func $dummy3563) + (func $dummy3564) + (func $dummy3565) + (func $dummy3566) + (func $dummy3567) + (func $dummy3568) + (func $dummy3569) + (func $dummy3570) + (func $dummy3571) + (func $dummy3572) + (func $dummy3573) + (func $dummy3574) + (func $dummy3575) + (func $dummy3576) + (func $dummy3577) + (func $dummy3578) + (func $dummy3579) + (func $dummy3580) + (func $dummy3581) + (func $dummy3582) + (func $dummy3583) + (func $dummy3584) + (func $dummy3585) + (func $dummy3586) + (func $dummy3587) + (func $dummy3588) + (func $dummy3589) + (func $dummy3590) + (func $dummy3591) + (func $dummy3592) + (func $dummy3593) + (func $dummy3594) + (func $dummy3595) + (func $dummy3596) + (func $dummy3597) + (func $dummy3598) + (func $dummy3599) + (func $dummy3600) + (func $dummy3601) + (func $dummy3602) + (func $dummy3603) + (func $dummy3604) + (func $dummy3605) + (func $dummy3606) + (func $dummy3607) + (func $dummy3608) + (func $dummy3609) + (func $dummy3610) + (func $dummy3611) + (func $dummy3612) + (func $dummy3613) + (func $dummy3614) + (func $dummy3615) + (func $dummy3616) + (func $dummy3617) + (func $dummy3618) + (func $dummy3619) + (func $dummy3620) + (func $dummy3621) + (func $dummy3622) + (func $dummy3623) + (func $dummy3624) + (func $dummy3625) + (func $dummy3626) + (func $dummy3627) + (func $dummy3628) + (func $dummy3629) + (func $dummy3630) + (func $dummy3631) + (func $dummy3632) + (func $dummy3633) + (func $dummy3634) + (func $dummy3635) + (func $dummy3636) + (func $dummy3637) + (func $dummy3638) + (func $dummy3639) + (func $dummy3640) + (func $dummy3641) + (func $dummy3642) + (func $dummy3643) + (func $dummy3644) + (func $dummy3645) + (func $dummy3646) + (func $dummy3647) + (func $dummy3648) + (func $dummy3649) + (func $dummy3650) + (func $dummy3651) + (func $dummy3652) + (func $dummy3653) + (func $dummy3654) + (func $dummy3655) + (func $dummy3656) + (func $dummy3657) + (func $dummy3658) + (func $dummy3659) + (func $dummy3660) + (func $dummy3661) + (func $dummy3662) + (func $dummy3663) + (func $dummy3664) + (func $dummy3665) + (func $dummy3666) + (func $dummy3667) + (func $dummy3668) + (func $dummy3669) + (func $dummy3670) + (func $dummy3671) + (func $dummy3672) + (func $dummy3673) + (func $dummy3674) + (func $dummy3675) + (func $dummy3676) + (func $dummy3677) + (func $dummy3678) + (func $dummy3679) + (func $dummy3680) + (func $dummy3681) + (func $dummy3682) + (func $dummy3683) + (func $dummy3684) + (func $dummy3685) + (func $dummy3686) + (func $dummy3687) + (func $dummy3688) + (func $dummy3689) + (func $dummy3690) + (func $dummy3691) + (func $dummy3692) + (func $dummy3693) + (func $dummy3694) + (func $dummy3695) + (func $dummy3696) + (func $dummy3697) + (func $dummy3698) + (func $dummy3699) + (func $dummy3700) + (func $dummy3701) + (func $dummy3702) + (func $dummy3703) + (func $dummy3704) + (func $dummy3705) + (func $dummy3706) + (func $dummy3707) + (func $dummy3708) + (func $dummy3709) + (func $dummy3710) + (func $dummy3711) + (func $dummy3712) + (func $dummy3713) + (func $dummy3714) + (func $dummy3715) + (func $dummy3716) + (func $dummy3717) + (func $dummy3718) + (func $dummy3719) + (func $dummy3720) + (func $dummy3721) + (func $dummy3722) + (func $dummy3723) + (func $dummy3724) + (func $dummy3725) + (func $dummy3726) + (func $dummy3727) + (func $dummy3728) + (func $dummy3729) + (func $dummy3730) + (func $dummy3731) + (func $dummy3732) + (func $dummy3733) + (func $dummy3734) + (func $dummy3735) + (func $dummy3736) + (func $dummy3737) + (func $dummy3738) + (func $dummy3739) + (func $dummy3740) + (func $dummy3741) + (func $dummy3742) + (func $dummy3743) + (func $dummy3744) + (func $dummy3745) + (func $dummy3746) + (func $dummy3747) + (func $dummy3748) + (func $dummy3749) + (func $dummy3750) + (func $dummy3751) + (func $dummy3752) + (func $dummy3753) + (func $dummy3754) + (func $dummy3755) + (func $dummy3756) + (func $dummy3757) + (func $dummy3758) + (func $dummy3759) + (func $dummy3760) + (func $dummy3761) + (func $dummy3762) + (func $dummy3763) + (func $dummy3764) + (func $dummy3765) + (func $dummy3766) + (func $dummy3767) + (func $dummy3768) + (func $dummy3769) + (func $dummy3770) + (func $dummy3771) + (func $dummy3772) + (func $dummy3773) + (func $dummy3774) + (func $dummy3775) + (func $dummy3776) + (func $dummy3777) + (func $dummy3778) + (func $dummy3779) + (func $dummy3780) + (func $dummy3781) + (func $dummy3782) + (func $dummy3783) + (func $dummy3784) + (func $dummy3785) + (func $dummy3786) + (func $dummy3787) + (func $dummy3788) + (func $dummy3789) + (func $dummy3790) + (func $dummy3791) + (func $dummy3792) + (func $dummy3793) + (func $dummy3794) + (func $dummy3795) + (func $dummy3796) + (func $dummy3797) + (func $dummy3798) + (func $dummy3799) + (func $dummy3800) + (func $dummy3801) + (func $dummy3802) + (func $dummy3803) + (func $dummy3804) + (func $dummy3805) + (func $dummy3806) + (func $dummy3807) + (func $dummy3808) + (func $dummy3809) + (func $dummy3810) + (func $dummy3811) + (func $dummy3812) + (func $dummy3813) + (func $dummy3814) + (func $dummy3815) + (func $dummy3816) + (func $dummy3817) + (func $dummy3818) + (func $dummy3819) + (func $dummy3820) + (func $dummy3821) + (func $dummy3822) + (func $dummy3823) + (func $dummy3824) + (func $dummy3825) + (func $dummy3826) + (func $dummy3827) + (func $dummy3828) + (func $dummy3829) + (func $dummy3830) + (func $dummy3831) + (func $dummy3832) + (func $dummy3833) + (func $dummy3834) + (func $dummy3835) + (func $dummy3836) + (func $dummy3837) + (func $dummy3838) + (func $dummy3839) + (func $dummy3840) + (func $dummy3841) + (func $dummy3842) + (func $dummy3843) + (func $dummy3844) + (func $dummy3845) + (func $dummy3846) + (func $dummy3847) + (func $dummy3848) + (func $dummy3849) + (func $dummy3850) + (func $dummy3851) + (func $dummy3852) + (func $dummy3853) + (func $dummy3854) + (func $dummy3855) + (func $dummy3856) + (func $dummy3857) + (func $dummy3858) + (func $dummy3859) + (func $dummy3860) + (func $dummy3861) + (func $dummy3862) + (func $dummy3863) + (func $dummy3864) + (func $dummy3865) + (func $dummy3866) + (func $dummy3867) + (func $dummy3868) + (func $dummy3869) + (func $dummy3870) + (func $dummy3871) + (func $dummy3872) + (func $dummy3873) + (func $dummy3874) + (func $dummy3875) + (func $dummy3876) + (func $dummy3877) + (func $dummy3878) + (func $dummy3879) + (func $dummy3880) + (func $dummy3881) + (func $dummy3882) + (func $dummy3883) + (func $dummy3884) + (func $dummy3885) + (func $dummy3886) + (func $dummy3887) + (func $dummy3888) + (func $dummy3889) + (func $dummy3890) + (func $dummy3891) + (func $dummy3892) + (func $dummy3893) + (func $dummy3894) + (func $dummy3895) + (func $dummy3896) + (func $dummy3897) + (func $dummy3898) + (func $dummy3899) + (func $dummy3900) + (func $dummy3901) + (func $dummy3902) + (func $dummy3903) + (func $dummy3904) + (func $dummy3905) + (func $dummy3906) + (func $dummy3907) + (func $dummy3908) + (func $dummy3909) + (func $dummy3910) + (func $dummy3911) + (func $dummy3912) + (func $dummy3913) + (func $dummy3914) + (func $dummy3915) + (func $dummy3916) + (func $dummy3917) + (func $dummy3918) + (func $dummy3919) + (func $dummy3920) + (func $dummy3921) + (func $dummy3922) + (func $dummy3923) + (func $dummy3924) + (func $dummy3925) + (func $dummy3926) + (func $dummy3927) + (func $dummy3928) + (func $dummy3929) + (func $dummy3930) + (func $dummy3931) + (func $dummy3932) + (func $dummy3933) + (func $dummy3934) + (func $dummy3935) + (func $dummy3936) + (func $dummy3937) + (func $dummy3938) + (func $dummy3939) + (func $dummy3940) + (func $dummy3941) + (func $dummy3942) + (func $dummy3943) + (func $dummy3944) + (func $dummy3945) + (func $dummy3946) + (func $dummy3947) + (func $dummy3948) + (func $dummy3949) + (func $dummy3950) + (func $dummy3951) + (func $dummy3952) + (func $dummy3953) + (func $dummy3954) + (func $dummy3955) + (func $dummy3956) + (func $dummy3957) + (func $dummy3958) + (func $dummy3959) + (func $dummy3960) + (func $dummy3961) + (func $dummy3962) + (func $dummy3963) + (func $dummy3964) + (func $dummy3965) + (func $dummy3966) + (func $dummy3967) + (func $dummy3968) + (func $dummy3969) + (func $dummy3970) + (func $dummy3971) + (func $dummy3972) + (func $dummy3973) + (func $dummy3974) + (func $dummy3975) + (func $dummy3976) + (func $dummy3977) + (func $dummy3978) + (func $dummy3979) + (func $dummy3980) + (func $dummy3981) + (func $dummy3982) + (func $dummy3983) + (func $dummy3984) + (func $dummy3985) + (func $dummy3986) + (func $dummy3987) + (func $dummy3988) + (func $dummy3989) + (func $dummy3990) + (func $dummy3991) + (func $dummy3992) + (func $dummy3993) + (func $dummy3994) + (func $dummy3995) + (func $dummy3996) + (func $dummy3997) + (func $dummy3998) + (func $dummy3999) + (func $dummy4000) + (func $dummy4001) + (func $dummy4002) + (func $dummy4003) + (func $dummy4004) + (func $dummy4005) + (func $dummy4006) + (func $dummy4007) + (func $dummy4008) + (func $dummy4009) + (func $dummy4010) + (func $dummy4011) + (func $dummy4012) + (func $dummy4013) + (func $dummy4014) + (func $dummy4015) + (func $dummy4016) + (func $dummy4017) + (func $dummy4018) + (func $dummy4019) + (func $dummy4020) + (func $dummy4021) + (func $dummy4022) + (func $dummy4023) + (func $dummy4024) + (func $dummy4025) + (func $dummy4026) + (func $dummy4027) + (func $dummy4028) + (func $dummy4029) + (func $dummy4030) + (func $dummy4031) + (func $dummy4032) + (func $dummy4033) + (func $dummy4034) + (func $dummy4035) + (func $dummy4036) + (func $dummy4037) + (func $dummy4038) + (func $dummy4039) + (func $dummy4040) + (func $dummy4041) + (func $dummy4042) + (func $dummy4043) + (func $dummy4044) + (func $dummy4045) + (func $dummy4046) + (func $dummy4047) + (func $dummy4048) + (func $dummy4049) + (func $dummy4050) + (func $dummy4051) + (func $dummy4052) + (func $dummy4053) + (func $dummy4054) + (func $dummy4055) + (func $dummy4056) + (func $dummy4057) + (func $dummy4058) + (func $dummy4059) + (func $dummy4060) + (func $dummy4061) + (func $dummy4062) + (func $dummy4063) + (func $dummy4064) + (func $dummy4065) + (func $dummy4066) + (func $dummy4067) + (func $dummy4068) + (func $dummy4069) + (func $dummy4070) + (func $dummy4071) + (func $dummy4072) + (func $dummy4073) + (func $dummy4074) + (func $dummy4075) + (func $dummy4076) + (func $dummy4077) + (func $dummy4078) + (func $dummy4079) + (func $dummy4080) + (func $dummy4081) + (func $dummy4082) + (func $dummy4083) + (func $dummy4084) + (func $dummy4085) + (func $dummy4086) + (func $dummy4087) + (func $dummy4088) + (func $dummy4089) + (func $dummy4090) + (func $dummy4091) + (func $dummy4092) + (func $dummy4093) + (func $dummy4094) + (func $dummy4095) + (func $dummy4096) + (func $dummy4097) + (func $dummy4098) + (func $dummy4099) + (func $dummy4100) + (func $dummy4101) + (func $dummy4102) + (func $dummy4103) + (func $dummy4104) + (func $dummy4105) + (func $dummy4106) + (func $dummy4107) + (func $dummy4108) + (func $dummy4109) + (func $dummy4110) + (func $dummy4111) + (func $dummy4112) + (func $dummy4113) + (func $dummy4114) + (func $dummy4115) + (func $dummy4116) + (func $dummy4117) + (func $dummy4118) + (func $dummy4119) + (func $dummy4120) + (func $dummy4121) + (func $dummy4122) + (func $dummy4123) + (func $dummy4124) + (func $dummy4125) + (func $dummy4126) + (func $dummy4127) + (func $dummy4128) + (func $dummy4129) + (func $dummy4130) + (func $dummy4131) + (func $dummy4132) + (func $dummy4133) + (func $dummy4134) + (func $dummy4135) + (func $dummy4136) + (func $dummy4137) + (func $dummy4138) + (func $dummy4139) + (func $dummy4140) + (func $dummy4141) + (func $dummy4142) + (func $dummy4143) + (func $dummy4144) + (func $dummy4145) + (func $dummy4146) + (func $dummy4147) + (func $dummy4148) + (func $dummy4149) + (func $dummy4150) + (func $dummy4151) + (func $dummy4152) + (func $dummy4153) + (func $dummy4154) + (func $dummy4155) + (func $dummy4156) + (func $dummy4157) + (func $dummy4158) + (func $dummy4159) + (func $dummy4160) + (func $dummy4161) + (func $dummy4162) + (func $dummy4163) + (func $dummy4164) + (func $dummy4165) + (func $dummy4166) + (func $dummy4167) + (func $dummy4168) + (func $dummy4169) + (func $dummy4170) + (func $dummy4171) + (func $dummy4172) + (func $dummy4173) + (func $dummy4174) + (func $dummy4175) + (func $dummy4176) + (func $dummy4177) + (func $dummy4178) + (func $dummy4179) + (func $dummy4180) + (func $dummy4181) + (func $dummy4182) + (func $dummy4183) + (func $dummy4184) + (func $dummy4185) + (func $dummy4186) + (func $dummy4187) + (func $dummy4188) + (func $dummy4189) + (func $dummy4190) + (func $dummy4191) + (func $dummy4192) + (func $dummy4193) + (func $dummy4194) + (func $dummy4195) + (func $dummy4196) + (func $dummy4197) + (func $dummy4198) + (func $dummy4199) + (func $dummy4200) + (func $dummy4201) + (func $dummy4202) + (func $dummy4203) + (func $dummy4204) + (func $dummy4205) + (func $dummy4206) + (func $dummy4207) + (func $dummy4208) + (func $dummy4209) + (func $dummy4210) + (func $dummy4211) + (func $dummy4212) + (func $dummy4213) + (func $dummy4214) + (func $dummy4215) + (func $dummy4216) + (func $dummy4217) + (func $dummy4218) + (func $dummy4219) + (func $dummy4220) + (func $dummy4221) + (func $dummy4222) + (func $dummy4223) + (func $dummy4224) + (func $dummy4225) + (func $dummy4226) + (func $dummy4227) + (func $dummy4228) + (func $dummy4229) + (func $dummy4230) + (func $dummy4231) + (func $dummy4232) + (func $dummy4233) + (func $dummy4234) + (func $dummy4235) + (func $dummy4236) + (func $dummy4237) + (func $dummy4238) + (func $dummy4239) + (func $dummy4240) + (func $dummy4241) + (func $dummy4242) + (func $dummy4243) + (func $dummy4244) + (func $dummy4245) + (func $dummy4246) + (func $dummy4247) + (func $dummy4248) + (func $dummy4249) + (func $dummy4250) + (func $dummy4251) + (func $dummy4252) + (func $dummy4253) + (func $dummy4254) + (func $dummy4255) + (func $dummy4256) + (func $dummy4257) + (func $dummy4258) + (func $dummy4259) + (func $dummy4260) + (func $dummy4261) + (func $dummy4262) + (func $dummy4263) + (func $dummy4264) + (func $dummy4265) + (func $dummy4266) + (func $dummy4267) + (func $dummy4268) + (func $dummy4269) + (func $dummy4270) + (func $dummy4271) + (func $dummy4272) + (func $dummy4273) + (func $dummy4274) + (func $dummy4275) + (func $dummy4276) + (func $dummy4277) + (func $dummy4278) + (func $dummy4279) + (func $dummy4280) + (func $dummy4281) + (func $dummy4282) + (func $dummy4283) + (func $dummy4284) + (func $dummy4285) + (func $dummy4286) + (func $dummy4287) + (func $dummy4288) + (func $dummy4289) + (func $dummy4290) + (func $dummy4291) + (func $dummy4292) + (func $dummy4293) + (func $dummy4294) + (func $dummy4295) + (func $dummy4296) + (func $dummy4297) + (func $dummy4298) + (func $dummy4299) + (func $dummy4300) + (func $dummy4301) + (func $dummy4302) + (func $dummy4303) + (func $dummy4304) + (func $dummy4305) + (func $dummy4306) + (func $dummy4307) + (func $dummy4308) + (func $dummy4309) + (func $dummy4310) + (func $dummy4311) + (func $dummy4312) + (func $dummy4313) + (func $dummy4314) + (func $dummy4315) + (func $dummy4316) + (func $dummy4317) + (func $dummy4318) + (func $dummy4319) + (func $dummy4320) + (func $dummy4321) + (func $dummy4322) + (func $dummy4323) + (func $dummy4324) + (func $dummy4325) + (func $dummy4326) + (func $dummy4327) + (func $dummy4328) + (func $dummy4329) + (func $dummy4330) + (func $dummy4331) + (func $dummy4332) + (func $dummy4333) + (func $dummy4334) + (func $dummy4335) + (func $dummy4336) + (func $dummy4337) + (func $dummy4338) + (func $dummy4339) + (func $dummy4340) + (func $dummy4341) + (func $dummy4342) + (func $dummy4343) + (func $dummy4344) + (func $dummy4345) + (func $dummy4346) + (func $dummy4347) + (func $dummy4348) + (func $dummy4349) + (func $dummy4350) + (func $dummy4351) + (func $dummy4352) + (func $dummy4353) + (func $dummy4354) + (func $dummy4355) + (func $dummy4356) + (func $dummy4357) + (func $dummy4358) + (func $dummy4359) + (func $dummy4360) + (func $dummy4361) + (func $dummy4362) + (func $dummy4363) + (func $dummy4364) + (func $dummy4365) + (func $dummy4366) + (func $dummy4367) + (func $dummy4368) + (func $dummy4369) + (func $dummy4370) + (func $dummy4371) + (func $dummy4372) + (func $dummy4373) + (func $dummy4374) + (func $dummy4375) + (func $dummy4376) + (func $dummy4377) + (func $dummy4378) + (func $dummy4379) + (func $dummy4380) + (func $dummy4381) + (func $dummy4382) + (func $dummy4383) + (func $dummy4384) + (func $dummy4385) + (func $dummy4386) + (func $dummy4387) + (func $dummy4388) + (func $dummy4389) + (func $dummy4390) + (func $dummy4391) + (func $dummy4392) + (func $dummy4393) + (func $dummy4394) + (func $dummy4395) + (func $dummy4396) + (func $dummy4397) + (func $dummy4398) + (func $dummy4399) + (func $dummy4400) + (func $dummy4401) + (func $dummy4402) + (func $dummy4403) + (func $dummy4404) + (func $dummy4405) + (func $dummy4406) + (func $dummy4407) + (func $dummy4408) + (func $dummy4409) + (func $dummy4410) + (func $dummy4411) + (func $dummy4412) + (func $dummy4413) + (func $dummy4414) + (func $dummy4415) + (func $dummy4416) + (func $dummy4417) + (func $dummy4418) + (func $dummy4419) + (func $dummy4420) + (func $dummy4421) + (func $dummy4422) + (func $dummy4423) + (func $dummy4424) + (func $dummy4425) + (func $dummy4426) + (func $dummy4427) + (func $dummy4428) + (func $dummy4429) + (func $dummy4430) + (func $dummy4431) + (func $dummy4432) + (func $dummy4433) + (func $dummy4434) + (func $dummy4435) + (func $dummy4436) + (func $dummy4437) + (func $dummy4438) + (func $dummy4439) + (func $dummy4440) + (func $dummy4441) + (func $dummy4442) + (func $dummy4443) + (func $dummy4444) + (func $dummy4445) + (func $dummy4446) + (func $dummy4447) + (func $dummy4448) + (func $dummy4449) + (func $dummy4450) + (func $dummy4451) + (func $dummy4452) + (func $dummy4453) + (func $dummy4454) + (func $dummy4455) + (func $dummy4456) + (func $dummy4457) + (func $dummy4458) + (func $dummy4459) + (func $dummy4460) + (func $dummy4461) + (func $dummy4462) + (func $dummy4463) + (func $dummy4464) + (func $dummy4465) + (func $dummy4466) + (func $dummy4467) + (func $dummy4468) + (func $dummy4469) + (func $dummy4470) + (func $dummy4471) + (func $dummy4472) + (func $dummy4473) + (func $dummy4474) + (func $dummy4475) + (func $dummy4476) + (func $dummy4477) + (func $dummy4478) + (func $dummy4479) + (func $dummy4480) + (func $dummy4481) + (func $dummy4482) + (func $dummy4483) + (func $dummy4484) + (func $dummy4485) + (func $dummy4486) + (func $dummy4487) + (func $dummy4488) + (func $dummy4489) + (func $dummy4490) + (func $dummy4491) + (func $dummy4492) + (func $dummy4493) + (func $dummy4494) + (func $dummy4495) + (func $dummy4496) + (func $dummy4497) + (func $dummy4498) + (func $dummy4499) + (func $dummy4500) + (func $dummy4501) + (func $dummy4502) + (func $dummy4503) + (func $dummy4504) + (func $dummy4505) + (func $dummy4506) + (func $dummy4507) + (func $dummy4508) + (func $dummy4509) + (func $dummy4510) + (func $dummy4511) + (func $dummy4512) + (func $dummy4513) + (func $dummy4514) + (func $dummy4515) + (func $dummy4516) + (func $dummy4517) + (func $dummy4518) + (func $dummy4519) + (func $dummy4520) + (func $dummy4521) + (func $dummy4522) + (func $dummy4523) + (func $dummy4524) + (func $dummy4525) + (func $dummy4526) + (func $dummy4527) + (func $dummy4528) + (func $dummy4529) + (func $dummy4530) + (func $dummy4531) + (func $dummy4532) + (func $dummy4533) + (func $dummy4534) + (func $dummy4535) + (func $dummy4536) + (func $dummy4537) + (func $dummy4538) + (func $dummy4539) + (func $dummy4540) + (func $dummy4541) + (func $dummy4542) + (func $dummy4543) + (func $dummy4544) + (func $dummy4545) + (func $dummy4546) + (func $dummy4547) + (func $dummy4548) + (func $dummy4549) + (func $dummy4550) + (func $dummy4551) + (func $dummy4552) + (func $dummy4553) + (func $dummy4554) + (func $dummy4555) + (func $dummy4556) + (func $dummy4557) + (func $dummy4558) + (func $dummy4559) + (func $dummy4560) + (func $dummy4561) + (func $dummy4562) + (func $dummy4563) + (func $dummy4564) + (func $dummy4565) + (func $dummy4566) + (func $dummy4567) + (func $dummy4568) + (func $dummy4569) + (func $dummy4570) + (func $dummy4571) + (func $dummy4572) + (func $dummy4573) + (func $dummy4574) + (func $dummy4575) + (func $dummy4576) + (func $dummy4577) + (func $dummy4578) + (func $dummy4579) + (func $dummy4580) + (func $dummy4581) + (func $dummy4582) + (func $dummy4583) + (func $dummy4584) + (func $dummy4585) + (func $dummy4586) + (func $dummy4587) + (func $dummy4588) + (func $dummy4589) + (func $dummy4590) + (func $dummy4591) + (func $dummy4592) + (func $dummy4593) + (func $dummy4594) + (func $dummy4595) + (func $dummy4596) + (func $dummy4597) + (func $dummy4598) + (func $dummy4599) + (func $dummy4600) + (func $dummy4601) + (func $dummy4602) + (func $dummy4603) + (func $dummy4604) + (func $dummy4605) + (func $dummy4606) + (func $dummy4607) + (func $dummy4608) + (func $dummy4609) + (func $dummy4610) + (func $dummy4611) + (func $dummy4612) + (func $dummy4613) + (func $dummy4614) + (func $dummy4615) + (func $dummy4616) + (func $dummy4617) + (func $dummy4618) + (func $dummy4619) + (func $dummy4620) + (func $dummy4621) + (func $dummy4622) + (func $dummy4623) + (func $dummy4624) + (func $dummy4625) + (func $dummy4626) + (func $dummy4627) + (func $dummy4628) + (func $dummy4629) + (func $dummy4630) + (func $dummy4631) + (func $dummy4632) + (func $dummy4633) + (func $dummy4634) + (func $dummy4635) + (func $dummy4636) + (func $dummy4637) + (func $dummy4638) + (func $dummy4639) + (func $dummy4640) + (func $dummy4641) + (func $dummy4642) + (func $dummy4643) + (func $dummy4644) + (func $dummy4645) + (func $dummy4646) + (func $dummy4647) + (func $dummy4648) + (func $dummy4649) + (func $dummy4650) + (func $dummy4651) + (func $dummy4652) + (func $dummy4653) + (func $dummy4654) + (func $dummy4655) + (func $dummy4656) + (func $dummy4657) + (func $dummy4658) + (func $dummy4659) + (func $dummy4660) + (func $dummy4661) + (func $dummy4662) + (func $dummy4663) + (func $dummy4664) + (func $dummy4665) + (func $dummy4666) + (func $dummy4667) + (func $dummy4668) + (func $dummy4669) + (func $dummy4670) + (func $dummy4671) + (func $dummy4672) + (func $dummy4673) + (func $dummy4674) + (func $dummy4675) + (func $dummy4676) + (func $dummy4677) + (func $dummy4678) + (func $dummy4679) + (func $dummy4680) + (func $dummy4681) + (func $dummy4682) + (func $dummy4683) + (func $dummy4684) + (func $dummy4685) + (func $dummy4686) + (func $dummy4687) + (func $dummy4688) + (func $dummy4689) + (func $dummy4690) + (func $dummy4691) + (func $dummy4692) + (func $dummy4693) + (func $dummy4694) + (func $dummy4695) + (func $dummy4696) + (func $dummy4697) + (func $dummy4698) + (func $dummy4699) + (func $dummy4700) + (func $dummy4701) + (func $dummy4702) + (func $dummy4703) + (func $dummy4704) + (func $dummy4705) + (func $dummy4706) + (func $dummy4707) + (func $dummy4708) + (func $dummy4709) + (func $dummy4710) + (func $dummy4711) + (func $dummy4712) + (func $dummy4713) + (func $dummy4714) + (func $dummy4715) + (func $dummy4716) + (func $dummy4717) + (func $dummy4718) + (func $dummy4719) + (func $dummy4720) + (func $dummy4721) + (func $dummy4722) + (func $dummy4723) + (func $dummy4724) + (func $dummy4725) + (func $dummy4726) + (func $dummy4727) + (func $dummy4728) + (func $dummy4729) + (func $dummy4730) + (func $dummy4731) + (func $dummy4732) + (func $dummy4733) + (func $dummy4734) + (func $dummy4735) + (func $dummy4736) + (func $dummy4737) + (func $dummy4738) + (func $dummy4739) + (func $dummy4740) + (func $dummy4741) + (func $dummy4742) + (func $dummy4743) + (func $dummy4744) + (func $dummy4745) + (func $dummy4746) + (func $dummy4747) + (func $dummy4748) + (func $dummy4749) + (func $dummy4750) + (func $dummy4751) + (func $dummy4752) + (func $dummy4753) + (func $dummy4754) + (func $dummy4755) + (func $dummy4756) + (func $dummy4757) + (func $dummy4758) + (func $dummy4759) + (func $dummy4760) + (func $dummy4761) + (func $dummy4762) + (func $dummy4763) + (func $dummy4764) + (func $dummy4765) + (func $dummy4766) + (func $dummy4767) + (func $dummy4768) + (func $dummy4769) + (func $dummy4770) + (func $dummy4771) + (func $dummy4772) + (func $dummy4773) + (func $dummy4774) + (func $dummy4775) + (func $dummy4776) + (func $dummy4777) + (func $dummy4778) + (func $dummy4779) + (func $dummy4780) + (func $dummy4781) + (func $dummy4782) + (func $dummy4783) + (func $dummy4784) + (func $dummy4785) + (func $dummy4786) + (func $dummy4787) + (func $dummy4788) + (func $dummy4789) + (func $dummy4790) + (func $dummy4791) + (func $dummy4792) + (func $dummy4793) + (func $dummy4794) + (func $dummy4795) + (func $dummy4796) + (func $dummy4797) + (func $dummy4798) + (func $dummy4799) + (func $dummy4800) + (func $dummy4801) + (func $dummy4802) + (func $dummy4803) + (func $dummy4804) + (func $dummy4805) + (func $dummy4806) + (func $dummy4807) + (func $dummy4808) + (func $dummy4809) + (func $dummy4810) + (func $dummy4811) + (func $dummy4812) + (func $dummy4813) + (func $dummy4814) + (func $dummy4815) + (func $dummy4816) + (func $dummy4817) + (func $dummy4818) + (func $dummy4819) + (func $dummy4820) + (func $dummy4821) + (func $dummy4822) + (func $dummy4823) + (func $dummy4824) + (func $dummy4825) + (func $dummy4826) + (func $dummy4827) + (func $dummy4828) + (func $dummy4829) + (func $dummy4830) + (func $dummy4831) + (func $dummy4832) + (func $dummy4833) + (func $dummy4834) + (func $dummy4835) + (func $dummy4836) + (func $dummy4837) + (func $dummy4838) + (func $dummy4839) + (func $dummy4840) + (func $dummy4841) + (func $dummy4842) + (func $dummy4843) + (func $dummy4844) + (func $dummy4845) + (func $dummy4846) + (func $dummy4847) + (func $dummy4848) + (func $dummy4849) + (func $dummy4850) + (func $dummy4851) + (func $dummy4852) + (func $dummy4853) + (func $dummy4854) + (func $dummy4855) + (func $dummy4856) + (func $dummy4857) + (func $dummy4858) + (func $dummy4859) + (func $dummy4860) + (func $dummy4861) + (func $dummy4862) + (func $dummy4863) + (func $dummy4864) + (func $dummy4865) + (func $dummy4866) + (func $dummy4867) + (func $dummy4868) + (func $dummy4869) + (func $dummy4870) + (func $dummy4871) + (func $dummy4872) + (func $dummy4873) + (func $dummy4874) + (func $dummy4875) + (func $dummy4876) + (func $dummy4877) + (func $dummy4878) + (func $dummy4879) + (func $dummy4880) + (func $dummy4881) + (func $dummy4882) + (func $dummy4883) + (func $dummy4884) + (func $dummy4885) + (func $dummy4886) + (func $dummy4887) + (func $dummy4888) + (func $dummy4889) + (func $dummy4890) + (func $dummy4891) + (func $dummy4892) + (func $dummy4893) + (func $dummy4894) + (func $dummy4895) + (func $dummy4896) + (func $dummy4897) + (func $dummy4898) + (func $dummy4899) + (func $dummy4900) + (func $dummy4901) + (func $dummy4902) + (func $dummy4903) + (func $dummy4904) + (func $dummy4905) + (func $dummy4906) + (func $dummy4907) + (func $dummy4908) + (func $dummy4909) + (func $dummy4910) + (func $dummy4911) + (func $dummy4912) + (func $dummy4913) + (func $dummy4914) + (func $dummy4915) + (func $dummy4916) + (func $dummy4917) + (func $dummy4918) + (func $dummy4919) + (func $dummy4920) + (func $dummy4921) + (func $dummy4922) + (func $dummy4923) + (func $dummy4924) + (func $dummy4925) + (func $dummy4926) + (func $dummy4927) + (func $dummy4928) + (func $dummy4929) + (func $dummy4930) + (func $dummy4931) + (func $dummy4932) + (func $dummy4933) + (func $dummy4934) + (func $dummy4935) + (func $dummy4936) + (func $dummy4937) + (func $dummy4938) + (func $dummy4939) + (func $dummy4940) + (func $dummy4941) + (func $dummy4942) + (func $dummy4943) + (func $dummy4944) + (func $dummy4945) + (func $dummy4946) + (func $dummy4947) + (func $dummy4948) + (func $dummy4949) + (func $dummy4950) + (func $dummy4951) + (func $dummy4952) + (func $dummy4953) + (func $dummy4954) + (func $dummy4955) + (func $dummy4956) + (func $dummy4957) + (func $dummy4958) + (func $dummy4959) + (func $dummy4960) + (func $dummy4961) + (func $dummy4962) + (func $dummy4963) + (func $dummy4964) + (func $dummy4965) + (func $dummy4966) + (func $dummy4967) + (func $dummy4968) + (func $dummy4969) + (func $dummy4970) + (func $dummy4971) + (func $dummy4972) + (func $dummy4973) + (func $dummy4974) + (func $dummy4975) + (func $dummy4976) + (func $dummy4977) + (func $dummy4978) + (func $dummy4979) + (func $dummy4980) + (func $dummy4981) + (func $dummy4982) + (func $dummy4983) + (func $dummy4984) + (func $dummy4985) + (func $dummy4986) + (func $dummy4987) + (func $dummy4988) + (func $dummy4989) + (func $dummy4990) + (func $dummy4991) + (func $dummy4992) + (func $dummy4993) + (func $dummy4994) + (func $dummy4995) + (func $dummy4996) + (func $dummy4997) + (func $dummy4998) + (func $dummy4999) + (func $dummy5000) + (func $dummy5001) + (func $dummy5002) + (func $dummy5003) + (func $dummy5004) + (func $dummy5005) + (func $dummy5006) + (func $dummy5007) + (func $dummy5008) + (func $dummy5009) + (func $dummy5010) + (func $dummy5011) + (func $dummy5012) + (func $dummy5013) + (func $dummy5014) + (func $dummy5015) + (func $dummy5016) + (func $dummy5017) + (func $dummy5018) + (func $dummy5019) + (func $dummy5020) + (func $dummy5021) + (func $dummy5022) + (func $dummy5023) + (func $dummy5024) + (func $dummy5025) + (func $dummy5026) + (func $dummy5027) + (func $dummy5028) + (func $dummy5029) + (func $dummy5030) + (func $dummy5031) + (func $dummy5032) + (func $dummy5033) + (func $dummy5034) + (func $dummy5035) + (func $dummy5036) + (func $dummy5037) + (func $dummy5038) + (func $dummy5039) + (func $dummy5040) + (func $dummy5041) + (func $dummy5042) + (func $dummy5043) + (func $dummy5044) + (func $dummy5045) + (func $dummy5046) + (func $dummy5047) + (func $dummy5048) + (func $dummy5049) + (func $dummy5050) + (func $dummy5051) + (func $dummy5052) + (func $dummy5053) + (func $dummy5054) + (func $dummy5055) + (func $dummy5056) + (func $dummy5057) + (func $dummy5058) + (func $dummy5059) + (func $dummy5060) + (func $dummy5061) + (func $dummy5062) + (func $dummy5063) + (func $dummy5064) + (func $dummy5065) + (func $dummy5066) + (func $dummy5067) + (func $dummy5068) + (func $dummy5069) + (func $dummy5070) + (func $dummy5071) + (func $dummy5072) + (func $dummy5073) + (func $dummy5074) + (func $dummy5075) + (func $dummy5076) + (func $dummy5077) + (func $dummy5078) + (func $dummy5079) + (func $dummy5080) + (func $dummy5081) + (func $dummy5082) + (func $dummy5083) + (func $dummy5084) + (func $dummy5085) + (func $dummy5086) + (func $dummy5087) + (func $dummy5088) + (func $dummy5089) + (func $dummy5090) + (func $dummy5091) + (func $dummy5092) + (func $dummy5093) + (func $dummy5094) + (func $dummy5095) + (func $dummy5096) + (func $dummy5097) + (func $dummy5098) + (func $dummy5099) + (func $dummy5100) + (func $dummy5101) + (func $dummy5102) + (func $dummy5103) + (func $dummy5104) + (func $dummy5105) + (func $dummy5106) + (func $dummy5107) + (func $dummy5108) + (func $dummy5109) + (func $dummy5110) + (func $dummy5111) + (func $dummy5112) + (func $dummy5113) + (func $dummy5114) + (func $dummy5115) + (func $dummy5116) + (func $dummy5117) + (func $dummy5118) + (func $dummy5119) + (func $dummy5120) + (func $dummy5121) + (func $dummy5122) + (func $dummy5123) + (func $dummy5124) + (func $dummy5125) + (func $dummy5126) + (func $dummy5127) + (func $dummy5128) + (func $dummy5129) + (func $dummy5130) + (func $dummy5131) + (func $dummy5132) + (func $dummy5133) + (func $dummy5134) + (func $dummy5135) + (func $dummy5136) + (func $dummy5137) + (func $dummy5138) + (func $dummy5139) + (func $dummy5140) + (func $dummy5141) + (func $dummy5142) + (func $dummy5143) + (func $dummy5144) + (func $dummy5145) + (func $dummy5146) + (func $dummy5147) + (func $dummy5148) + (func $dummy5149) + (func $dummy5150) + (func $dummy5151) + (func $dummy5152) + (func $dummy5153) + (func $dummy5154) + (func $dummy5155) + (func $dummy5156) + (func $dummy5157) + (func $dummy5158) + (func $dummy5159) + (func $dummy5160) + (func $dummy5161) + (func $dummy5162) + (func $dummy5163) + (func $dummy5164) + (func $dummy5165) + (func $dummy5166) + (func $dummy5167) + (func $dummy5168) + (func $dummy5169) + (func $dummy5170) + (func $dummy5171) + (func $dummy5172) + (func $dummy5173) + (func $dummy5174) + (func $dummy5175) + (func $dummy5176) + (func $dummy5177) + (func $dummy5178) + (func $dummy5179) + (func $dummy5180) + (func $dummy5181) + (func $dummy5182) + (func $dummy5183) + (func $dummy5184) + (func $dummy5185) + (func $dummy5186) + (func $dummy5187) + (func $dummy5188) + (func $dummy5189) + (func $dummy5190) + (func $dummy5191) + (func $dummy5192) + (func $dummy5193) + (func $dummy5194) + (func $dummy5195) + (func $dummy5196) + (func $dummy5197) + (func $dummy5198) + (func $dummy5199) + (func $dummy5200) + (func $dummy5201) + (func $dummy5202) + (func $dummy5203) + (func $dummy5204) + (func $dummy5205) + (func $dummy5206) + (func $dummy5207) + (func $dummy5208) + (func $dummy5209) + (func $dummy5210) + (func $dummy5211) + (func $dummy5212) + (func $dummy5213) + (func $dummy5214) + (func $dummy5215) + (func $dummy5216) + (func $dummy5217) + (func $dummy5218) + (func $dummy5219) + (func $dummy5220) + (func $dummy5221) + (func $dummy5222) + (func $dummy5223) + (func $dummy5224) + (func $dummy5225) + (func $dummy5226) + (func $dummy5227) + (func $dummy5228) + (func $dummy5229) + (func $dummy5230) + (func $dummy5231) + (func $dummy5232) + (func $dummy5233) + (func $dummy5234) + (func $dummy5235) + (func $dummy5236) + (func $dummy5237) + (func $dummy5238) + (func $dummy5239) + (func $dummy5240) + (func $dummy5241) + (func $dummy5242) + (func $dummy5243) + (func $dummy5244) + (func $dummy5245) + (func $dummy5246) + (func $dummy5247) + (func $dummy5248) + (func $dummy5249) + (func $dummy5250) + (func $dummy5251) + (func $dummy5252) + (func $dummy5253) + (func $dummy5254) + (func $dummy5255) + (func $dummy5256) + (func $dummy5257) + (func $dummy5258) + (func $dummy5259) + (func $dummy5260) + (func $dummy5261) + (func $dummy5262) + (func $dummy5263) + (func $dummy5264) + (func $dummy5265) + (func $dummy5266) + (func $dummy5267) + (func $dummy5268) + (func $dummy5269) + (func $dummy5270) + (func $dummy5271) + (func $dummy5272) + (func $dummy5273) + (func $dummy5274) + (func $dummy5275) + (func $dummy5276) + (func $dummy5277) + (func $dummy5278) + (func $dummy5279) + (func $dummy5280) + (func $dummy5281) + (func $dummy5282) + (func $dummy5283) + (func $dummy5284) + (func $dummy5285) + (func $dummy5286) + (func $dummy5287) + (func $dummy5288) + (func $dummy5289) + (func $dummy5290) + (func $dummy5291) + (func $dummy5292) + (func $dummy5293) + (func $dummy5294) + (func $dummy5295) + (func $dummy5296) + (func $dummy5297) + (func $dummy5298) + (func $dummy5299) + (func $dummy5300) + (func $dummy5301) + (func $dummy5302) + (func $dummy5303) + (func $dummy5304) + (func $dummy5305) + (func $dummy5306) + (func $dummy5307) + (func $dummy5308) + (func $dummy5309) + (func $dummy5310) + (func $dummy5311) + (func $dummy5312) + (func $dummy5313) + (func $dummy5314) + (func $dummy5315) + (func $dummy5316) + (func $dummy5317) + (func $dummy5318) + (func $dummy5319) + (func $dummy5320) + (func $dummy5321) + (func $dummy5322) + (func $dummy5323) + (func $dummy5324) + (func $dummy5325) + (func $dummy5326) + (func $dummy5327) + (func $dummy5328) + (func $dummy5329) + (func $dummy5330) + (func $dummy5331) + (func $dummy5332) + (func $dummy5333) + (func $dummy5334) + (func $dummy5335) + (func $dummy5336) + (func $dummy5337) + (func $dummy5338) + (func $dummy5339) + (func $dummy5340) + (func $dummy5341) + (func $dummy5342) + (func $dummy5343) + (func $dummy5344) + (func $dummy5345) + (func $dummy5346) + (func $dummy5347) + (func $dummy5348) + (func $dummy5349) + (func $dummy5350) + (func $dummy5351) + (func $dummy5352) + (func $dummy5353) + (func $dummy5354) + (func $dummy5355) + (func $dummy5356) + (func $dummy5357) + (func $dummy5358) + (func $dummy5359) + (func $dummy5360) + (func $dummy5361) + (func $dummy5362) + (func $dummy5363) + (func $dummy5364) + (func $dummy5365) + (func $dummy5366) + (func $dummy5367) + (func $dummy5368) + (func $dummy5369) + (func $dummy5370) + (func $dummy5371) + (func $dummy5372) + (func $dummy5373) + (func $dummy5374) + (func $dummy5375) + (func $dummy5376) + (func $dummy5377) + (func $dummy5378) + (func $dummy5379) + (func $dummy5380) + (func $dummy5381) + (func $dummy5382) + (func $dummy5383) + (func $dummy5384) + (func $dummy5385) + (func $dummy5386) + (func $dummy5387) + (func $dummy5388) + (func $dummy5389) + (func $dummy5390) + (func $dummy5391) + (func $dummy5392) + (func $dummy5393) + (func $dummy5394) + (func $dummy5395) + (func $dummy5396) + (func $dummy5397) + (func $dummy5398) + (func $dummy5399) + (func $dummy5400) + (func $dummy5401) + (func $dummy5402) + (func $dummy5403) + (func $dummy5404) + (func $dummy5405) + (func $dummy5406) + (func $dummy5407) + (func $dummy5408) + (func $dummy5409) + (func $dummy5410) + (func $dummy5411) + (func $dummy5412) + (func $dummy5413) + (func $dummy5414) + (func $dummy5415) + (func $dummy5416) + (func $dummy5417) + (func $dummy5418) + (func $dummy5419) + (func $dummy5420) + (func $dummy5421) + (func $dummy5422) + (func $dummy5423) + (func $dummy5424) + (func $dummy5425) + (func $dummy5426) + (func $dummy5427) + (func $dummy5428) + (func $dummy5429) + (func $dummy5430) + (func $dummy5431) + (func $dummy5432) + (func $dummy5433) + (func $dummy5434) + (func $dummy5435) + (func $dummy5436) + (func $dummy5437) + (func $dummy5438) + (func $dummy5439) + (func $dummy5440) + (func $dummy5441) + (func $dummy5442) + (func $dummy5443) + (func $dummy5444) + (func $dummy5445) + (func $dummy5446) + (func $dummy5447) + (func $dummy5448) + (func $dummy5449) + (func $dummy5450) + (func $dummy5451) + (func $dummy5452) + (func $dummy5453) + (func $dummy5454) + (func $dummy5455) + (func $dummy5456) + (func $dummy5457) + (func $dummy5458) + (func $dummy5459) + (func $dummy5460) + (func $dummy5461) + (func $dummy5462) + (func $dummy5463) + (func $dummy5464) + (func $dummy5465) + (func $dummy5466) + (func $dummy5467) + (func $dummy5468) + (func $dummy5469) + (func $dummy5470) + (func $dummy5471) + (func $dummy5472) + (func $dummy5473) + (func $dummy5474) + (func $dummy5475) + (func $dummy5476) + (func $dummy5477) + (func $dummy5478) + (func $dummy5479) + (func $dummy5480) + (func $dummy5481) + (func $dummy5482) + (func $dummy5483) + (func $dummy5484) + (func $dummy5485) + (func $dummy5486) + (func $dummy5487) + (func $dummy5488) + (func $dummy5489) + (func $dummy5490) + (func $dummy5491) + (func $dummy5492) + (func $dummy5493) + (func $dummy5494) + (func $dummy5495) + (func $dummy5496) + (func $dummy5497) + (func $dummy5498) + (func $dummy5499) + (func $dummy5500) + (func $dummy5501) + (func $dummy5502) + (func $dummy5503) + (func $dummy5504) + (func $dummy5505) + (func $dummy5506) + (func $dummy5507) + (func $dummy5508) + (func $dummy5509) + (func $dummy5510) + (func $dummy5511) + (func $dummy5512) + (func $dummy5513) + (func $dummy5514) + (func $dummy5515) + (func $dummy5516) + (func $dummy5517) + (func $dummy5518) + (func $dummy5519) + (func $dummy5520) + (func $dummy5521) + (func $dummy5522) + (func $dummy5523) + (func $dummy5524) + (func $dummy5525) + (func $dummy5526) + (func $dummy5527) + (func $dummy5528) + (func $dummy5529) + (func $dummy5530) + (func $dummy5531) + (func $dummy5532) + (func $dummy5533) + (func $dummy5534) + (func $dummy5535) + (func $dummy5536) + (func $dummy5537) + (func $dummy5538) + (func $dummy5539) + (func $dummy5540) + (func $dummy5541) + (func $dummy5542) + (func $dummy5543) + (func $dummy5544) + (func $dummy5545) + (func $dummy5546) + (func $dummy5547) + (func $dummy5548) + (func $dummy5549) + (func $dummy5550) + (func $dummy5551) + (func $dummy5552) + (func $dummy5553) + (func $dummy5554) + (func $dummy5555) + (func $dummy5556) + (func $dummy5557) + (func $dummy5558) + (func $dummy5559) + (func $dummy5560) + (func $dummy5561) + (func $dummy5562) + (func $dummy5563) + (func $dummy5564) + (func $dummy5565) + (func $dummy5566) + (func $dummy5567) + (func $dummy5568) + (func $dummy5569) + (func $dummy5570) + (func $dummy5571) + (func $dummy5572) + (func $dummy5573) + (func $dummy5574) + (func $dummy5575) + (func $dummy5576) + (func $dummy5577) + (func $dummy5578) + (func $dummy5579) + (func $dummy5580) + (func $dummy5581) + (func $dummy5582) + (func $dummy5583) + (func $dummy5584) + (func $dummy5585) + (func $dummy5586) + (func $dummy5587) + (func $dummy5588) + (func $dummy5589) + (func $dummy5590) + (func $dummy5591) + (func $dummy5592) + (func $dummy5593) + (func $dummy5594) + (func $dummy5595) + (func $dummy5596) + (func $dummy5597) + (func $dummy5598) + (func $dummy5599) + (func $dummy5600) + (func $dummy5601) + (func $dummy5602) + (func $dummy5603) + (func $dummy5604) + (func $dummy5605) + (func $dummy5606) + (func $dummy5607) + (func $dummy5608) + (func $dummy5609) + (func $dummy5610) + (func $dummy5611) + (func $dummy5612) + (func $dummy5613) + (func $dummy5614) + (func $dummy5615) + (func $dummy5616) + (func $dummy5617) + (func $dummy5618) + (func $dummy5619) + (func $dummy5620) + (func $dummy5621) + (func $dummy5622) + (func $dummy5623) + (func $dummy5624) + (func $dummy5625) + (func $dummy5626) + (func $dummy5627) + (func $dummy5628) + (func $dummy5629) + (func $dummy5630) + (func $dummy5631) + (func $dummy5632) + (func $dummy5633) + (func $dummy5634) + (func $dummy5635) + (func $dummy5636) + (func $dummy5637) + (func $dummy5638) + (func $dummy5639) + (func $dummy5640) + (func $dummy5641) + (func $dummy5642) + (func $dummy5643) + (func $dummy5644) + (func $dummy5645) + (func $dummy5646) + (func $dummy5647) + (func $dummy5648) + (func $dummy5649) + (func $dummy5650) + (func $dummy5651) + (func $dummy5652) + (func $dummy5653) + (func $dummy5654) + (func $dummy5655) + (func $dummy5656) + (func $dummy5657) + (func $dummy5658) + (func $dummy5659) + (func $dummy5660) + (func $dummy5661) + (func $dummy5662) + (func $dummy5663) + (func $dummy5664) + (func $dummy5665) + (func $dummy5666) + (func $dummy5667) + (func $dummy5668) + (func $dummy5669) + (func $dummy5670) + (func $dummy5671) + (func $dummy5672) + (func $dummy5673) + (func $dummy5674) + (func $dummy5675) + (func $dummy5676) + (func $dummy5677) + (func $dummy5678) + (func $dummy5679) + (func $dummy5680) + (func $dummy5681) + (func $dummy5682) + (func $dummy5683) + (func $dummy5684) + (func $dummy5685) + (func $dummy5686) + (func $dummy5687) + (func $dummy5688) + (func $dummy5689) + (func $dummy5690) + (func $dummy5691) + (func $dummy5692) + (func $dummy5693) + (func $dummy5694) + (func $dummy5695) + (func $dummy5696) + (func $dummy5697) + (func $dummy5698) + (func $dummy5699) + (func $dummy5700) + (func $dummy5701) + (func $dummy5702) + (func $dummy5703) + (func $dummy5704) + (func $dummy5705) + (func $dummy5706) + (func $dummy5707) + (func $dummy5708) + (func $dummy5709) + (func $dummy5710) + (func $dummy5711) + (func $dummy5712) + (func $dummy5713) + (func $dummy5714) + (func $dummy5715) + (func $dummy5716) + (func $dummy5717) + (func $dummy5718) + (func $dummy5719) + (func $dummy5720) + (func $dummy5721) + (func $dummy5722) + (func $dummy5723) + (func $dummy5724) + (func $dummy5725) + (func $dummy5726) + (func $dummy5727) + (func $dummy5728) + (func $dummy5729) + (func $dummy5730) + (func $dummy5731) + (func $dummy5732) + (func $dummy5733) + (func $dummy5734) + (func $dummy5735) + (func $dummy5736) + (func $dummy5737) + (func $dummy5738) + (func $dummy5739) + (func $dummy5740) + (func $dummy5741) + (func $dummy5742) + (func $dummy5743) + (func $dummy5744) + (func $dummy5745) + (func $dummy5746) + (func $dummy5747) + (func $dummy5748) + (func $dummy5749) + (func $dummy5750) + (func $dummy5751) + (func $dummy5752) + (func $dummy5753) + (func $dummy5754) + (func $dummy5755) + (func $dummy5756) + (func $dummy5757) + (func $dummy5758) + (func $dummy5759) + (func $dummy5760) + (func $dummy5761) + (func $dummy5762) + (func $dummy5763) + (func $dummy5764) + (func $dummy5765) + (func $dummy5766) + (func $dummy5767) + (func $dummy5768) + (func $dummy5769) + (func $dummy5770) + (func $dummy5771) + (func $dummy5772) + (func $dummy5773) + (func $dummy5774) + (func $dummy5775) + (func $dummy5776) + (func $dummy5777) + (func $dummy5778) + (func $dummy5779) + (func $dummy5780) + (func $dummy5781) + (func $dummy5782) + (func $dummy5783) + (func $dummy5784) + (func $dummy5785) + (func $dummy5786) + (func $dummy5787) + (func $dummy5788) + (func $dummy5789) + (func $dummy5790) + (func $dummy5791) + (func $dummy5792) + (func $dummy5793) + (func $dummy5794) + (func $dummy5795) + (func $dummy5796) + (func $dummy5797) + (func $dummy5798) + (func $dummy5799) + (func $dummy5800) + (func $dummy5801) + (func $dummy5802) + (func $dummy5803) + (func $dummy5804) + (func $dummy5805) + (func $dummy5806) + (func $dummy5807) + (func $dummy5808) + (func $dummy5809) + (func $dummy5810) + (func $dummy5811) + (func $dummy5812) + (func $dummy5813) + (func $dummy5814) + (func $dummy5815) + (func $dummy5816) + (func $dummy5817) + (func $dummy5818) + (func $dummy5819) + (func $dummy5820) + (func $dummy5821) + (func $dummy5822) + (func $dummy5823) + (func $dummy5824) + (func $dummy5825) + (func $dummy5826) + (func $dummy5827) + (func $dummy5828) + (func $dummy5829) + (func $dummy5830) + (func $dummy5831) + (func $dummy5832) + (func $dummy5833) + (func $dummy5834) + (func $dummy5835) + (func $dummy5836) + (func $dummy5837) + (func $dummy5838) + (func $dummy5839) + (func $dummy5840) + (func $dummy5841) + (func $dummy5842) + (func $dummy5843) + (func $dummy5844) + (func $dummy5845) + (func $dummy5846) + (func $dummy5847) + (func $dummy5848) + (func $dummy5849) + (func $dummy5850) + (func $dummy5851) + (func $dummy5852) + (func $dummy5853) + (func $dummy5854) + (func $dummy5855) + (func $dummy5856) + (func $dummy5857) + (func $dummy5858) + (func $dummy5859) + (func $dummy5860) + (func $dummy5861) + (func $dummy5862) + (func $dummy5863) + (func $dummy5864) + (func $dummy5865) + (func $dummy5866) + (func $dummy5867) + (func $dummy5868) + (func $dummy5869) + (func $dummy5870) + (func $dummy5871) + (func $dummy5872) + (func $dummy5873) + (func $dummy5874) + (func $dummy5875) + (func $dummy5876) + (func $dummy5877) + (func $dummy5878) + (func $dummy5879) + (func $dummy5880) + (func $dummy5881) + (func $dummy5882) + (func $dummy5883) + (func $dummy5884) + (func $dummy5885) + (func $dummy5886) + (func $dummy5887) + (func $dummy5888) + (func $dummy5889) + (func $dummy5890) + (func $dummy5891) + (func $dummy5892) + (func $dummy5893) + (func $dummy5894) + (func $dummy5895) + (func $dummy5896) + (func $dummy5897) + (func $dummy5898) + (func $dummy5899) + (func $dummy5900) + (func $dummy5901) + (func $dummy5902) + (func $dummy5903) + (func $dummy5904) + (func $dummy5905) + (func $dummy5906) + (func $dummy5907) + (func $dummy5908) + (func $dummy5909) + (func $dummy5910) + (func $dummy5911) + (func $dummy5912) + (func $dummy5913) + (func $dummy5914) + (func $dummy5915) + (func $dummy5916) + (func $dummy5917) + (func $dummy5918) + (func $dummy5919) + (func $dummy5920) + (func $dummy5921) + (func $dummy5922) + (func $dummy5923) + (func $dummy5924) + (func $dummy5925) + (func $dummy5926) + (func $dummy5927) + (func $dummy5928) + (func $dummy5929) + (func $dummy5930) + (func $dummy5931) + (func $dummy5932) + (func $dummy5933) + (func $dummy5934) + (func $dummy5935) + (func $dummy5936) + (func $dummy5937) + (func $dummy5938) + (func $dummy5939) + (func $dummy5940) + (func $dummy5941) + (func $dummy5942) + (func $dummy5943) + (func $dummy5944) + (func $dummy5945) + (func $dummy5946) + (func $dummy5947) + (func $dummy5948) + (func $dummy5949) + (func $dummy5950) + (func $dummy5951) + (func $dummy5952) + (func $dummy5953) + (func $dummy5954) + (func $dummy5955) + (func $dummy5956) + (func $dummy5957) + (func $dummy5958) + (func $dummy5959) + (func $dummy5960) + (func $dummy5961) + (func $dummy5962) + (func $dummy5963) + (func $dummy5964) + (func $dummy5965) + (func $dummy5966) + (func $dummy5967) + (func $dummy5968) + (func $dummy5969) + (func $dummy5970) + (func $dummy5971) + (func $dummy5972) + (func $dummy5973) + (func $dummy5974) + (func $dummy5975) + (func $dummy5976) + (func $dummy5977) + (func $dummy5978) + (func $dummy5979) + (func $dummy5980) + (func $dummy5981) + (func $dummy5982) + (func $dummy5983) + (func $dummy5984) + (func $dummy5985) + (func $dummy5986) + (func $dummy5987) + (func $dummy5988) + (func $dummy5989) + (func $dummy5990) + (func $dummy5991) + (func $dummy5992) + (func $dummy5993) + (func $dummy5994) + (func $dummy5995) + (func $dummy5996) + (func $dummy5997) + (func $dummy5998) + (func $dummy5999) + (func $dummy6000) + (func $dummy6001) + (func $dummy6002) + (func $dummy6003) + (func $dummy6004) + (func $dummy6005) + (func $dummy6006) + (func $dummy6007) + (func $dummy6008) + (func $dummy6009) + (func $dummy6010) + (func $dummy6011) + (func $dummy6012) + (func $dummy6013) + (func $dummy6014) + (func $dummy6015) + (func $dummy6016) + (func $dummy6017) + (func $dummy6018) + (func $dummy6019) + (func $dummy6020) + (func $dummy6021) + (func $dummy6022) + (func $dummy6023) + (func $dummy6024) + (func $dummy6025) + (func $dummy6026) + (func $dummy6027) + (func $dummy6028) + (func $dummy6029) + (func $dummy6030) + (func $dummy6031) + (func $dummy6032) + (func $dummy6033) + (func $dummy6034) + (func $dummy6035) + (func $dummy6036) + (func $dummy6037) + (func $dummy6038) + (func $dummy6039) + (func $dummy6040) + (func $dummy6041) + (func $dummy6042) + (func $dummy6043) + (func $dummy6044) + (func $dummy6045) + (func $dummy6046) + (func $dummy6047) + (func $dummy6048) + (func $dummy6049) + (func $dummy6050) + (func $dummy6051) + (func $dummy6052) + (func $dummy6053) + (func $dummy6054) + (func $dummy6055) + (func $dummy6056) + (func $dummy6057) + (func $dummy6058) + (func $dummy6059) + (func $dummy6060) + (func $dummy6061) + (func $dummy6062) + (func $dummy6063) + (func $dummy6064) + (func $dummy6065) + (func $dummy6066) + (func $dummy6067) + (func $dummy6068) + (func $dummy6069) + (func $dummy6070) + (func $dummy6071) + (func $dummy6072) + (func $dummy6073) + (func $dummy6074) + (func $dummy6075) + (func $dummy6076) + (func $dummy6077) + (func $dummy6078) + (func $dummy6079) + (func $dummy6080) + (func $dummy6081) + (func $dummy6082) + (func $dummy6083) + (func $dummy6084) + (func $dummy6085) + (func $dummy6086) + (func $dummy6087) + (func $dummy6088) + (func $dummy6089) + (func $dummy6090) + (func $dummy6091) + (func $dummy6092) + (func $dummy6093) + (func $dummy6094) + (func $dummy6095) + (func $dummy6096) + (func $dummy6097) + (func $dummy6098) + (func $dummy6099) + (func $dummy6100) + (func $dummy6101) + (func $dummy6102) + (func $dummy6103) + (func $dummy6104) + (func $dummy6105) + (func $dummy6106) + (func $dummy6107) + (func $dummy6108) + (func $dummy6109) + (func $dummy6110) + (func $dummy6111) + (func $dummy6112) + (func $dummy6113) + (func $dummy6114) + (func $dummy6115) + (func $dummy6116) + (func $dummy6117) + (func $dummy6118) + (func $dummy6119) + (func $dummy6120) + (func $dummy6121) + (func $dummy6122) + (func $dummy6123) + (func $dummy6124) + (func $dummy6125) + (func $dummy6126) + (func $dummy6127) + (func $dummy6128) + (func $dummy6129) + (func $dummy6130) + (func $dummy6131) + (func $dummy6132) + (func $dummy6133) + (func $dummy6134) + (func $dummy6135) + (func $dummy6136) + (func $dummy6137) + (func $dummy6138) + (func $dummy6139) + (func $dummy6140) + (func $dummy6141) + (func $dummy6142) + (func $dummy6143) + (func $dummy6144) + (func $dummy6145) + (func $dummy6146) + (func $dummy6147) + (func $dummy6148) + (func $dummy6149) + (func $dummy6150) + (func $dummy6151) + (func $dummy6152) + (func $dummy6153) + (func $dummy6154) + (func $dummy6155) + (func $dummy6156) + (func $dummy6157) + (func $dummy6158) + (func $dummy6159) + (func $dummy6160) + (func $dummy6161) + (func $dummy6162) + (func $dummy6163) + (func $dummy6164) + (func $dummy6165) + (func $dummy6166) + (func $dummy6167) + (func $dummy6168) + (func $dummy6169) + (func $dummy6170) + (func $dummy6171) + (func $dummy6172) + (func $dummy6173) + (func $dummy6174) + (func $dummy6175) + (func $dummy6176) + (func $dummy6177) + (func $dummy6178) + (func $dummy6179) + (func $dummy6180) + (func $dummy6181) + (func $dummy6182) + (func $dummy6183) + (func $dummy6184) + (func $dummy6185) + (func $dummy6186) + (func $dummy6187) + (func $dummy6188) + (func $dummy6189) + (func $dummy6190) + (func $dummy6191) + (func $dummy6192) + (func $dummy6193) + (func $dummy6194) + (func $dummy6195) + (func $dummy6196) + (func $dummy6197) + (func $dummy6198) + (func $dummy6199) + (func $dummy6200) + (func $dummy6201) + (func $dummy6202) + (func $dummy6203) + (func $dummy6204) + (func $dummy6205) + (func $dummy6206) + (func $dummy6207) + (func $dummy6208) + (func $dummy6209) + (func $dummy6210) + (func $dummy6211) + (func $dummy6212) + (func $dummy6213) + (func $dummy6214) + (func $dummy6215) + (func $dummy6216) + (func $dummy6217) + (func $dummy6218) + (func $dummy6219) + (func $dummy6220) + (func $dummy6221) + (func $dummy6222) + (func $dummy6223) + (func $dummy6224) + (func $dummy6225) + (func $dummy6226) + (func $dummy6227) + (func $dummy6228) + (func $dummy6229) + (func $dummy6230) + (func $dummy6231) + (func $dummy6232) + (func $dummy6233) + (func $dummy6234) + (func $dummy6235) + (func $dummy6236) + (func $dummy6237) + (func $dummy6238) + (func $dummy6239) + (func $dummy6240) + (func $dummy6241) + (func $dummy6242) + (func $dummy6243) + (func $dummy6244) + (func $dummy6245) + (func $dummy6246) + (func $dummy6247) + (func $dummy6248) + (func $dummy6249) + (func $dummy6250) + (func $dummy6251) + (func $dummy6252) + (func $dummy6253) + (func $dummy6254) + (func $dummy6255) + (func $dummy6256) + (func $dummy6257) + (func $dummy6258) + (func $dummy6259) + (func $dummy6260) + (func $dummy6261) + (func $dummy6262) + (func $dummy6263) + (func $dummy6264) + (func $dummy6265) + (func $dummy6266) + (func $dummy6267) + (func $dummy6268) + (func $dummy6269) + (func $dummy6270) + (func $dummy6271) + (func $dummy6272) + (func $dummy6273) + (func $dummy6274) + (func $dummy6275) + (func $dummy6276) + (func $dummy6277) + (func $dummy6278) + (func $dummy6279) + (func $dummy6280) + (func $dummy6281) + (func $dummy6282) + (func $dummy6283) + (func $dummy6284) + (func $dummy6285) + (func $dummy6286) + (func $dummy6287) + (func $dummy6288) + (func $dummy6289) + (func $dummy6290) + (func $dummy6291) + (func $dummy6292) + (func $dummy6293) + (func $dummy6294) + (func $dummy6295) + (func $dummy6296) + (func $dummy6297) + (func $dummy6298) + (func $dummy6299) + (func $dummy6300) + (func $dummy6301) + (func $dummy6302) + (func $dummy6303) + (func $dummy6304) + (func $dummy6305) + (func $dummy6306) + (func $dummy6307) + (func $dummy6308) + (func $dummy6309) + (func $dummy6310) + (func $dummy6311) + (func $dummy6312) + (func $dummy6313) + (func $dummy6314) + (func $dummy6315) + (func $dummy6316) + (func $dummy6317) + (func $dummy6318) + (func $dummy6319) + (func $dummy6320) + (func $dummy6321) + (func $dummy6322) + (func $dummy6323) + (func $dummy6324) + (func $dummy6325) + (func $dummy6326) + (func $dummy6327) + (func $dummy6328) + (func $dummy6329) + (func $dummy6330) + (func $dummy6331) + (func $dummy6332) + (func $dummy6333) + (func $dummy6334) + (func $dummy6335) + (func $dummy6336) + (func $dummy6337) + (func $dummy6338) + (func $dummy6339) + (func $dummy6340) + (func $dummy6341) + (func $dummy6342) + (func $dummy6343) + (func $dummy6344) + (func $dummy6345) + (func $dummy6346) + (func $dummy6347) + (func $dummy6348) + (func $dummy6349) + (func $dummy6350) + (func $dummy6351) + (func $dummy6352) + (func $dummy6353) + (func $dummy6354) + (func $dummy6355) + (func $dummy6356) + (func $dummy6357) + (func $dummy6358) + (func $dummy6359) + (func $dummy6360) + (func $dummy6361) + (func $dummy6362) + (func $dummy6363) + (func $dummy6364) + (func $dummy6365) + (func $dummy6366) + (func $dummy6367) + (func $dummy6368) + (func $dummy6369) + (func $dummy6370) + (func $dummy6371) + (func $dummy6372) + (func $dummy6373) + (func $dummy6374) + (func $dummy6375) + (func $dummy6376) + (func $dummy6377) + (func $dummy6378) + (func $dummy6379) + (func $dummy6380) + (func $dummy6381) + (func $dummy6382) + (func $dummy6383) + (func $dummy6384) + (func $dummy6385) + (func $dummy6386) + (func $dummy6387) + (func $dummy6388) + (func $dummy6389) + (func $dummy6390) + (func $dummy6391) + (func $dummy6392) + (func $dummy6393) + (func $dummy6394) + (func $dummy6395) + (func $dummy6396) + (func $dummy6397) + (func $dummy6398) + (func $dummy6399) + (func $dummy6400) + (func $dummy6401) + (func $dummy6402) + (func $dummy6403) + (func $dummy6404) + (func $dummy6405) + (func $dummy6406) + (func $dummy6407) + (func $dummy6408) + (func $dummy6409) + (func $dummy6410) + (func $dummy6411) + (func $dummy6412) + (func $dummy6413) + (func $dummy6414) + (func $dummy6415) + (func $dummy6416) + (func $dummy6417) + (func $dummy6418) + (func $dummy6419) + (func $dummy6420) + (func $dummy6421) + (func $dummy6422) + (func $dummy6423) + (func $dummy6424) + (func $dummy6425) + (func $dummy6426) + (func $dummy6427) + (func $dummy6428) + (func $dummy6429) + (func $dummy6430) + (func $dummy6431) + (func $dummy6432) + (func $dummy6433) + (func $dummy6434) + (func $dummy6435) + (func $dummy6436) + (func $dummy6437) + (func $dummy6438) + (func $dummy6439) + (func $dummy6440) + (func $dummy6441) + (func $dummy6442) + (func $dummy6443) + (func $dummy6444) + (func $dummy6445) + (func $dummy6446) + (func $dummy6447) + (func $dummy6448) + (func $dummy6449) + (func $dummy6450) + (func $dummy6451) + (func $dummy6452) + (func $dummy6453) + (func $dummy6454) + (func $dummy6455) + (func $dummy6456) + (func $dummy6457) + (func $dummy6458) + (func $dummy6459) + (func $dummy6460) + (func $dummy6461) + (func $dummy6462) + (func $dummy6463) + (func $dummy6464) + (func $dummy6465) + (func $dummy6466) + (func $dummy6467) + (func $dummy6468) + (func $dummy6469) + (func $dummy6470) + (func $dummy6471) + (func $dummy6472) + (func $dummy6473) + (func $dummy6474) + (func $dummy6475) + (func $dummy6476) + (func $dummy6477) + (func $dummy6478) + (func $dummy6479) + (func $dummy6480) + (func $dummy6481) + (func $dummy6482) + (func $dummy6483) + (func $dummy6484) + (func $dummy6485) + (func $dummy6486) + (func $dummy6487) + (func $dummy6488) + (func $dummy6489) + (func $dummy6490) + (func $dummy6491) + (func $dummy6492) + (func $dummy6493) + (func $dummy6494) + (func $dummy6495) + (func $dummy6496) + (func $dummy6497) + (func $dummy6498) + (func $dummy6499) + (func $dummy6500) + (func $dummy6501) + (func $dummy6502) + (func $dummy6503) + (func $dummy6504) + (func $dummy6505) + (func $dummy6506) + (func $dummy6507) + (func $dummy6508) + (func $dummy6509) + (func $dummy6510) + (func $dummy6511) + (func $dummy6512) + (func $dummy6513) + (func $dummy6514) + (func $dummy6515) + (func $dummy6516) + (func $dummy6517) + (func $dummy6518) + (func $dummy6519) + (func $dummy6520) + (func $dummy6521) + (func $dummy6522) + (func $dummy6523) + (func $dummy6524) + (func $dummy6525) + (func $dummy6526) + (func $dummy6527) + (func $dummy6528) + (func $dummy6529) + (func $dummy6530) + (func $dummy6531) + (func $dummy6532) + (func $dummy6533) + (func $dummy6534) + (func $dummy6535) + (func $dummy6536) + (func $dummy6537) + (func $dummy6538) + (func $dummy6539) + (func $dummy6540) + (func $dummy6541) + (func $dummy6542) + (func $dummy6543) + (func $dummy6544) + (func $dummy6545) + (func $dummy6546) + (func $dummy6547) + (func $dummy6548) + (func $dummy6549) + (func $dummy6550) + (func $dummy6551) + (func $dummy6552) + (func $dummy6553) + (func $dummy6554) + (func $dummy6555) + (func $dummy6556) + (func $dummy6557) + (func $dummy6558) + (func $dummy6559) + (func $dummy6560) + (func $dummy6561) + (func $dummy6562) + (func $dummy6563) + (func $dummy6564) + (func $dummy6565) + (func $dummy6566) + (func $dummy6567) + (func $dummy6568) + (func $dummy6569) + (func $dummy6570) + (func $dummy6571) + (func $dummy6572) + (func $dummy6573) + (func $dummy6574) + (func $dummy6575) + (func $dummy6576) + (func $dummy6577) + (func $dummy6578) + (func $dummy6579) + (func $dummy6580) + (func $dummy6581) + (func $dummy6582) + (func $dummy6583) + (func $dummy6584) + (func $dummy6585) + (func $dummy6586) + (func $dummy6587) + (func $dummy6588) + (func $dummy6589) + (func $dummy6590) + (func $dummy6591) + (func $dummy6592) + (func $dummy6593) + (func $dummy6594) + (func $dummy6595) + (func $dummy6596) + (func $dummy6597) + (func $dummy6598) + (func $dummy6599) + (func $dummy6600) + (func $dummy6601) + (func $dummy6602) + (func $dummy6603) + (func $dummy6604) + (func $dummy6605) + (func $dummy6606) + (func $dummy6607) + (func $dummy6608) + (func $dummy6609) + (func $dummy6610) + (func $dummy6611) + (func $dummy6612) + (func $dummy6613) + (func $dummy6614) + (func $dummy6615) + (func $dummy6616) + (func $dummy6617) + (func $dummy6618) + (func $dummy6619) + (func $dummy6620) + (func $dummy6621) + (func $dummy6622) + (func $dummy6623) + (func $dummy6624) + (func $dummy6625) + (func $dummy6626) + (func $dummy6627) + (func $dummy6628) + (func $dummy6629) + (func $dummy6630) + (func $dummy6631) + (func $dummy6632) + (func $dummy6633) + (func $dummy6634) + (func $dummy6635) + (func $dummy6636) + (func $dummy6637) + (func $dummy6638) + (func $dummy6639) + (func $dummy6640) + (func $dummy6641) + (func $dummy6642) + (func $dummy6643) + (func $dummy6644) + (func $dummy6645) + (func $dummy6646) + (func $dummy6647) + (func $dummy6648) + (func $dummy6649) + (func $dummy6650) + (func $dummy6651) + (func $dummy6652) + (func $dummy6653) + (func $dummy6654) + (func $dummy6655) + (func $dummy6656) + (func $dummy6657) + (func $dummy6658) + (func $dummy6659) + (func $dummy6660) + (func $dummy6661) + (func $dummy6662) + (func $dummy6663) + (func $dummy6664) + (func $dummy6665) + (func $dummy6666) + (func $dummy6667) + (func $dummy6668) + (func $dummy6669) + (func $dummy6670) + (func $dummy6671) + (func $dummy6672) + (func $dummy6673) + (func $dummy6674) + (func $dummy6675) + (func $dummy6676) + (func $dummy6677) + (func $dummy6678) + (func $dummy6679) + (func $dummy6680) + (func $dummy6681) + (func $dummy6682) + (func $dummy6683) + (func $dummy6684) + (func $dummy6685) + (func $dummy6686) + (func $dummy6687) + (func $dummy6688) + (func $dummy6689) + (func $dummy6690) + (func $dummy6691) + (func $dummy6692) + (func $dummy6693) + (func $dummy6694) + (func $dummy6695) + (func $dummy6696) + (func $dummy6697) + (func $dummy6698) + (func $dummy6699) + (func $dummy6700) + (func $dummy6701) + (func $dummy6702) + (func $dummy6703) + (func $dummy6704) + (func $dummy6705) + (func $dummy6706) + (func $dummy6707) + (func $dummy6708) + (func $dummy6709) + (func $dummy6710) + (func $dummy6711) + (func $dummy6712) + (func $dummy6713) + (func $dummy6714) + (func $dummy6715) + (func $dummy6716) + (func $dummy6717) + (func $dummy6718) + (func $dummy6719) + (func $dummy6720) + (func $dummy6721) + (func $dummy6722) + (func $dummy6723) + (func $dummy6724) + (func $dummy6725) + (func $dummy6726) + (func $dummy6727) + (func $dummy6728) + (func $dummy6729) + (func $dummy6730) + (func $dummy6731) + (func $dummy6732) + (func $dummy6733) + (func $dummy6734) + (func $dummy6735) + (func $dummy6736) + (func $dummy6737) + (func $dummy6738) + (func $dummy6739) + (func $dummy6740) + (func $dummy6741) + (func $dummy6742) + (func $dummy6743) + (func $dummy6744) + (func $dummy6745) + (func $dummy6746) + (func $dummy6747) + (func $dummy6748) + (func $dummy6749) + (func $dummy6750) + (func $dummy6751) + (func $dummy6752) + (func $dummy6753) + (func $dummy6754) + (func $dummy6755) + (func $dummy6756) + (func $dummy6757) + (func $dummy6758) + (func $dummy6759) + (func $dummy6760) + (func $dummy6761) + (func $dummy6762) + (func $dummy6763) + (func $dummy6764) + (func $dummy6765) + (func $dummy6766) + (func $dummy6767) + (func $dummy6768) + (func $dummy6769) + (func $dummy6770) + (func $dummy6771) + (func $dummy6772) + (func $dummy6773) + (func $dummy6774) + (func $dummy6775) + (func $dummy6776) + (func $dummy6777) + (func $dummy6778) + (func $dummy6779) + (func $dummy6780) + (func $dummy6781) + (func $dummy6782) + (func $dummy6783) + (func $dummy6784) + (func $dummy6785) + (func $dummy6786) + (func $dummy6787) + (func $dummy6788) + (func $dummy6789) + (func $dummy6790) + (func $dummy6791) + (func $dummy6792) + (func $dummy6793) + (func $dummy6794) + (func $dummy6795) + (func $dummy6796) + (func $dummy6797) + (func $dummy6798) + (func $dummy6799) + (func $dummy6800) + (func $dummy6801) + (func $dummy6802) + (func $dummy6803) + (func $dummy6804) + (func $dummy6805) + (func $dummy6806) + (func $dummy6807) + (func $dummy6808) + (func $dummy6809) + (func $dummy6810) + (func $dummy6811) + (func $dummy6812) + (func $dummy6813) + (func $dummy6814) + (func $dummy6815) + (func $dummy6816) + (func $dummy6817) + (func $dummy6818) + (func $dummy6819) + (func $dummy6820) + (func $dummy6821) + (func $dummy6822) + (func $dummy6823) + (func $dummy6824) + (func $dummy6825) + (func $dummy6826) + (func $dummy6827) + (func $dummy6828) + (func $dummy6829) + (func $dummy6830) + (func $dummy6831) + (func $dummy6832) + (func $dummy6833) + (func $dummy6834) + (func $dummy6835) + (func $dummy6836) + (func $dummy6837) + (func $dummy6838) + (func $dummy6839) + (func $dummy6840) + (func $dummy6841) + (func $dummy6842) + (func $dummy6843) + (func $dummy6844) + (func $dummy6845) + (func $dummy6846) + (func $dummy6847) + (func $dummy6848) + (func $dummy6849) + (func $dummy6850) + (func $dummy6851) + (func $dummy6852) + (func $dummy6853) + (func $dummy6854) + (func $dummy6855) + (func $dummy6856) + (func $dummy6857) + (func $dummy6858) + (func $dummy6859) + (func $dummy6860) + (func $dummy6861) + (func $dummy6862) + (func $dummy6863) + (func $dummy6864) + (func $dummy6865) + (func $dummy6866) + (func $dummy6867) + (func $dummy6868) + (func $dummy6869) + (func $dummy6870) + (func $dummy6871) + (func $dummy6872) + (func $dummy6873) + (func $dummy6874) + (func $dummy6875) + (func $dummy6876) + (func $dummy6877) + (func $dummy6878) + (func $dummy6879) + (func $dummy6880) + (func $dummy6881) + (func $dummy6882) + (func $dummy6883) + (func $dummy6884) + (func $dummy6885) + (func $dummy6886) + (func $dummy6887) + (func $dummy6888) + (func $dummy6889) + (func $dummy6890) + (func $dummy6891) + (func $dummy6892) + (func $dummy6893) + (func $dummy6894) + (func $dummy6895) + (func $dummy6896) + (func $dummy6897) + (func $dummy6898) + (func $dummy6899) + (func $dummy6900) + (func $dummy6901) + (func $dummy6902) + (func $dummy6903) + (func $dummy6904) + (func $dummy6905) + (func $dummy6906) + (func $dummy6907) + (func $dummy6908) + (func $dummy6909) + (func $dummy6910) + (func $dummy6911) + (func $dummy6912) + (func $dummy6913) + (func $dummy6914) + (func $dummy6915) + (func $dummy6916) + (func $dummy6917) + (func $dummy6918) + (func $dummy6919) + (func $dummy6920) + (func $dummy6921) + (func $dummy6922) + (func $dummy6923) + (func $dummy6924) + (func $dummy6925) + (func $dummy6926) + (func $dummy6927) + (func $dummy6928) + (func $dummy6929) + (func $dummy6930) + (func $dummy6931) + (func $dummy6932) + (func $dummy6933) + (func $dummy6934) + (func $dummy6935) + (func $dummy6936) + (func $dummy6937) + (func $dummy6938) + (func $dummy6939) + (func $dummy6940) + (func $dummy6941) + (func $dummy6942) + (func $dummy6943) + (func $dummy6944) + (func $dummy6945) + (func $dummy6946) + (func $dummy6947) + (func $dummy6948) + (func $dummy6949) + (func $dummy6950) + (func $dummy6951) + (func $dummy6952) + (func $dummy6953) + (func $dummy6954) + (func $dummy6955) + (func $dummy6956) + (func $dummy6957) + (func $dummy6958) + (func $dummy6959) + (func $dummy6960) + (func $dummy6961) + (func $dummy6962) + (func $dummy6963) + (func $dummy6964) + (func $dummy6965) + (func $dummy6966) + (func $dummy6967) + (func $dummy6968) + (func $dummy6969) + (func $dummy6970) + (func $dummy6971) + (func $dummy6972) + (func $dummy6973) + (func $dummy6974) + (func $dummy6975) + (func $dummy6976) + (func $dummy6977) + (func $dummy6978) + (func $dummy6979) + (func $dummy6980) + (func $dummy6981) + (func $dummy6982) + (func $dummy6983) + (func $dummy6984) + (func $dummy6985) + (func $dummy6986) + (func $dummy6987) + (func $dummy6988) + (func $dummy6989) + (func $dummy6990) + (func $dummy6991) + (func $dummy6992) + (func $dummy6993) + (func $dummy6994) + (func $dummy6995) + (func $dummy6996) + (func $dummy6997) + (func $dummy6998) + (func $dummy6999) + (func $dummy7000) + (func $dummy7001) + (func $dummy7002) + (func $dummy7003) + (func $dummy7004) + (func $dummy7005) + (func $dummy7006) + (func $dummy7007) + (func $dummy7008) + (func $dummy7009) + (func $dummy7010) + (func $dummy7011) + (func $dummy7012) + (func $dummy7013) + (func $dummy7014) + (func $dummy7015) + (func $dummy7016) + (func $dummy7017) + (func $dummy7018) + (func $dummy7019) + (func $dummy7020) + (func $dummy7021) + (func $dummy7022) + (func $dummy7023) + (func $dummy7024) + (func $dummy7025) + (func $dummy7026) + (func $dummy7027) + (func $dummy7028) + (func $dummy7029) + (func $dummy7030) + (func $dummy7031) + (func $dummy7032) + (func $dummy7033) + (func $dummy7034) + (func $dummy7035) + (func $dummy7036) + (func $dummy7037) + (func $dummy7038) + (func $dummy7039) + (func $dummy7040) + (func $dummy7041) + (func $dummy7042) + (func $dummy7043) + (func $dummy7044) + (func $dummy7045) + (func $dummy7046) + (func $dummy7047) + (func $dummy7048) + (func $dummy7049) + (func $dummy7050) + (func $dummy7051) + (func $dummy7052) + (func $dummy7053) + (func $dummy7054) + (func $dummy7055) + (func $dummy7056) + (func $dummy7057) + (func $dummy7058) + (func $dummy7059) + (func $dummy7060) + (func $dummy7061) + (func $dummy7062) + (func $dummy7063) + (func $dummy7064) + (func $dummy7065) + (func $dummy7066) + (func $dummy7067) + (func $dummy7068) + (func $dummy7069) + (func $dummy7070) + (func $dummy7071) + (func $dummy7072) + (func $dummy7073) + (func $dummy7074) + (func $dummy7075) + (func $dummy7076) + (func $dummy7077) + (func $dummy7078) + (func $dummy7079) + (func $dummy7080) + (func $dummy7081) + (func $dummy7082) + (func $dummy7083) + (func $dummy7084) + (func $dummy7085) + (func $dummy7086) + (func $dummy7087) + (func $dummy7088) + (func $dummy7089) + (func $dummy7090) + (func $dummy7091) + (func $dummy7092) + (func $dummy7093) + (func $dummy7094) + (func $dummy7095) + (func $dummy7096) + (func $dummy7097) + (func $dummy7098) + (func $dummy7099) + (func $dummy7100) + (func $dummy7101) + (func $dummy7102) + (func $dummy7103) + (func $dummy7104) + (func $dummy7105) + (func $dummy7106) + (func $dummy7107) + (func $dummy7108) + (func $dummy7109) + (func $dummy7110) + (func $dummy7111) + (func $dummy7112) + (func $dummy7113) + (func $dummy7114) + (func $dummy7115) + (func $dummy7116) + (func $dummy7117) + (func $dummy7118) + (func $dummy7119) + (func $dummy7120) + (func $dummy7121) + (func $dummy7122) + (func $dummy7123) + (func $dummy7124) + (func $dummy7125) + (func $dummy7126) + (func $dummy7127) + (func $dummy7128) + (func $dummy7129) + (func $dummy7130) + (func $dummy7131) + (func $dummy7132) + (func $dummy7133) + (func $dummy7134) + (func $dummy7135) + (func $dummy7136) + (func $dummy7137) + (func $dummy7138) + (func $dummy7139) + (func $dummy7140) + (func $dummy7141) + (func $dummy7142) + (func $dummy7143) + (func $dummy7144) + (func $dummy7145) + (func $dummy7146) + (func $dummy7147) + (func $dummy7148) + (func $dummy7149) + (func $dummy7150) + (func $dummy7151) + (func $dummy7152) + (func $dummy7153) + (func $dummy7154) + (func $dummy7155) + (func $dummy7156) + (func $dummy7157) + (func $dummy7158) + (func $dummy7159) + (func $dummy7160) + (func $dummy7161) + (func $dummy7162) + (func $dummy7163) + (func $dummy7164) + (func $dummy7165) + (func $dummy7166) + (func $dummy7167) + (func $dummy7168) + (func $dummy7169) + (func $dummy7170) + (func $dummy7171) + (func $dummy7172) + (func $dummy7173) + (func $dummy7174) + (func $dummy7175) + (func $dummy7176) + (func $dummy7177) + (func $dummy7178) + (func $dummy7179) + (func $dummy7180) + (func $dummy7181) + (func $dummy7182) + (func $dummy7183) + (func $dummy7184) + (func $dummy7185) + (func $dummy7186) + (func $dummy7187) + (func $dummy7188) + (func $dummy7189) + (func $dummy7190) + (func $dummy7191) + (func $dummy7192) + (func $dummy7193) + (func $dummy7194) + (func $dummy7195) + (func $dummy7196) + (func $dummy7197) + (func $dummy7198) + (func $dummy7199) + (func $dummy7200) + (func $dummy7201) + (func $dummy7202) + (func $dummy7203) + (func $dummy7204) + (func $dummy7205) + (func $dummy7206) + (func $dummy7207) + (func $dummy7208) + (func $dummy7209) + (func $dummy7210) + (func $dummy7211) + (func $dummy7212) + (func $dummy7213) + (func $dummy7214) + (func $dummy7215) + (func $dummy7216) + (func $dummy7217) + (func $dummy7218) + (func $dummy7219) + (func $dummy7220) + (func $dummy7221) + (func $dummy7222) + (func $dummy7223) + (func $dummy7224) + (func $dummy7225) + (func $dummy7226) + (func $dummy7227) + (func $dummy7228) + (func $dummy7229) + (func $dummy7230) + (func $dummy7231) + (func $dummy7232) + (func $dummy7233) + (func $dummy7234) + (func $dummy7235) + (func $dummy7236) + (func $dummy7237) + (func $dummy7238) + (func $dummy7239) + (func $dummy7240) + (func $dummy7241) + (func $dummy7242) + (func $dummy7243) + (func $dummy7244) + (func $dummy7245) + (func $dummy7246) + (func $dummy7247) + (func $dummy7248) + (func $dummy7249) + (func $dummy7250) + (func $dummy7251) + (func $dummy7252) + (func $dummy7253) + (func $dummy7254) + (func $dummy7255) + (func $dummy7256) + (func $dummy7257) + (func $dummy7258) + (func $dummy7259) + (func $dummy7260) + (func $dummy7261) + (func $dummy7262) + (func $dummy7263) + (func $dummy7264) + (func $dummy7265) + (func $dummy7266) + (func $dummy7267) + (func $dummy7268) + (func $dummy7269) + (func $dummy7270) + (func $dummy7271) + (func $dummy7272) + (func $dummy7273) + (func $dummy7274) + (func $dummy7275) + (func $dummy7276) + (func $dummy7277) + (func $dummy7278) + (func $dummy7279) + (func $dummy7280) + (func $dummy7281) + (func $dummy7282) + (func $dummy7283) + (func $dummy7284) + (func $dummy7285) + (func $dummy7286) + (func $dummy7287) + (func $dummy7288) + (func $dummy7289) + (func $dummy7290) + (func $dummy7291) + (func $dummy7292) + (func $dummy7293) + (func $dummy7294) + (func $dummy7295) + (func $dummy7296) + (func $dummy7297) + (func $dummy7298) + (func $dummy7299) + (func $dummy7300) + (func $dummy7301) + (func $dummy7302) + (func $dummy7303) + (func $dummy7304) + (func $dummy7305) + (func $dummy7306) + (func $dummy7307) + (func $dummy7308) + (func $dummy7309) + (func $dummy7310) + (func $dummy7311) + (func $dummy7312) + (func $dummy7313) + (func $dummy7314) + (func $dummy7315) + (func $dummy7316) + (func $dummy7317) + (func $dummy7318) + (func $dummy7319) + (func $dummy7320) + (func $dummy7321) + (func $dummy7322) + (func $dummy7323) + (func $dummy7324) + (func $dummy7325) + (func $dummy7326) + (func $dummy7327) + (func $dummy7328) + (func $dummy7329) + (func $dummy7330) + (func $dummy7331) + (func $dummy7332) + (func $dummy7333) + (func $dummy7334) + (func $dummy7335) + (func $dummy7336) + (func $dummy7337) + (func $dummy7338) + (func $dummy7339) + (func $dummy7340) + (func $dummy7341) + (func $dummy7342) + (func $dummy7343) + (func $dummy7344) + (func $dummy7345) + (func $dummy7346) + (func $dummy7347) + (func $dummy7348) + (func $dummy7349) + (func $dummy7350) + (func $dummy7351) + (func $dummy7352) + (func $dummy7353) + (func $dummy7354) + (func $dummy7355) + (func $dummy7356) + (func $dummy7357) + (func $dummy7358) + (func $dummy7359) + (func $dummy7360) + (func $dummy7361) + (func $dummy7362) + (func $dummy7363) + (func $dummy7364) + (func $dummy7365) + (func $dummy7366) + (func $dummy7367) + (func $dummy7368) + (func $dummy7369) + (func $dummy7370) + (func $dummy7371) + (func $dummy7372) + (func $dummy7373) + (func $dummy7374) + (func $dummy7375) + (func $dummy7376) + (func $dummy7377) + (func $dummy7378) + (func $dummy7379) + (func $dummy7380) + (func $dummy7381) + (func $dummy7382) + (func $dummy7383) + (func $dummy7384) + (func $dummy7385) + (func $dummy7386) + (func $dummy7387) + (func $dummy7388) + (func $dummy7389) + (func $dummy7390) + (func $dummy7391) + (func $dummy7392) + (func $dummy7393) + (func $dummy7394) + (func $dummy7395) + (func $dummy7396) + (func $dummy7397) + (func $dummy7398) + (func $dummy7399) + (func $dummy7400) + (func $dummy7401) + (func $dummy7402) + (func $dummy7403) + (func $dummy7404) + (func $dummy7405) + (func $dummy7406) + (func $dummy7407) + (func $dummy7408) + (func $dummy7409) + (func $dummy7410) + (func $dummy7411) + (func $dummy7412) + (func $dummy7413) + (func $dummy7414) + (func $dummy7415) + (func $dummy7416) + (func $dummy7417) + (func $dummy7418) + (func $dummy7419) + (func $dummy7420) + (func $dummy7421) + (func $dummy7422) + (func $dummy7423) + (func $dummy7424) + (func $dummy7425) + (func $dummy7426) + (func $dummy7427) + (func $dummy7428) + (func $dummy7429) + (func $dummy7430) + (func $dummy7431) + (func $dummy7432) + (func $dummy7433) + (func $dummy7434) + (func $dummy7435) + (func $dummy7436) + (func $dummy7437) + (func $dummy7438) + (func $dummy7439) + (func $dummy7440) + (func $dummy7441) + (func $dummy7442) + (func $dummy7443) + (func $dummy7444) + (func $dummy7445) + (func $dummy7446) + (func $dummy7447) + (func $dummy7448) + (func $dummy7449) + (func $dummy7450) + (func $dummy7451) + (func $dummy7452) + (func $dummy7453) + (func $dummy7454) + (func $dummy7455) + (func $dummy7456) + (func $dummy7457) + (func $dummy7458) + (func $dummy7459) + (func $dummy7460) + (func $dummy7461) + (func $dummy7462) + (func $dummy7463) + (func $dummy7464) + (func $dummy7465) + (func $dummy7466) + (func $dummy7467) + (func $dummy7468) + (func $dummy7469) + (func $dummy7470) + (func $dummy7471) + (func $dummy7472) + (func $dummy7473) + (func $dummy7474) + (func $dummy7475) + (func $dummy7476) + (func $dummy7477) + (func $dummy7478) + (func $dummy7479) + (func $dummy7480) + (func $dummy7481) + (func $dummy7482) + (func $dummy7483) + (func $dummy7484) + (func $dummy7485) + (func $dummy7486) + (func $dummy7487) + (func $dummy7488) + (func $dummy7489) + (func $dummy7490) + (func $dummy7491) + (func $dummy7492) + (func $dummy7493) + (func $dummy7494) + (func $dummy7495) + (func $dummy7496) + (func $dummy7497) + (func $dummy7498) + (func $dummy7499) + (func $dummy7500) + (func $dummy7501) + (func $dummy7502) + (func $dummy7503) + (func $dummy7504) + (func $dummy7505) + (func $dummy7506) + (func $dummy7507) + (func $dummy7508) + (func $dummy7509) + (func $dummy7510) + (func $dummy7511) + (func $dummy7512) + (func $dummy7513) + (func $dummy7514) + (func $dummy7515) + (func $dummy7516) + (func $dummy7517) + (func $dummy7518) + (func $dummy7519) + (func $dummy7520) + (func $dummy7521) + (func $dummy7522) + (func $dummy7523) + (func $dummy7524) + (func $dummy7525) + (func $dummy7526) + (func $dummy7527) + (func $dummy7528) + (func $dummy7529) + (func $dummy7530) + (func $dummy7531) + (func $dummy7532) + (func $dummy7533) + (func $dummy7534) + (func $dummy7535) + (func $dummy7536) + (func $dummy7537) + (func $dummy7538) + (func $dummy7539) + (func $dummy7540) + (func $dummy7541) + (func $dummy7542) + (func $dummy7543) + (func $dummy7544) + (func $dummy7545) + (func $dummy7546) + (func $dummy7547) + (func $dummy7548) + (func $dummy7549) + (func $dummy7550) + (func $dummy7551) + (func $dummy7552) + (func $dummy7553) + (func $dummy7554) + (func $dummy7555) + (func $dummy7556) + (func $dummy7557) + (func $dummy7558) + (func $dummy7559) + (func $dummy7560) + (func $dummy7561) + (func $dummy7562) + (func $dummy7563) + (func $dummy7564) + (func $dummy7565) + (func $dummy7566) + (func $dummy7567) + (func $dummy7568) + (func $dummy7569) + (func $dummy7570) + (func $dummy7571) + (func $dummy7572) + (func $dummy7573) + (func $dummy7574) + (func $dummy7575) + (func $dummy7576) + (func $dummy7577) + (func $dummy7578) + (func $dummy7579) + (func $dummy7580) + (func $dummy7581) + (func $dummy7582) + (func $dummy7583) + (func $dummy7584) + (func $dummy7585) + (func $dummy7586) + (func $dummy7587) + (func $dummy7588) + (func $dummy7589) + (func $dummy7590) + (func $dummy7591) + (func $dummy7592) + (func $dummy7593) + (func $dummy7594) + (func $dummy7595) + (func $dummy7596) + (func $dummy7597) + (func $dummy7598) + (func $dummy7599) + (func $dummy7600) + (func $dummy7601) + (func $dummy7602) + (func $dummy7603) + (func $dummy7604) + (func $dummy7605) + (func $dummy7606) + (func $dummy7607) + (func $dummy7608) + (func $dummy7609) + (func $dummy7610) + (func $dummy7611) + (func $dummy7612) + (func $dummy7613) + (func $dummy7614) + (func $dummy7615) + (func $dummy7616) + (func $dummy7617) + (func $dummy7618) + (func $dummy7619) + (func $dummy7620) + (func $dummy7621) + (func $dummy7622) + (func $dummy7623) + (func $dummy7624) + (func $dummy7625) + (func $dummy7626) + (func $dummy7627) + (func $dummy7628) + (func $dummy7629) + (func $dummy7630) + (func $dummy7631) + (func $dummy7632) + (func $dummy7633) + (func $dummy7634) + (func $dummy7635) + (func $dummy7636) + (func $dummy7637) + (func $dummy7638) + (func $dummy7639) + (func $dummy7640) + (func $dummy7641) + (func $dummy7642) + (func $dummy7643) + (func $dummy7644) + (func $dummy7645) + (func $dummy7646) + (func $dummy7647) + (func $dummy7648) + (func $dummy7649) + (func $dummy7650) + (func $dummy7651) + (func $dummy7652) + (func $dummy7653) + (func $dummy7654) + (func $dummy7655) + (func $dummy7656) + (func $dummy7657) + (func $dummy7658) + (func $dummy7659) + (func $dummy7660) + (func $dummy7661) + (func $dummy7662) + (func $dummy7663) + (func $dummy7664) + (func $dummy7665) + (func $dummy7666) + (func $dummy7667) + (func $dummy7668) + (func $dummy7669) + (func $dummy7670) + (func $dummy7671) + (func $dummy7672) + (func $dummy7673) + (func $dummy7674) + (func $dummy7675) + (func $dummy7676) + (func $dummy7677) + (func $dummy7678) + (func $dummy7679) + (func $dummy7680) + (func $dummy7681) + (func $dummy7682) + (func $dummy7683) + (func $dummy7684) + (func $dummy7685) + (func $dummy7686) + (func $dummy7687) + (func $dummy7688) + (func $dummy7689) + (func $dummy7690) + (func $dummy7691) + (func $dummy7692) + (func $dummy7693) + (func $dummy7694) + (func $dummy7695) + (func $dummy7696) + (func $dummy7697) + (func $dummy7698) + (func $dummy7699) + (func $dummy7700) + (func $dummy7701) + (func $dummy7702) + (func $dummy7703) + (func $dummy7704) + (func $dummy7705) + (func $dummy7706) + (func $dummy7707) + (func $dummy7708) + (func $dummy7709) + (func $dummy7710) + (func $dummy7711) + (func $dummy7712) + (func $dummy7713) + (func $dummy7714) + (func $dummy7715) + (func $dummy7716) + (func $dummy7717) + (func $dummy7718) + (func $dummy7719) + (func $dummy7720) + (func $dummy7721) + (func $dummy7722) + (func $dummy7723) + (func $dummy7724) + (func $dummy7725) + (func $dummy7726) + (func $dummy7727) + (func $dummy7728) + (func $dummy7729) + (func $dummy7730) + (func $dummy7731) + (func $dummy7732) + (func $dummy7733) + (func $dummy7734) + (func $dummy7735) + (func $dummy7736) + (func $dummy7737) + (func $dummy7738) + (func $dummy7739) + (func $dummy7740) + (func $dummy7741) + (func $dummy7742) + (func $dummy7743) + (func $dummy7744) + (func $dummy7745) + (func $dummy7746) + (func $dummy7747) + (func $dummy7748) + (func $dummy7749) + (func $dummy7750) + (func $dummy7751) + (func $dummy7752) + (func $dummy7753) + (func $dummy7754) + (func $dummy7755) + (func $dummy7756) + (func $dummy7757) + (func $dummy7758) + (func $dummy7759) + (func $dummy7760) + (func $dummy7761) + (func $dummy7762) + (func $dummy7763) + (func $dummy7764) + (func $dummy7765) + (func $dummy7766) + (func $dummy7767) + (func $dummy7768) + (func $dummy7769) + (func $dummy7770) + (func $dummy7771) + (func $dummy7772) + (func $dummy7773) + (func $dummy7774) + (func $dummy7775) + (func $dummy7776) + (func $dummy7777) + (func $dummy7778) + (func $dummy7779) + (func $dummy7780) + (func $dummy7781) + (func $dummy7782) + (func $dummy7783) + (func $dummy7784) + (func $dummy7785) + (func $dummy7786) + (func $dummy7787) + (func $dummy7788) + (func $dummy7789) + (func $dummy7790) + (func $dummy7791) + (func $dummy7792) + (func $dummy7793) + (func $dummy7794) + (func $dummy7795) + (func $dummy7796) + (func $dummy7797) + (func $dummy7798) + (func $dummy7799) + (func $dummy7800) + (func $dummy7801) + (func $dummy7802) + (func $dummy7803) + (func $dummy7804) + (func $dummy7805) + (func $dummy7806) + (func $dummy7807) + (func $dummy7808) + (func $dummy7809) + (func $dummy7810) + (func $dummy7811) + (func $dummy7812) + (func $dummy7813) + (func $dummy7814) + (func $dummy7815) + (func $dummy7816) + (func $dummy7817) + (func $dummy7818) + (func $dummy7819) + (func $dummy7820) + (func $dummy7821) + (func $dummy7822) + (func $dummy7823) + (func $dummy7824) + (func $dummy7825) + (func $dummy7826) + (func $dummy7827) + (func $dummy7828) + (func $dummy7829) + (func $dummy7830) + (func $dummy7831) + (func $dummy7832) + (func $dummy7833) + (func $dummy7834) + (func $dummy7835) + (func $dummy7836) + (func $dummy7837) + (func $dummy7838) + (func $dummy7839) + (func $dummy7840) + (func $dummy7841) + (func $dummy7842) + (func $dummy7843) + (func $dummy7844) + (func $dummy7845) + (func $dummy7846) + (func $dummy7847) + (func $dummy7848) + (func $dummy7849) + (func $dummy7850) + (func $dummy7851) + (func $dummy7852) + (func $dummy7853) + (func $dummy7854) + (func $dummy7855) + (func $dummy7856) + (func $dummy7857) + (func $dummy7858) + (func $dummy7859) + (func $dummy7860) + (func $dummy7861) + (func $dummy7862) + (func $dummy7863) + (func $dummy7864) + (func $dummy7865) + (func $dummy7866) + (func $dummy7867) + (func $dummy7868) + (func $dummy7869) + (func $dummy7870) + (func $dummy7871) + (func $dummy7872) + (func $dummy7873) + (func $dummy7874) + (func $dummy7875) + (func $dummy7876) + (func $dummy7877) + (func $dummy7878) + (func $dummy7879) + (func $dummy7880) + (func $dummy7881) + (func $dummy7882) + (func $dummy7883) + (func $dummy7884) + (func $dummy7885) + (func $dummy7886) + (func $dummy7887) + (func $dummy7888) + (func $dummy7889) + (func $dummy7890) + (func $dummy7891) + (func $dummy7892) + (func $dummy7893) + (func $dummy7894) + (func $dummy7895) + (func $dummy7896) + (func $dummy7897) + (func $dummy7898) + (func $dummy7899) + (func $dummy7900) + (func $dummy7901) + (func $dummy7902) + (func $dummy7903) + (func $dummy7904) + (func $dummy7905) + (func $dummy7906) + (func $dummy7907) + (func $dummy7908) + (func $dummy7909) + (func $dummy7910) + (func $dummy7911) + (func $dummy7912) + (func $dummy7913) + (func $dummy7914) + (func $dummy7915) + (func $dummy7916) + (func $dummy7917) + (func $dummy7918) + (func $dummy7919) + (func $dummy7920) + (func $dummy7921) + (func $dummy7922) + (func $dummy7923) + (func $dummy7924) + (func $dummy7925) + (func $dummy7926) + (func $dummy7927) + (func $dummy7928) + (func $dummy7929) + (func $dummy7930) + (func $dummy7931) + (func $dummy7932) + (func $dummy7933) + (func $dummy7934) + (func $dummy7935) + (func $dummy7936) + (func $dummy7937) + (func $dummy7938) + (func $dummy7939) + (func $dummy7940) + (func $dummy7941) + (func $dummy7942) + (func $dummy7943) + (func $dummy7944) + (func $dummy7945) + (func $dummy7946) + (func $dummy7947) + (func $dummy7948) + (func $dummy7949) + (func $dummy7950) + (func $dummy7951) + (func $dummy7952) + (func $dummy7953) + (func $dummy7954) + (func $dummy7955) + (func $dummy7956) + (func $dummy7957) + (func $dummy7958) + (func $dummy7959) + (func $dummy7960) + (func $dummy7961) + (func $dummy7962) + (func $dummy7963) + (func $dummy7964) + (func $dummy7965) + (func $dummy7966) + (func $dummy7967) + (func $dummy7968) + (func $dummy7969) + (func $dummy7970) + (func $dummy7971) + (func $dummy7972) + (func $dummy7973) + (func $dummy7974) + (func $dummy7975) + (func $dummy7976) + (func $dummy7977) + (func $dummy7978) + (func $dummy7979) + (func $dummy7980) + (func $dummy7981) + (func $dummy7982) + (func $dummy7983) + (func $dummy7984) + (func $dummy7985) + (func $dummy7986) + (func $dummy7987) + (func $dummy7988) + (func $dummy7989) + (func $dummy7990) + (func $dummy7991) + (func $dummy7992) + (func $dummy7993) + (func $dummy7994) + (func $dummy7995) + (func $dummy7996) + (func $dummy7997) + (func $dummy7998) + (func $dummy7999) + (func $dummy8000) + (func $dummy8001) + (func $dummy8002) + (func $dummy8003) + (func $dummy8004) + (func $dummy8005) + (func $dummy8006) + (func $dummy8007) + (func $dummy8008) + (func $dummy8009) + (func $dummy8010) + (func $dummy8011) + (func $dummy8012) + (func $dummy8013) + (func $dummy8014) + (func $dummy8015) + (func $dummy8016) + (func $dummy8017) + (func $dummy8018) + (func $dummy8019) + (func $dummy8020) + (func $dummy8021) + (func $dummy8022) + (func $dummy8023) + (func $dummy8024) + (func $dummy8025) + (func $dummy8026) + (func $dummy8027) + (func $dummy8028) + (func $dummy8029) + (func $dummy8030) + (func $dummy8031) + (func $dummy8032) + (func $dummy8033) + (func $dummy8034) + (func $dummy8035) + (func $dummy8036) + (func $dummy8037) + (func $dummy8038) + (func $dummy8039) + (func $dummy8040) + (func $dummy8041) + (func $dummy8042) + (func $dummy8043) + (func $dummy8044) + (func $dummy8045) + (func $dummy8046) + (func $dummy8047) + (func $dummy8048) + (func $dummy8049) + (func $dummy8050) + (func $dummy8051) + (func $dummy8052) + (func $dummy8053) + (func $dummy8054) + (func $dummy8055) + (func $dummy8056) + (func $dummy8057) + (func $dummy8058) + (func $dummy8059) + (func $dummy8060) + (func $dummy8061) + (func $dummy8062) + (func $dummy8063) + (func $dummy8064) + (func $dummy8065) + (func $dummy8066) + (func $dummy8067) + (func $dummy8068) + (func $dummy8069) + (func $dummy8070) + (func $dummy8071) + (func $dummy8072) + (func $dummy8073) + (func $dummy8074) + (func $dummy8075) + (func $dummy8076) + (func $dummy8077) + (func $dummy8078) + (func $dummy8079) + (func $dummy8080) + (func $dummy8081) + (func $dummy8082) + (func $dummy8083) + (func $dummy8084) + (func $dummy8085) + (func $dummy8086) + (func $dummy8087) + (func $dummy8088) + (func $dummy8089) + (func $dummy8090) + (func $dummy8091) + (func $dummy8092) + (func $dummy8093) + (func $dummy8094) + (func $dummy8095) + (func $dummy8096) + (func $dummy8097) + (func $dummy8098) + (func $dummy8099) + (func $dummy8100) + (func $dummy8101) + (func $dummy8102) + (func $dummy8103) + (func $dummy8104) + (func $dummy8105) + (func $dummy8106) + (func $dummy8107) + (func $dummy8108) + (func $dummy8109) + (func $dummy8110) + (func $dummy8111) + (func $dummy8112) + (func $dummy8113) + (func $dummy8114) + (func $dummy8115) + (func $dummy8116) + (func $dummy8117) + (func $dummy8118) + (func $dummy8119) + (func $dummy8120) + (func $dummy8121) + (func $dummy8122) + (func $dummy8123) + (func $dummy8124) + (func $dummy8125) + (func $dummy8126) + (func $dummy8127) + (func $dummy8128) + (func $dummy8129) + (func $dummy8130) + (func $dummy8131) + (func $dummy8132) + (func $dummy8133) + (func $dummy8134) + (func $dummy8135) + (func $dummy8136) + (func $dummy8137) + (func $dummy8138) + (func $dummy8139) + (func $dummy8140) + (func $dummy8141) + (func $dummy8142) + (func $dummy8143) + (func $dummy8144) + (func $dummy8145) + (func $dummy8146) + (func $dummy8147) + (func $dummy8148) + (func $dummy8149) + (func $dummy8150) + (func $dummy8151) + (func $dummy8152) + (func $dummy8153) + (func $dummy8154) + (func $dummy8155) + (func $dummy8156) + (func $dummy8157) + (func $dummy8158) + (func $dummy8159) + (func $dummy8160) + (func $dummy8161) + (func $dummy8162) + (func $dummy8163) + (func $dummy8164) + (func $dummy8165) + (func $dummy8166) + (func $dummy8167) + (func $dummy8168) + (func $dummy8169) + (func $dummy8170) + (func $dummy8171) + (func $dummy8172) + (func $dummy8173) + (func $dummy8174) + (func $dummy8175) + (func $dummy8176) + (func $dummy8177) + (func $dummy8178) + (func $dummy8179) + (func $dummy8180) + (func $dummy8181) + (func $dummy8182) + (func $dummy8183) + (func $dummy8184) + (func $dummy8185) + (func $dummy8186) + (func $dummy8187) + (func $dummy8188) + (func $dummy8189) + (func $dummy8190) + (func $dummy8191) + (func $dummy8192) + (func $dummy8193) + (func $dummy8194) + (func $dummy8195) + (func $dummy8196) + (func $dummy8197) + (func $dummy8198) + (func $dummy8199) + (func $dummy8200) + (func $dummy8201) + (func $dummy8202) + (func $dummy8203) + (func $dummy8204) + (func $dummy8205) + (func $dummy8206) + (func $dummy8207) + (func $dummy8208) + (func $dummy8209) + (func $dummy8210) + (func $dummy8211) + (func $dummy8212) + (func $dummy8213) + (func $dummy8214) + (func $dummy8215) + (func $dummy8216) + (func $dummy8217) + (func $dummy8218) + (func $dummy8219) + (func $dummy8220) + (func $dummy8221) + (func $dummy8222) + (func $dummy8223) + (func $dummy8224) + (func $dummy8225) + (func $dummy8226) + (func $dummy8227) + (func $dummy8228) + (func $dummy8229) + (func $dummy8230) + (func $dummy8231) + (func $dummy8232) + (func $dummy8233) + (func $dummy8234) + (func $dummy8235) + (func $dummy8236) + (func $dummy8237) + (func $dummy8238) + (func $dummy8239) + (func $dummy8240) + (func $dummy8241) + (func $dummy8242) + (func $dummy8243) + (func $dummy8244) + (func $dummy8245) + (func $dummy8246) + (func $dummy8247) + (func $dummy8248) + (func $dummy8249) + (func $dummy8250) + (func $dummy8251) + (func $dummy8252) + (func $dummy8253) + (func $dummy8254) + (func $dummy8255) + (func $dummy8256) + (func $dummy8257) + (func $dummy8258) + (func $dummy8259) + (func $dummy8260) + (func $dummy8261) + (func $dummy8262) + (func $dummy8263) + (func $dummy8264) + (func $dummy8265) + (func $dummy8266) + (func $dummy8267) + (func $dummy8268) + (func $dummy8269) + (func $dummy8270) + (func $dummy8271) + (func $dummy8272) + (func $dummy8273) + (func $dummy8274) + (func $dummy8275) + (func $dummy8276) + (func $dummy8277) + (func $dummy8278) + (func $dummy8279) + (func $dummy8280) + (func $dummy8281) + (func $dummy8282) + (func $dummy8283) + (func $dummy8284) + (func $dummy8285) + (func $dummy8286) + (func $dummy8287) + (func $dummy8288) + (func $dummy8289) + (func $dummy8290) + (func $dummy8291) + (func $dummy8292) + (func $dummy8293) + (func $dummy8294) + (func $dummy8295) + (func $dummy8296) + (func $dummy8297) + (func $dummy8298) + (func $dummy8299) + (func $dummy8300) + (func $dummy8301) + (func $dummy8302) + (func $dummy8303) + (func $dummy8304) + (func $dummy8305) + (func $dummy8306) + (func $dummy8307) + (func $dummy8308) + (func $dummy8309) + (func $dummy8310) + (func $dummy8311) + (func $dummy8312) + (func $dummy8313) + (func $dummy8314) + (func $dummy8315) + (func $dummy8316) + (func $dummy8317) + (func $dummy8318) + (func $dummy8319) + (func $dummy8320) + (func $dummy8321) + (func $dummy8322) + (func $dummy8323) + (func $dummy8324) + (func $dummy8325) + (func $dummy8326) + (func $dummy8327) + (func $dummy8328) + (func $dummy8329) + (func $dummy8330) + (func $dummy8331) + (func $dummy8332) + (func $dummy8333) + (func $dummy8334) + (func $dummy8335) + (func $dummy8336) + (func $dummy8337) + (func $dummy8338) + (func $dummy8339) + (func $dummy8340) + (func $dummy8341) + (func $dummy8342) + (func $dummy8343) + (func $dummy8344) + (func $dummy8345) + (func $dummy8346) + (func $dummy8347) + (func $dummy8348) + (func $dummy8349) + (func $dummy8350) + (func $dummy8351) + (func $dummy8352) + (func $dummy8353) + (func $dummy8354) + (func $dummy8355) + (func $dummy8356) + (func $dummy8357) + (func $dummy8358) + (func $dummy8359) + (func $dummy8360) + (func $dummy8361) + (func $dummy8362) + (func $dummy8363) + (func $dummy8364) + (func $dummy8365) + (func $dummy8366) + (func $dummy8367) + (func $dummy8368) + (func $dummy8369) + (func $dummy8370) + (func $dummy8371) + (func $dummy8372) + (func $dummy8373) + (func $dummy8374) + (func $dummy8375) + (func $dummy8376) + (func $dummy8377) + (func $dummy8378) + (func $dummy8379) + (func $dummy8380) + (func $dummy8381) + (func $dummy8382) + (func $dummy8383) + (func $dummy8384) + (func $dummy8385) + (func $dummy8386) + (func $dummy8387) + (func $dummy8388) + (func $dummy8389) + (func $dummy8390) + (func $dummy8391) + (func $dummy8392) + (func $dummy8393) + (func $dummy8394) + (func $dummy8395) + (func $dummy8396) + (func $dummy8397) + (func $dummy8398) + (func $dummy8399) + (func $dummy8400) + (func $dummy8401) + (func $dummy8402) + (func $dummy8403) + (func $dummy8404) + (func $dummy8405) + (func $dummy8406) + (func $dummy8407) + (func $dummy8408) + (func $dummy8409) + (func $dummy8410) + (func $dummy8411) + (func $dummy8412) + (func $dummy8413) + (func $dummy8414) + (func $dummy8415) + (func $dummy8416) + (func $dummy8417) + (func $dummy8418) + (func $dummy8419) + (func $dummy8420) + (func $dummy8421) + (func $dummy8422) + (func $dummy8423) + (func $dummy8424) + (func $dummy8425) + (func $dummy8426) + (func $dummy8427) + (func $dummy8428) + (func $dummy8429) + (func $dummy8430) + (func $dummy8431) + (func $dummy8432) + (func $dummy8433) + (func $dummy8434) + (func $dummy8435) + (func $dummy8436) + (func $dummy8437) + (func $dummy8438) + (func $dummy8439) + (func $dummy8440) + (func $dummy8441) + (func $dummy8442) + (func $dummy8443) + (func $dummy8444) + (func $dummy8445) + (func $dummy8446) + (func $dummy8447) + (func $dummy8448) + (func $dummy8449) + (func $dummy8450) + (func $dummy8451) + (func $dummy8452) + (func $dummy8453) + (func $dummy8454) + (func $dummy8455) + (func $dummy8456) + (func $dummy8457) + (func $dummy8458) + (func $dummy8459) + (func $dummy8460) + (func $dummy8461) + (func $dummy8462) + (func $dummy8463) + (func $dummy8464) + (func $dummy8465) + (func $dummy8466) + (func $dummy8467) + (func $dummy8468) + (func $dummy8469) + (func $dummy8470) + (func $dummy8471) + (func $dummy8472) + (func $dummy8473) + (func $dummy8474) + (func $dummy8475) + (func $dummy8476) + (func $dummy8477) + (func $dummy8478) + (func $dummy8479) + (func $dummy8480) + (func $dummy8481) + (func $dummy8482) + (func $dummy8483) + (func $dummy8484) + (func $dummy8485) + (func $dummy8486) + (func $dummy8487) + (func $dummy8488) + (func $dummy8489) + (func $dummy8490) + (func $dummy8491) + (func $dummy8492) + (func $dummy8493) + (func $dummy8494) + (func $dummy8495) + (func $dummy8496) + (func $dummy8497) + (func $dummy8498) + (func $dummy8499) + (func $dummy8500) + (func $dummy8501) + (func $dummy8502) + (func $dummy8503) + (func $dummy8504) + (func $dummy8505) + (func $dummy8506) + (func $dummy8507) + (func $dummy8508) + (func $dummy8509) + (func $dummy8510) + (func $dummy8511) + (func $dummy8512) + (func $dummy8513) + (func $dummy8514) + (func $dummy8515) + (func $dummy8516) + (func $dummy8517) + (func $dummy8518) + (func $dummy8519) + (func $dummy8520) + (func $dummy8521) + (func $dummy8522) + (func $dummy8523) + (func $dummy8524) + (func $dummy8525) + (func $dummy8526) + (func $dummy8527) + (func $dummy8528) + (func $dummy8529) + (func $dummy8530) + (func $dummy8531) + (func $dummy8532) + (func $dummy8533) + (func $dummy8534) + (func $dummy8535) + (func $dummy8536) + (func $dummy8537) + (func $dummy8538) + (func $dummy8539) + (func $dummy8540) + (func $dummy8541) + (func $dummy8542) + (func $dummy8543) + (func $dummy8544) + (func $dummy8545) + (func $dummy8546) + (func $dummy8547) + (func $dummy8548) + (func $dummy8549) + (func $dummy8550) + (func $dummy8551) + (func $dummy8552) + (func $dummy8553) + (func $dummy8554) + (func $dummy8555) + (func $dummy8556) + (func $dummy8557) + (func $dummy8558) + (func $dummy8559) + (func $dummy8560) + (func $dummy8561) + (func $dummy8562) + (func $dummy8563) + (func $dummy8564) + (func $dummy8565) + (func $dummy8566) + (func $dummy8567) + (func $dummy8568) + (func $dummy8569) + (func $dummy8570) + (func $dummy8571) + (func $dummy8572) + (func $dummy8573) + (func $dummy8574) + (func $dummy8575) + (func $dummy8576) + (func $dummy8577) + (func $dummy8578) + (func $dummy8579) + (func $dummy8580) + (func $dummy8581) + (func $dummy8582) + (func $dummy8583) + (func $dummy8584) + (func $dummy8585) + (func $dummy8586) + (func $dummy8587) + (func $dummy8588) + (func $dummy8589) + (func $dummy8590) + (func $dummy8591) + (func $dummy8592) + (func $dummy8593) + (func $dummy8594) + (func $dummy8595) + (func $dummy8596) + (func $dummy8597) + (func $dummy8598) + (func $dummy8599) + (func $dummy8600) + (func $dummy8601) + (func $dummy8602) + (func $dummy8603) + (func $dummy8604) + (func $dummy8605) + (func $dummy8606) + (func $dummy8607) + (func $dummy8608) + (func $dummy8609) + (func $dummy8610) + (func $dummy8611) + (func $dummy8612) + (func $dummy8613) + (func $dummy8614) + (func $dummy8615) + (func $dummy8616) + (func $dummy8617) + (func $dummy8618) + (func $dummy8619) + (func $dummy8620) + (func $dummy8621) + (func $dummy8622) + (func $dummy8623) + (func $dummy8624) + (func $dummy8625) + (func $dummy8626) + (func $dummy8627) + (func $dummy8628) + (func $dummy8629) + (func $dummy8630) + (func $dummy8631) + (func $dummy8632) + (func $dummy8633) + (func $dummy8634) + (func $dummy8635) + (func $dummy8636) + (func $dummy8637) + (func $dummy8638) + (func $dummy8639) + (func $dummy8640) + (func $dummy8641) + (func $dummy8642) + (func $dummy8643) + (func $dummy8644) + (func $dummy8645) + (func $dummy8646) + (func $dummy8647) + (func $dummy8648) + (func $dummy8649) + (func $dummy8650) + (func $dummy8651) + (func $dummy8652) + (func $dummy8653) + (func $dummy8654) + (func $dummy8655) + (func $dummy8656) + (func $dummy8657) + (func $dummy8658) + (func $dummy8659) + (func $dummy8660) + (func $dummy8661) + (func $dummy8662) + (func $dummy8663) + (func $dummy8664) + (func $dummy8665) + (func $dummy8666) + (func $dummy8667) + (func $dummy8668) + (func $dummy8669) + (func $dummy8670) + (func $dummy8671) + (func $dummy8672) + (func $dummy8673) + (func $dummy8674) + (func $dummy8675) + (func $dummy8676) + (func $dummy8677) + (func $dummy8678) + (func $dummy8679) + (func $dummy8680) + (func $dummy8681) + (func $dummy8682) + (func $dummy8683) + (func $dummy8684) + (func $dummy8685) + (func $dummy8686) + (func $dummy8687) + (func $dummy8688) + (func $dummy8689) + (func $dummy8690) + (func $dummy8691) + (func $dummy8692) + (func $dummy8693) + (func $dummy8694) + (func $dummy8695) + (func $dummy8696) + (func $dummy8697) + (func $dummy8698) + (func $dummy8699) + (func $dummy8700) + (func $dummy8701) + (func $dummy8702) + (func $dummy8703) + (func $dummy8704) + (func $dummy8705) + (func $dummy8706) + (func $dummy8707) + (func $dummy8708) + (func $dummy8709) + (func $dummy8710) + (func $dummy8711) + (func $dummy8712) + (func $dummy8713) + (func $dummy8714) + (func $dummy8715) + (func $dummy8716) + (func $dummy8717) + (func $dummy8718) + (func $dummy8719) + (func $dummy8720) + (func $dummy8721) + (func $dummy8722) + (func $dummy8723) + (func $dummy8724) + (func $dummy8725) + (func $dummy8726) + (func $dummy8727) + (func $dummy8728) + (func $dummy8729) + (func $dummy8730) + (func $dummy8731) + (func $dummy8732) + (func $dummy8733) + (func $dummy8734) + (func $dummy8735) + (func $dummy8736) + (func $dummy8737) + (func $dummy8738) + (func $dummy8739) + (func $dummy8740) + (func $dummy8741) + (func $dummy8742) + (func $dummy8743) + (func $dummy8744) + (func $dummy8745) + (func $dummy8746) + (func $dummy8747) + (func $dummy8748) + (func $dummy8749) + (func $dummy8750) + (func $dummy8751) + (func $dummy8752) + (func $dummy8753) + (func $dummy8754) + (func $dummy8755) + (func $dummy8756) + (func $dummy8757) + (func $dummy8758) + (func $dummy8759) + (func $dummy8760) + (func $dummy8761) + (func $dummy8762) + (func $dummy8763) + (func $dummy8764) + (func $dummy8765) + (func $dummy8766) + (func $dummy8767) + (func $dummy8768) + (func $dummy8769) + (func $dummy8770) + (func $dummy8771) + (func $dummy8772) + (func $dummy8773) + (func $dummy8774) + (func $dummy8775) + (func $dummy8776) + (func $dummy8777) + (func $dummy8778) + (func $dummy8779) + (func $dummy8780) + (func $dummy8781) + (func $dummy8782) + (func $dummy8783) + (func $dummy8784) + (func $dummy8785) + (func $dummy8786) + (func $dummy8787) + (func $dummy8788) + (func $dummy8789) + (func $dummy8790) + (func $dummy8791) + (func $dummy8792) + (func $dummy8793) + (func $dummy8794) + (func $dummy8795) + (func $dummy8796) + (func $dummy8797) + (func $dummy8798) + (func $dummy8799) + (func $dummy8800) + (func $dummy8801) + (func $dummy8802) + (func $dummy8803) + (func $dummy8804) + (func $dummy8805) + (func $dummy8806) + (func $dummy8807) + (func $dummy8808) + (func $dummy8809) + (func $dummy8810) + (func $dummy8811) + (func $dummy8812) + (func $dummy8813) + (func $dummy8814) + (func $dummy8815) + (func $dummy8816) + (func $dummy8817) + (func $dummy8818) + (func $dummy8819) + (func $dummy8820) + (func $dummy8821) + (func $dummy8822) + (func $dummy8823) + (func $dummy8824) + (func $dummy8825) + (func $dummy8826) + (func $dummy8827) + (func $dummy8828) + (func $dummy8829) + (func $dummy8830) + (func $dummy8831) + (func $dummy8832) + (func $dummy8833) + (func $dummy8834) + (func $dummy8835) + (func $dummy8836) + (func $dummy8837) + (func $dummy8838) + (func $dummy8839) + (func $dummy8840) + (func $dummy8841) + (func $dummy8842) + (func $dummy8843) + (func $dummy8844) + (func $dummy8845) + (func $dummy8846) + (func $dummy8847) + (func $dummy8848) + (func $dummy8849) + (func $dummy8850) + (func $dummy8851) + (func $dummy8852) + (func $dummy8853) + (func $dummy8854) + (func $dummy8855) + (func $dummy8856) + (func $dummy8857) + (func $dummy8858) + (func $dummy8859) + (func $dummy8860) + (func $dummy8861) + (func $dummy8862) + (func $dummy8863) + (func $dummy8864) + (func $dummy8865) + (func $dummy8866) + (func $dummy8867) + (func $dummy8868) + (func $dummy8869) + (func $dummy8870) + (func $dummy8871) + (func $dummy8872) + (func $dummy8873) + (func $dummy8874) + (func $dummy8875) + (func $dummy8876) + (func $dummy8877) + (func $dummy8878) + (func $dummy8879) + (func $dummy8880) + (func $dummy8881) + (func $dummy8882) + (func $dummy8883) + (func $dummy8884) + (func $dummy8885) + (func $dummy8886) + (func $dummy8887) + (func $dummy8888) + (func $dummy8889) + (func $dummy8890) + (func $dummy8891) + (func $dummy8892) + (func $dummy8893) + (func $dummy8894) + (func $dummy8895) + (func $dummy8896) + (func $dummy8897) + (func $dummy8898) + (func $dummy8899) + (func $dummy8900) + (func $dummy8901) + (func $dummy8902) + (func $dummy8903) + (func $dummy8904) + (func $dummy8905) + (func $dummy8906) + (func $dummy8907) + (func $dummy8908) + (func $dummy8909) + (func $dummy8910) + (func $dummy8911) + (func $dummy8912) + (func $dummy8913) + (func $dummy8914) + (func $dummy8915) + (func $dummy8916) + (func $dummy8917) + (func $dummy8918) + (func $dummy8919) + (func $dummy8920) + (func $dummy8921) + (func $dummy8922) + (func $dummy8923) + (func $dummy8924) + (func $dummy8925) + (func $dummy8926) + (func $dummy8927) + (func $dummy8928) + (func $dummy8929) + (func $dummy8930) + (func $dummy8931) + (func $dummy8932) + (func $dummy8933) + (func $dummy8934) + (func $dummy8935) + (func $dummy8936) + (func $dummy8937) + (func $dummy8938) + (func $dummy8939) + (func $dummy8940) + (func $dummy8941) + (func $dummy8942) + (func $dummy8943) + (func $dummy8944) + (func $dummy8945) + (func $dummy8946) + (func $dummy8947) + (func $dummy8948) + (func $dummy8949) + (func $dummy8950) + (func $dummy8951) + (func $dummy8952) + (func $dummy8953) + (func $dummy8954) + (func $dummy8955) + (func $dummy8956) + (func $dummy8957) + (func $dummy8958) + (func $dummy8959) + (func $dummy8960) + (func $dummy8961) + (func $dummy8962) + (func $dummy8963) + (func $dummy8964) + (func $dummy8965) + (func $dummy8966) + (func $dummy8967) + (func $dummy8968) + (func $dummy8969) + (func $dummy8970) + (func $dummy8971) + (func $dummy8972) + (func $dummy8973) + (func $dummy8974) + (func $dummy8975) + (func $dummy8976) + (func $dummy8977) + (func $dummy8978) + (func $dummy8979) + (func $dummy8980) + (func $dummy8981) + (func $dummy8982) + (func $dummy8983) + (func $dummy8984) + (func $dummy8985) + (func $dummy8986) + (func $dummy8987) + (func $dummy8988) + (func $dummy8989) + (func $dummy8990) + (func $dummy8991) + (func $dummy8992) + (func $dummy8993) + (func $dummy8994) + (func $dummy8995) + (func $dummy8996) + (func $dummy8997) + (func $dummy8998) + (func $dummy8999) + (func $dummy9000) + (func $dummy9001) + (func $dummy9002) + (func $dummy9003) + (func $dummy9004) + (func $dummy9005) + (func $dummy9006) + (func $dummy9007) + (func $dummy9008) + (func $dummy9009) + (func $dummy9010) + (func $dummy9011) + (func $dummy9012) + (func $dummy9013) + (func $dummy9014) + (func $dummy9015) + (func $dummy9016) + (func $dummy9017) + (func $dummy9018) + (func $dummy9019) + (func $dummy9020) + (func $dummy9021) + (func $dummy9022) + (func $dummy9023) + (func $dummy9024) + (func $dummy9025) + (func $dummy9026) + (func $dummy9027) + (func $dummy9028) + (func $dummy9029) + (func $dummy9030) + (func $dummy9031) + (func $dummy9032) + (func $dummy9033) + (func $dummy9034) + (func $dummy9035) + (func $dummy9036) + (func $dummy9037) + (func $dummy9038) + (func $dummy9039) + (func $dummy9040) + (func $dummy9041) + (func $dummy9042) + (func $dummy9043) + (func $dummy9044) + (func $dummy9045) + (func $dummy9046) + (func $dummy9047) + (func $dummy9048) + (func $dummy9049) + (func $dummy9050) + (func $dummy9051) + (func $dummy9052) + (func $dummy9053) + (func $dummy9054) + (func $dummy9055) + (func $dummy9056) + (func $dummy9057) + (func $dummy9058) + (func $dummy9059) + (func $dummy9060) + (func $dummy9061) + (func $dummy9062) + (func $dummy9063) + (func $dummy9064) + (func $dummy9065) + (func $dummy9066) + (func $dummy9067) + (func $dummy9068) + (func $dummy9069) + (func $dummy9070) + (func $dummy9071) + (func $dummy9072) + (func $dummy9073) + (func $dummy9074) + (func $dummy9075) + (func $dummy9076) + (func $dummy9077) + (func $dummy9078) + (func $dummy9079) + (func $dummy9080) + (func $dummy9081) + (func $dummy9082) + (func $dummy9083) + (func $dummy9084) + (func $dummy9085) + (func $dummy9086) + (func $dummy9087) + (func $dummy9088) + (func $dummy9089) + (func $dummy9090) + (func $dummy9091) + (func $dummy9092) + (func $dummy9093) + (func $dummy9094) + (func $dummy9095) + (func $dummy9096) + (func $dummy9097) + (func $dummy9098) + (func $dummy9099) + (func $dummy9100) + (func $dummy9101) + (func $dummy9102) + (func $dummy9103) + (func $dummy9104) + (func $dummy9105) + (func $dummy9106) + (func $dummy9107) + (func $dummy9108) + (func $dummy9109) + (func $dummy9110) + (func $dummy9111) + (func $dummy9112) + (func $dummy9113) + (func $dummy9114) + (func $dummy9115) + (func $dummy9116) + (func $dummy9117) + (func $dummy9118) + (func $dummy9119) + (func $dummy9120) + (func $dummy9121) + (func $dummy9122) + (func $dummy9123) + (func $dummy9124) + (func $dummy9125) + (func $dummy9126) + (func $dummy9127) + (func $dummy9128) + (func $dummy9129) + (func $dummy9130) + (func $dummy9131) + (func $dummy9132) + (func $dummy9133) + (func $dummy9134) + (func $dummy9135) + (func $dummy9136) + (func $dummy9137) + (func $dummy9138) + (func $dummy9139) + (func $dummy9140) + (func $dummy9141) + (func $dummy9142) + (func $dummy9143) + (func $dummy9144) + (func $dummy9145) + (func $dummy9146) + (func $dummy9147) + (func $dummy9148) + (func $dummy9149) + (func $dummy9150) + (func $dummy9151) + (func $dummy9152) + (func $dummy9153) + (func $dummy9154) + (func $dummy9155) + (func $dummy9156) + (func $dummy9157) + (func $dummy9158) + (func $dummy9159) + (func $dummy9160) + (func $dummy9161) + (func $dummy9162) + (func $dummy9163) + (func $dummy9164) + (func $dummy9165) + (func $dummy9166) + (func $dummy9167) + (func $dummy9168) + (func $dummy9169) + (func $dummy9170) + (func $dummy9171) + (func $dummy9172) + (func $dummy9173) + (func $dummy9174) + (func $dummy9175) + (func $dummy9176) + (func $dummy9177) + (func $dummy9178) + (func $dummy9179) + (func $dummy9180) + (func $dummy9181) + (func $dummy9182) + (func $dummy9183) + (func $dummy9184) + (func $dummy9185) + (func $dummy9186) + (func $dummy9187) + (func $dummy9188) + (func $dummy9189) + (func $dummy9190) + (func $dummy9191) + (func $dummy9192) + (func $dummy9193) + (func $dummy9194) + (func $dummy9195) + (func $dummy9196) + (func $dummy9197) + (func $dummy9198) + (func $dummy9199) + (func $dummy9200) + (func $dummy9201) + (func $dummy9202) + (func $dummy9203) + (func $dummy9204) + (func $dummy9205) + (func $dummy9206) + (func $dummy9207) + (func $dummy9208) + (func $dummy9209) + (func $dummy9210) + (func $dummy9211) + (func $dummy9212) + (func $dummy9213) + (func $dummy9214) + (func $dummy9215) + (func $dummy9216) + (func $dummy9217) + (func $dummy9218) + (func $dummy9219) + (func $dummy9220) + (func $dummy9221) + (func $dummy9222) + (func $dummy9223) + (func $dummy9224) + (func $dummy9225) + (func $dummy9226) + (func $dummy9227) + (func $dummy9228) + (func $dummy9229) + (func $dummy9230) + (func $dummy9231) + (func $dummy9232) + (func $dummy9233) + (func $dummy9234) + (func $dummy9235) + (func $dummy9236) + (func $dummy9237) + (func $dummy9238) + (func $dummy9239) + (func $dummy9240) + (func $dummy9241) + (func $dummy9242) + (func $dummy9243) + (func $dummy9244) + (func $dummy9245) + (func $dummy9246) + (func $dummy9247) + (func $dummy9248) + (func $dummy9249) + (func $dummy9250) + (func $dummy9251) + (func $dummy9252) + (func $dummy9253) + (func $dummy9254) + (func $dummy9255) + (func $dummy9256) + (func $dummy9257) + (func $dummy9258) + (func $dummy9259) + (func $dummy9260) + (func $dummy9261) + (func $dummy9262) + (func $dummy9263) + (func $dummy9264) + (func $dummy9265) + (func $dummy9266) + (func $dummy9267) + (func $dummy9268) + (func $dummy9269) + (func $dummy9270) + (func $dummy9271) + (func $dummy9272) + (func $dummy9273) + (func $dummy9274) + (func $dummy9275) + (func $dummy9276) + (func $dummy9277) + (func $dummy9278) + (func $dummy9279) + (func $dummy9280) + (func $dummy9281) + (func $dummy9282) + (func $dummy9283) + (func $dummy9284) + (func $dummy9285) + (func $dummy9286) + (func $dummy9287) + (func $dummy9288) + (func $dummy9289) + (func $dummy9290) + (func $dummy9291) + (func $dummy9292) + (func $dummy9293) + (func $dummy9294) + (func $dummy9295) + (func $dummy9296) + (func $dummy9297) + (func $dummy9298) + (func $dummy9299) + (func $dummy9300) + (func $dummy9301) + (func $dummy9302) + (func $dummy9303) + (func $dummy9304) + (func $dummy9305) + (func $dummy9306) + (func $dummy9307) + (func $dummy9308) + (func $dummy9309) + (func $dummy9310) + (func $dummy9311) + (func $dummy9312) + (func $dummy9313) + (func $dummy9314) + (func $dummy9315) + (func $dummy9316) + (func $dummy9317) + (func $dummy9318) + (func $dummy9319) + (func $dummy9320) + (func $dummy9321) + (func $dummy9322) + (func $dummy9323) + (func $dummy9324) + (func $dummy9325) + (func $dummy9326) + (func $dummy9327) + (func $dummy9328) + (func $dummy9329) + (func $dummy9330) + (func $dummy9331) + (func $dummy9332) + (func $dummy9333) + (func $dummy9334) + (func $dummy9335) + (func $dummy9336) + (func $dummy9337) + (func $dummy9338) + (func $dummy9339) + (func $dummy9340) + (func $dummy9341) + (func $dummy9342) + (func $dummy9343) + (func $dummy9344) + (func $dummy9345) + (func $dummy9346) + (func $dummy9347) + (func $dummy9348) + (func $dummy9349) + (func $dummy9350) + (func $dummy9351) + (func $dummy9352) + (func $dummy9353) + (func $dummy9354) + (func $dummy9355) + (func $dummy9356) + (func $dummy9357) + (func $dummy9358) + (func $dummy9359) + (func $dummy9360) + (func $dummy9361) + (func $dummy9362) + (func $dummy9363) + (func $dummy9364) + (func $dummy9365) + (func $dummy9366) + (func $dummy9367) + (func $dummy9368) + (func $dummy9369) + (func $dummy9370) + (func $dummy9371) + (func $dummy9372) + (func $dummy9373) + (func $dummy9374) + (func $dummy9375) + (func $dummy9376) + (func $dummy9377) + (func $dummy9378) + (func $dummy9379) + (func $dummy9380) + (func $dummy9381) + (func $dummy9382) + (func $dummy9383) + (func $dummy9384) + (func $dummy9385) + (func $dummy9386) + (func $dummy9387) + (func $dummy9388) + (func $dummy9389) + (func $dummy9390) + (func $dummy9391) + (func $dummy9392) + (func $dummy9393) + (func $dummy9394) + (func $dummy9395) + (func $dummy9396) + (func $dummy9397) + (func $dummy9398) + (func $dummy9399) + (func $dummy9400) + (func $dummy9401) + (func $dummy9402) + (func $dummy9403) + (func $dummy9404) + (func $dummy9405) + (func $dummy9406) + (func $dummy9407) + (func $dummy9408) + (func $dummy9409) + (func $dummy9410) + (func $dummy9411) + (func $dummy9412) + (func $dummy9413) + (func $dummy9414) + (func $dummy9415) + (func $dummy9416) + (func $dummy9417) + (func $dummy9418) + (func $dummy9419) + (func $dummy9420) + (func $dummy9421) + (func $dummy9422) + (func $dummy9423) + (func $dummy9424) + (func $dummy9425) + (func $dummy9426) + (func $dummy9427) + (func $dummy9428) + (func $dummy9429) + (func $dummy9430) + (func $dummy9431) + (func $dummy9432) + (func $dummy9433) + (func $dummy9434) + (func $dummy9435) + (func $dummy9436) + (func $dummy9437) + (func $dummy9438) + (func $dummy9439) + (func $dummy9440) + (func $dummy9441) + (func $dummy9442) + (func $dummy9443) + (func $dummy9444) + (func $dummy9445) + (func $dummy9446) + (func $dummy9447) + (func $dummy9448) + (func $dummy9449) + (func $dummy9450) + (func $dummy9451) + (func $dummy9452) + (func $dummy9453) + (func $dummy9454) + (func $dummy9455) + (func $dummy9456) + (func $dummy9457) + (func $dummy9458) + (func $dummy9459) + (func $dummy9460) + (func $dummy9461) + (func $dummy9462) + (func $dummy9463) + (func $dummy9464) + (func $dummy9465) + (func $dummy9466) + (func $dummy9467) + (func $dummy9468) + (func $dummy9469) + (func $dummy9470) + (func $dummy9471) + (func $dummy9472) + (func $dummy9473) + (func $dummy9474) + (func $dummy9475) + (func $dummy9476) + (func $dummy9477) + (func $dummy9478) + (func $dummy9479) + (func $dummy9480) + (func $dummy9481) + (func $dummy9482) + (func $dummy9483) + (func $dummy9484) + (func $dummy9485) + (func $dummy9486) + (func $dummy9487) + (func $dummy9488) + (func $dummy9489) + (func $dummy9490) + (func $dummy9491) + (func $dummy9492) + (func $dummy9493) + (func $dummy9494) + (func $dummy9495) + (func $dummy9496) + (func $dummy9497) + (func $dummy9498) + (func $dummy9499) + (func $dummy9500) + (func $dummy9501) + (func $dummy9502) + (func $dummy9503) + (func $dummy9504) + (func $dummy9505) + (func $dummy9506) + (func $dummy9507) + (func $dummy9508) + (func $dummy9509) + (func $dummy9510) + (func $dummy9511) + (func $dummy9512) + (func $dummy9513) + (func $dummy9514) + (func $dummy9515) + (func $dummy9516) + (func $dummy9517) + (func $dummy9518) + (func $dummy9519) + (func $dummy9520) + (func $dummy9521) + (func $dummy9522) + (func $dummy9523) + (func $dummy9524) + (func $dummy9525) + (func $dummy9526) + (func $dummy9527) + (func $dummy9528) + (func $dummy9529) + (func $dummy9530) + (func $dummy9531) + (func $dummy9532) + (func $dummy9533) + (func $dummy9534) + (func $dummy9535) + (func $dummy9536) + (func $dummy9537) + (func $dummy9538) + (func $dummy9539) + (func $dummy9540) + (func $dummy9541) + (func $dummy9542) + (func $dummy9543) + (func $dummy9544) + (func $dummy9545) + (func $dummy9546) + (func $dummy9547) + (func $dummy9548) + (func $dummy9549) + (func $dummy9550) + (func $dummy9551) + (func $dummy9552) + (func $dummy9553) + (func $dummy9554) + (func $dummy9555) + (func $dummy9556) + (func $dummy9557) + (func $dummy9558) + (func $dummy9559) + (func $dummy9560) + (func $dummy9561) + (func $dummy9562) + (func $dummy9563) + (func $dummy9564) + (func $dummy9565) + (func $dummy9566) + (func $dummy9567) + (func $dummy9568) + (func $dummy9569) + (func $dummy9570) + (func $dummy9571) + (func $dummy9572) + (func $dummy9573) + (func $dummy9574) + (func $dummy9575) + (func $dummy9576) + (func $dummy9577) + (func $dummy9578) + (func $dummy9579) + (func $dummy9580) + (func $dummy9581) + (func $dummy9582) + (func $dummy9583) + (func $dummy9584) + (func $dummy9585) + (func $dummy9586) + (func $dummy9587) + (func $dummy9588) + (func $dummy9589) + (func $dummy9590) + (func $dummy9591) + (func $dummy9592) + (func $dummy9593) + (func $dummy9594) + (func $dummy9595) + (func $dummy9596) + (func $dummy9597) + (func $dummy9598) + (func $dummy9599) + (func $dummy9600) + (func $dummy9601) + (func $dummy9602) + (func $dummy9603) + (func $dummy9604) + (func $dummy9605) + (func $dummy9606) + (func $dummy9607) + (func $dummy9608) + (func $dummy9609) + (func $dummy9610) + (func $dummy9611) + (func $dummy9612) + (func $dummy9613) + (func $dummy9614) + (func $dummy9615) + (func $dummy9616) + (func $dummy9617) + (func $dummy9618) + (func $dummy9619) + (func $dummy9620) + (func $dummy9621) + (func $dummy9622) + (func $dummy9623) + (func $dummy9624) + (func $dummy9625) + (func $dummy9626) + (func $dummy9627) + (func $dummy9628) + (func $dummy9629) + (func $dummy9630) + (func $dummy9631) + (func $dummy9632) + (func $dummy9633) + (func $dummy9634) + (func $dummy9635) + (func $dummy9636) + (func $dummy9637) + (func $dummy9638) + (func $dummy9639) + (func $dummy9640) + (func $dummy9641) + (func $dummy9642) + (func $dummy9643) + (func $dummy9644) + (func $dummy9645) + (func $dummy9646) + (func $dummy9647) + (func $dummy9648) + (func $dummy9649) + (func $dummy9650) + (func $dummy9651) + (func $dummy9652) + (func $dummy9653) + (func $dummy9654) + (func $dummy9655) + (func $dummy9656) + (func $dummy9657) + (func $dummy9658) + (func $dummy9659) + (func $dummy9660) + (func $dummy9661) + (func $dummy9662) + (func $dummy9663) + (func $dummy9664) + (func $dummy9665) + (func $dummy9666) + (func $dummy9667) + (func $dummy9668) + (func $dummy9669) + (func $dummy9670) + (func $dummy9671) + (func $dummy9672) + (func $dummy9673) + (func $dummy9674) + (func $dummy9675) + (func $dummy9676) + (func $dummy9677) + (func $dummy9678) + (func $dummy9679) + (func $dummy9680) + (func $dummy9681) + (func $dummy9682) + (func $dummy9683) + (func $dummy9684) + (func $dummy9685) + (func $dummy9686) + (func $dummy9687) + (func $dummy9688) + (func $dummy9689) + (func $dummy9690) + (func $dummy9691) + (func $dummy9692) + (func $dummy9693) + (func $dummy9694) + (func $dummy9695) + (func $dummy9696) + (func $dummy9697) + (func $dummy9698) + (func $dummy9699) + (func $dummy9700) + (func $dummy9701) + (func $dummy9702) + (func $dummy9703) + (func $dummy9704) + (func $dummy9705) + (func $dummy9706) + (func $dummy9707) + (func $dummy9708) + (func $dummy9709) + (func $dummy9710) + (func $dummy9711) + (func $dummy9712) + (func $dummy9713) + (func $dummy9714) + (func $dummy9715) + (func $dummy9716) + (func $dummy9717) + (func $dummy9718) + (func $dummy9719) + (func $dummy9720) + (func $dummy9721) + (func $dummy9722) + (func $dummy9723) + (func $dummy9724) + (func $dummy9725) + (func $dummy9726) + (func $dummy9727) + (func $dummy9728) + (func $dummy9729) + (func $dummy9730) + (func $dummy9731) + (func $dummy9732) + (func $dummy9733) + (func $dummy9734) + (func $dummy9735) + (func $dummy9736) + (func $dummy9737) + (func $dummy9738) + (func $dummy9739) + (func $dummy9740) + (func $dummy9741) + (func $dummy9742) + (func $dummy9743) + (func $dummy9744) + (func $dummy9745) + (func $dummy9746) + (func $dummy9747) + (func $dummy9748) + (func $dummy9749) + (func $dummy9750) + (func $dummy9751) + (func $dummy9752) + (func $dummy9753) + (func $dummy9754) + (func $dummy9755) + (func $dummy9756) + (func $dummy9757) + (func $dummy9758) + (func $dummy9759) + (func $dummy9760) + (func $dummy9761) + (func $dummy9762) + (func $dummy9763) + (func $dummy9764) + (func $dummy9765) + (func $dummy9766) + (func $dummy9767) + (func $dummy9768) + (func $dummy9769) + (func $dummy9770) + (func $dummy9771) + (func $dummy9772) + (func $dummy9773) + (func $dummy9774) + (func $dummy9775) + (func $dummy9776) + (func $dummy9777) + (func $dummy9778) + (func $dummy9779) + (func $dummy9780) + (func $dummy9781) + (func $dummy9782) + (func $dummy9783) + (func $dummy9784) + (func $dummy9785) + (func $dummy9786) + (func $dummy9787) + (func $dummy9788) + (func $dummy9789) + (func $dummy9790) + (func $dummy9791) + (func $dummy9792) + (func $dummy9793) + (func $dummy9794) + (func $dummy9795) + (func $dummy9796) + (func $dummy9797) + (func $dummy9798) + (func $dummy9799) + (func $dummy9800) + (func $dummy9801) + (func $dummy9802) + (func $dummy9803) + (func $dummy9804) + (func $dummy9805) + (func $dummy9806) + (func $dummy9807) + (func $dummy9808) + (func $dummy9809) + (func $dummy9810) + (func $dummy9811) + (func $dummy9812) + (func $dummy9813) + (func $dummy9814) + (func $dummy9815) + (func $dummy9816) + (func $dummy9817) + (func $dummy9818) + (func $dummy9819) + (func $dummy9820) + (func $dummy9821) + (func $dummy9822) + (func $dummy9823) + (func $dummy9824) + (func $dummy9825) + (func $dummy9826) + (func $dummy9827) + (func $dummy9828) + (func $dummy9829) + (func $dummy9830) + (func $dummy9831) + (func $dummy9832) + (func $dummy9833) + (func $dummy9834) + (func $dummy9835) + (func $dummy9836) + (func $dummy9837) + (func $dummy9838) + (func $dummy9839) + (func $dummy9840) + (func $dummy9841) + (func $dummy9842) + (func $dummy9843) + (func $dummy9844) + (func $dummy9845) + (func $dummy9846) + (func $dummy9847) + (func $dummy9848) + (func $dummy9849) + (func $dummy9850) + (func $dummy9851) + (func $dummy9852) + (func $dummy9853) + (func $dummy9854) + (func $dummy9855) + (func $dummy9856) + (func $dummy9857) + (func $dummy9858) + (func $dummy9859) + (func $dummy9860) + (func $dummy9861) + (func $dummy9862) + (func $dummy9863) + (func $dummy9864) + (func $dummy9865) + (func $dummy9866) + (func $dummy9867) + (func $dummy9868) + (func $dummy9869) + (func $dummy9870) + (func $dummy9871) + (func $dummy9872) + (func $dummy9873) + (func $dummy9874) + (func $dummy9875) + (func $dummy9876) + (func $dummy9877) + (func $dummy9878) + (func $dummy9879) + (func $dummy9880) + (func $dummy9881) + (func $dummy9882) + (func $dummy9883) + (func $dummy9884) + (func $dummy9885) + (func $dummy9886) + (func $dummy9887) + (func $dummy9888) + (func $dummy9889) + (func $dummy9890) + (func $dummy9891) + (func $dummy9892) + (func $dummy9893) + (func $dummy9894) + (func $dummy9895) + (func $dummy9896) + (func $dummy9897) + (func $dummy9898) + (func $dummy9899) + (func $dummy9900) + (func $dummy9901) + (func $dummy9902) + (func $dummy9903) + (func $dummy9904) + (func $dummy9905) + (func $dummy9906) + (func $dummy9907) + (func $dummy9908) + (func $dummy9909) + (func $dummy9910) + (func $dummy9911) + (func $dummy9912) + (func $dummy9913) + (func $dummy9914) + (func $dummy9915) + (func $dummy9916) + (func $dummy9917) + (func $dummy9918) + (func $dummy9919) + (func $dummy9920) + (func $dummy9921) + (func $dummy9922) + (func $dummy9923) + (func $dummy9924) + (func $dummy9925) + (func $dummy9926) + (func $dummy9927) + (func $dummy9928) + (func $dummy9929) + (func $dummy9930) + (func $dummy9931) + (func $dummy9932) + (func $dummy9933) + (func $dummy9934) + (func $dummy9935) + (func $dummy9936) + (func $dummy9937) + (func $dummy9938) + (func $dummy9939) + (func $dummy9940) + (func $dummy9941) + (func $dummy9942) + (func $dummy9943) + (func $dummy9944) + (func $dummy9945) + (func $dummy9946) + (func $dummy9947) + (func $dummy9948) + (func $dummy9949) + (func $dummy9950) + (func $dummy9951) + (func $dummy9952) + (func $dummy9953) + (func $dummy9954) + (func $dummy9955) + (func $dummy9956) + (func $dummy9957) + (func $dummy9958) + (func $dummy9959) + (func $dummy9960) + (func $dummy9961) + (func $dummy9962) + (func $dummy9963) + (func $dummy9964) + (func $dummy9965) + (func $dummy9966) + (func $dummy9967) + (func $dummy9968) + (func $dummy9969) + (func $dummy9970) + (func $dummy9971) + (func $dummy9972) + (func $dummy9973) + (func $dummy9974) + (func $dummy9975) + (func $dummy9976) + (func $dummy9977) + (func $dummy9978) + (func $dummy9979) + (func $dummy9980) + (func $dummy9981) + (func $dummy9982) + (func $dummy9983) + (func $dummy9984) + (func $dummy9985) + (func $dummy9986) + (func $dummy9987) + (func $dummy9988) + (func $dummy9989) + (func $dummy9990) + (func $dummy9991) + (func $dummy9992) + (func $dummy9993) + (func $dummy9994) + (func $dummy9995) + (func $dummy9996) + (func $dummy9997) + (func $dummy9998) + (func $dummy9999) + (func $dummy10000) + (func $dummy10001) + (func $dummy10002) + (func $dummy10003) + (func $dummy10004) + (func $dummy10005) + (func $dummy10006) + (func $dummy10007) + (func $dummy10008) + (func $dummy10009) + (func $dummy10010) + (func $dummy10011) + (func $dummy10012) + (func $dummy10013) + (func $dummy10014) + (func $dummy10015) + (func $dummy10016) + (func $dummy10017) + (func $dummy10018) + (func $dummy10019) + (func $dummy10020) + (func $dummy10021) + (func $dummy10022) + (func $dummy10023) + (func $dummy10024) + (func $dummy10025) + (func $dummy10026) + (func $dummy10027) + (func $dummy10028) + (func $dummy10029) + (func $dummy10030) + (func $dummy10031) + (func $dummy10032) + (func $dummy10033) + (func $dummy10034) + (func $dummy10035) + (func $dummy10036) + (func $dummy10037) + (func $dummy10038) + (func $dummy10039) + (func $dummy10040) + (func $dummy10041) + (func $dummy10042) + (func $dummy10043) + (func $dummy10044) + (func $dummy10045) + (func $dummy10046) + (func $dummy10047) + (func $dummy10048) + (func $dummy10049) + (func $dummy10050) + (func $dummy10051) + (func $dummy10052) + (func $dummy10053) + (func $dummy10054) + (func $dummy10055) + (func $dummy10056) + (func $dummy10057) + (func $dummy10058) + (func $dummy10059) + (func $dummy10060) + (func $dummy10061) + (func $dummy10062) + (func $dummy10063) + (func $dummy10064) + (func $dummy10065) + (func $dummy10066) + (func $dummy10067) + (func $dummy10068) + (func $dummy10069) + (func $dummy10070) + (func $dummy10071) + (func $dummy10072) + (func $dummy10073) + (func $dummy10074) + (func $dummy10075) + (func $dummy10076) + (func $dummy10077) + (func $dummy10078) + (func $dummy10079) + (func $dummy10080) + (func $dummy10081) + (func $dummy10082) + (func $dummy10083) + (func $dummy10084) + (func $dummy10085) + (func $dummy10086) + (func $dummy10087) + (func $dummy10088) + (func $dummy10089) + (func $dummy10090) + (func $dummy10091) + (func $dummy10092) + (func $dummy10093) + (func $dummy10094) + (func $dummy10095) + (func $dummy10096) + (func $dummy10097) + (func $dummy10098) + (func $dummy10099) + (func $dummy10100) + (func $dummy10101) + (func $dummy10102) + (func $dummy10103) + (func $dummy10104) + (func $dummy10105) + (func $dummy10106) + (func $dummy10107) + (func $dummy10108) + (func $dummy10109) + (func $dummy10110) + (func $dummy10111) + (func $dummy10112) + (func $dummy10113) + (func $dummy10114) + (func $dummy10115) + (func $dummy10116) + (func $dummy10117) + (func $dummy10118) + (func $dummy10119) + (func $dummy10120) + (func $dummy10121) + (func $dummy10122) + (func $dummy10123) + (func $dummy10124) + (func $dummy10125) + (func $dummy10126) + (func $dummy10127) + (func $dummy10128) + (func $dummy10129) + (func $dummy10130) + (func $dummy10131) + (func $dummy10132) + (func $dummy10133) + (func $dummy10134) + (func $dummy10135) + (func $dummy10136) + (func $dummy10137) + (func $dummy10138) + (func $dummy10139) + (func $dummy10140) + (func $dummy10141) + (func $dummy10142) + (func $dummy10143) + (func $dummy10144) + (func $dummy10145) + (func $dummy10146) + (func $dummy10147) + (func $dummy10148) + (func $dummy10149) + (func $dummy10150) + (func $dummy10151) + (func $dummy10152) + (func $dummy10153) + (func $dummy10154) + (func $dummy10155) + (func $dummy10156) + (func $dummy10157) + (func $dummy10158) + (func $dummy10159) + (func $dummy10160) + (func $dummy10161) + (func $dummy10162) + (func $dummy10163) + (func $dummy10164) + (func $dummy10165) + (func $dummy10166) + (func $dummy10167) + (func $dummy10168) + (func $dummy10169) + (func $dummy10170) + (func $dummy10171) + (func $dummy10172) + (func $dummy10173) + (func $dummy10174) + (func $dummy10175) + (func $dummy10176) + (func $dummy10177) + (func $dummy10178) + (func $dummy10179) + (func $dummy10180) + (func $dummy10181) + (func $dummy10182) + (func $dummy10183) + (func $dummy10184) + (func $dummy10185) + (func $dummy10186) + (func $dummy10187) + (func $dummy10188) + (func $dummy10189) + (func $dummy10190) + (func $dummy10191) + (func $dummy10192) + (func $dummy10193) + (func $dummy10194) + (func $dummy10195) + (func $dummy10196) + (func $dummy10197) + (func $dummy10198) + (func $dummy10199) + (func $dummy10200) + (func $dummy10201) + (func $dummy10202) + (func $dummy10203) + (func $dummy10204) + (func $dummy10205) + (func $dummy10206) + (func $dummy10207) + (func $dummy10208) + (func $dummy10209) + (func $dummy10210) + (func $dummy10211) + (func $dummy10212) + (func $dummy10213) + (func $dummy10214) + (func $dummy10215) + (func $dummy10216) + (func $dummy10217) + (func $dummy10218) + (func $dummy10219) + (func $dummy10220) + (func $dummy10221) + (func $dummy10222) + (func $dummy10223) + (func $dummy10224) + (func $dummy10225) + (func $dummy10226) + (func $dummy10227) + (func $dummy10228) + (func $dummy10229) + (func $dummy10230) + (func $dummy10231) + (func $dummy10232) + (func $dummy10233) + (func $dummy10234) + (func $dummy10235) + (func $dummy10236) + (func $dummy10237) + (func $dummy10238) + (func $dummy10239) + (func $dummy10240) + (func $dummy10241) + (func $dummy10242) + (func $dummy10243) + (func $dummy10244) + (func $dummy10245) + (func $dummy10246) + (func $dummy10247) + (func $dummy10248) + (func $dummy10249) + (func $dummy10250) + (func $dummy10251) + (func $dummy10252) + (func $dummy10253) + (func $dummy10254) + (func $dummy10255) + (func $dummy10256) + (func $dummy10257) + (func $dummy10258) + (func $dummy10259) + (func $dummy10260) + (func $dummy10261) + (func $dummy10262) + (func $dummy10263) + (func $dummy10264) + (func $dummy10265) + (func $dummy10266) + (func $dummy10267) + (func $dummy10268) + (func $dummy10269) + (func $dummy10270) + (func $dummy10271) + (func $dummy10272) + (func $dummy10273) + (func $dummy10274) + (func $dummy10275) + (func $dummy10276) + (func $dummy10277) + (func $dummy10278) + (func $dummy10279) + (func $dummy10280) + (func $dummy10281) + (func $dummy10282) + (func $dummy10283) + (func $dummy10284) + (func $dummy10285) + (func $dummy10286) + (func $dummy10287) + (func $dummy10288) + (func $dummy10289) + (func $dummy10290) + (func $dummy10291) + (func $dummy10292) + (func $dummy10293) + (func $dummy10294) + (func $dummy10295) + (func $dummy10296) + (func $dummy10297) + (func $dummy10298) + (func $dummy10299) + (func $dummy10300) + (func $dummy10301) + (func $dummy10302) + (func $dummy10303) + (func $dummy10304) + (func $dummy10305) + (func $dummy10306) + (func $dummy10307) + (func $dummy10308) + (func $dummy10309) + (func $dummy10310) + (func $dummy10311) + (func $dummy10312) + (func $dummy10313) + (func $dummy10314) + (func $dummy10315) + (func $dummy10316) + (func $dummy10317) + (func $dummy10318) + (func $dummy10319) + (func $dummy10320) + (func $dummy10321) + (func $dummy10322) + (func $dummy10323) + (func $dummy10324) + (func $dummy10325) + (func $dummy10326) + (func $dummy10327) + (func $dummy10328) + (func $dummy10329) + (func $dummy10330) + (func $dummy10331) + (func $dummy10332) + (func $dummy10333) + (func $dummy10334) + (func $dummy10335) + (func $dummy10336) + (func $dummy10337) + (func $dummy10338) + (func $dummy10339) + (func $dummy10340) + (func $dummy10341) + (func $dummy10342) + (func $dummy10343) + (func $dummy10344) + (func $dummy10345) + (func $dummy10346) + (func $dummy10347) + (func $dummy10348) + (func $dummy10349) + (func $dummy10350) + (func $dummy10351) + (func $dummy10352) + (func $dummy10353) + (func $dummy10354) + (func $dummy10355) + (func $dummy10356) + (func $dummy10357) + (func $dummy10358) + (func $dummy10359) + (func $dummy10360) + (func $dummy10361) + (func $dummy10362) + (func $dummy10363) + (func $dummy10364) + (func $dummy10365) + (func $dummy10366) + (func $dummy10367) + (func $dummy10368) + (func $dummy10369) + (func $dummy10370) + (func $dummy10371) + (func $dummy10372) + (func $dummy10373) + (func $dummy10374) + (func $dummy10375) + (func $dummy10376) + (func $dummy10377) + (func $dummy10378) + (func $dummy10379) + (func $dummy10380) + (func $dummy10381) + (func $dummy10382) + (func $dummy10383) + (func $dummy10384) + (func $dummy10385) + (func $dummy10386) + (func $dummy10387) + (func $dummy10388) + (func $dummy10389) + (func $dummy10390) + (func $dummy10391) + (func $dummy10392) + (func $dummy10393) + (func $dummy10394) + (func $dummy10395) + (func $dummy10396) + (func $dummy10397) + (func $dummy10398) + (func $dummy10399) + (func $dummy10400) + (func $dummy10401) + (func $dummy10402) + (func $dummy10403) + (func $dummy10404) + (func $dummy10405) + (func $dummy10406) + (func $dummy10407) + (func $dummy10408) + (func $dummy10409) + (func $dummy10410) + (func $dummy10411) + (func $dummy10412) + (func $dummy10413) + (func $dummy10414) + (func $dummy10415) + (func $dummy10416) + (func $dummy10417) + (func $dummy10418) + (func $dummy10419) + (func $dummy10420) + (func $dummy10421) + (func $dummy10422) + (func $dummy10423) + (func $dummy10424) + (func $dummy10425) + (func $dummy10426) + (func $dummy10427) + (func $dummy10428) + (func $dummy10429) + (func $dummy10430) + (func $dummy10431) + (func $dummy10432) + (func $dummy10433) + (func $dummy10434) + (func $dummy10435) + (func $dummy10436) + (func $dummy10437) + (func $dummy10438) + (func $dummy10439) + (func $dummy10440) + (func $dummy10441) + (func $dummy10442) + (func $dummy10443) + (func $dummy10444) + (func $dummy10445) + (func $dummy10446) + (func $dummy10447) + (func $dummy10448) + (func $dummy10449) + (func $dummy10450) + (func $dummy10451) + (func $dummy10452) + (func $dummy10453) + (func $dummy10454) + (func $dummy10455) + (func $dummy10456) + (func $dummy10457) + (func $dummy10458) + (func $dummy10459) + (func $dummy10460) + (func $dummy10461) + (func $dummy10462) + (func $dummy10463) + (func $dummy10464) + (func $dummy10465) + (func $dummy10466) + (func $dummy10467) + (func $dummy10468) + (func $dummy10469) + (func $dummy10470) + (func $dummy10471) + (func $dummy10472) + (func $dummy10473) + (func $dummy10474) + (func $dummy10475) + (func $dummy10476) + (func $dummy10477) + (func $dummy10478) + (func $dummy10479) + (func $dummy10480) + (func $dummy10481) + (func $dummy10482) + (func $dummy10483) + (func $dummy10484) + (func $dummy10485) + (func $dummy10486) + (func $dummy10487) + (func $dummy10488) + (func $dummy10489) + (func $dummy10490) + (func $dummy10491) + (func $dummy10492) + (func $dummy10493) + (func $dummy10494) + (func $dummy10495) + (func $dummy10496) + (func $dummy10497) + (func $dummy10498) + (func $dummy10499) + (func $dummy10500) + (func $dummy10501) + (func $dummy10502) + (func $dummy10503) + (func $dummy10504) + (func $dummy10505) + (func $dummy10506) + (func $dummy10507) + (func $dummy10508) + (func $dummy10509) + (func $dummy10510) + (func $dummy10511) + (func $dummy10512) + (func $dummy10513) + (func $dummy10514) + (func $dummy10515) + (func $dummy10516) + (func $dummy10517) + (func $dummy10518) + (func $dummy10519) + (func $dummy10520) + (func $dummy10521) + (func $dummy10522) + (func $dummy10523) + (func $dummy10524) + (func $dummy10525) + (func $dummy10526) + (func $dummy10527) + (func $dummy10528) + (func $dummy10529) + (func $dummy10530) + (func $dummy10531) + (func $dummy10532) + (func $dummy10533) + (func $dummy10534) + (func $dummy10535) + (func $dummy10536) + (func $dummy10537) + (func $dummy10538) + (func $dummy10539) + (func $dummy10540) + (func $dummy10541) + (func $dummy10542) + (func $dummy10543) + (func $dummy10544) + (func $dummy10545) + (func $dummy10546) + (func $dummy10547) + (func $dummy10548) + (func $dummy10549) + (func $dummy10550) + (func $dummy10551) + (func $dummy10552) + (func $dummy10553) + (func $dummy10554) + (func $dummy10555) + (func $dummy10556) + (func $dummy10557) + (func $dummy10558) + (func $dummy10559) + (func $dummy10560) + (func $dummy10561) + (func $dummy10562) + (func $dummy10563) + (func $dummy10564) + (func $dummy10565) + (func $dummy10566) + (func $dummy10567) + (func $dummy10568) + (func $dummy10569) + (func $dummy10570) + (func $dummy10571) + (func $dummy10572) + (func $dummy10573) + (func $dummy10574) + (func $dummy10575) + (func $dummy10576) + (func $dummy10577) + (func $dummy10578) + (func $dummy10579) + (func $dummy10580) + (func $dummy10581) + (func $dummy10582) + (func $dummy10583) + (func $dummy10584) + (func $dummy10585) + (func $dummy10586) + (func $dummy10587) + (func $dummy10588) + (func $dummy10589) + (func $dummy10590) + (func $dummy10591) + (func $dummy10592) + (func $dummy10593) + (func $dummy10594) + (func $dummy10595) + (func $dummy10596) + (func $dummy10597) + (func $dummy10598) + (func $dummy10599) + (func $dummy10600) + (func $dummy10601) + (func $dummy10602) + (func $dummy10603) + (func $dummy10604) + (func $dummy10605) + (func $dummy10606) + (func $dummy10607) + (func $dummy10608) + (func $dummy10609) + (func $dummy10610) + (func $dummy10611) + (func $dummy10612) + (func $dummy10613) + (func $dummy10614) + (func $dummy10615) + (func $dummy10616) + (func $dummy10617) + (func $dummy10618) + (func $dummy10619) + (func $dummy10620) + (func $dummy10621) + (func $dummy10622) + (func $dummy10623) + (func $dummy10624) + (func $dummy10625) + (func $dummy10626) + (func $dummy10627) + (func $dummy10628) + (func $dummy10629) + (func $dummy10630) + (func $dummy10631) + (func $dummy10632) + (func $dummy10633) + (func $dummy10634) + (func $dummy10635) + (func $dummy10636) + (func $dummy10637) + (func $dummy10638) + (func $dummy10639) + (func $dummy10640) + (func $dummy10641) + (func $dummy10642) + (func $dummy10643) + (func $dummy10644) + (func $dummy10645) + (func $dummy10646) + (func $dummy10647) + (func $dummy10648) + (func $dummy10649) + (func $dummy10650) + (func $dummy10651) + (func $dummy10652) + (func $dummy10653) + (func $dummy10654) + (func $dummy10655) + (func $dummy10656) + (func $dummy10657) + (func $dummy10658) + (func $dummy10659) + (func $dummy10660) + (func $dummy10661) + (func $dummy10662) + (func $dummy10663) + (func $dummy10664) + (func $dummy10665) + (func $dummy10666) + (func $dummy10667) + (func $dummy10668) + (func $dummy10669) + (func $dummy10670) + (func $dummy10671) + (func $dummy10672) + (func $dummy10673) + (func $dummy10674) + (func $dummy10675) + (func $dummy10676) + (func $dummy10677) + (func $dummy10678) + (func $dummy10679) + (func $dummy10680) + (func $dummy10681) + (func $dummy10682) + (func $dummy10683) + (func $dummy10684) + (func $dummy10685) + (func $dummy10686) + (func $dummy10687) + (func $dummy10688) + (func $dummy10689) + (func $dummy10690) + (func $dummy10691) + (func $dummy10692) + (func $dummy10693) + (func $dummy10694) + (func $dummy10695) + (func $dummy10696) + (func $dummy10697) + (func $dummy10698) + (func $dummy10699) + (func $dummy10700) + (func $dummy10701) + (func $dummy10702) + (func $dummy10703) + (func $dummy10704) + (func $dummy10705) + (func $dummy10706) + (func $dummy10707) + (func $dummy10708) + (func $dummy10709) + (func $dummy10710) + (func $dummy10711) + (func $dummy10712) + (func $dummy10713) + (func $dummy10714) + (func $dummy10715) + (func $dummy10716) + (func $dummy10717) + (func $dummy10718) + (func $dummy10719) + (func $dummy10720) + (func $dummy10721) + (func $dummy10722) + (func $dummy10723) + (func $dummy10724) + (func $dummy10725) + (func $dummy10726) + (func $dummy10727) + (func $dummy10728) + (func $dummy10729) + (func $dummy10730) + (func $dummy10731) + (func $dummy10732) + (func $dummy10733) + (func $dummy10734) + (func $dummy10735) + (func $dummy10736) + (func $dummy10737) + (func $dummy10738) + (func $dummy10739) + (func $dummy10740) + (func $dummy10741) + (func $dummy10742) + (func $dummy10743) + (func $dummy10744) + (func $dummy10745) + (func $dummy10746) + (func $dummy10747) + (func $dummy10748) + (func $dummy10749) + (func $dummy10750) + (func $dummy10751) + (func $dummy10752) + (func $dummy10753) + (func $dummy10754) + (func $dummy10755) + (func $dummy10756) + (func $dummy10757) + (func $dummy10758) + (func $dummy10759) + (func $dummy10760) + (func $dummy10761) + (func $dummy10762) + (func $dummy10763) + (func $dummy10764) + (func $dummy10765) + (func $dummy10766) + (func $dummy10767) + (func $dummy10768) + (func $dummy10769) + (func $dummy10770) + (func $dummy10771) + (func $dummy10772) + (func $dummy10773) + (func $dummy10774) + (func $dummy10775) + (func $dummy10776) + (func $dummy10777) + (func $dummy10778) + (func $dummy10779) + (func $dummy10780) + (func $dummy10781) + (func $dummy10782) + (func $dummy10783) + (func $dummy10784) + (func $dummy10785) + (func $dummy10786) + (func $dummy10787) + (func $dummy10788) + (func $dummy10789) + (func $dummy10790) + (func $dummy10791) + (func $dummy10792) + (func $dummy10793) + (func $dummy10794) + (func $dummy10795) + (func $dummy10796) + (func $dummy10797) + (func $dummy10798) + (func $dummy10799) + (func $dummy10800) + (func $dummy10801) + (func $dummy10802) + (func $dummy10803) + (func $dummy10804) + (func $dummy10805) + (func $dummy10806) + (func $dummy10807) + (func $dummy10808) + (func $dummy10809) + (func $dummy10810) + (func $dummy10811) + (func $dummy10812) + (func $dummy10813) + (func $dummy10814) + (func $dummy10815) + (func $dummy10816) + (func $dummy10817) + (func $dummy10818) + (func $dummy10819) + (func $dummy10820) + (func $dummy10821) + (func $dummy10822) + (func $dummy10823) + (func $dummy10824) + (func $dummy10825) + (func $dummy10826) + (func $dummy10827) + (func $dummy10828) + (func $dummy10829) + (func $dummy10830) + (func $dummy10831) + (func $dummy10832) + (func $dummy10833) + (func $dummy10834) + (func $dummy10835) + (func $dummy10836) + (func $dummy10837) + (func $dummy10838) + (func $dummy10839) + (func $dummy10840) + (func $dummy10841) + (func $dummy10842) + (func $dummy10843) + (func $dummy10844) + (func $dummy10845) + (func $dummy10846) + (func $dummy10847) + (func $dummy10848) + (func $dummy10849) + (func $dummy10850) + (func $dummy10851) + (func $dummy10852) + (func $dummy10853) + (func $dummy10854) + (func $dummy10855) + (func $dummy10856) + (func $dummy10857) + (func $dummy10858) + (func $dummy10859) + (func $dummy10860) + (func $dummy10861) + (func $dummy10862) + (func $dummy10863) + (func $dummy10864) + (func $dummy10865) + (func $dummy10866) + (func $dummy10867) + (func $dummy10868) + (func $dummy10869) + (func $dummy10870) + (func $dummy10871) + (func $dummy10872) + (func $dummy10873) + (func $dummy10874) + (func $dummy10875) + (func $dummy10876) + (func $dummy10877) + (func $dummy10878) + (func $dummy10879) + (func $dummy10880) + (func $dummy10881) + (func $dummy10882) + (func $dummy10883) + (func $dummy10884) + (func $dummy10885) + (func $dummy10886) + (func $dummy10887) + (func $dummy10888) + (func $dummy10889) + (func $dummy10890) + (func $dummy10891) + (func $dummy10892) + (func $dummy10893) + (func $dummy10894) + (func $dummy10895) + (func $dummy10896) + (func $dummy10897) + (func $dummy10898) + (func $dummy10899) + (func $dummy10900) + (func $dummy10901) + (func $dummy10902) + (func $dummy10903) + (func $dummy10904) + (func $dummy10905) + (func $dummy10906) + (func $dummy10907) + (func $dummy10908) + (func $dummy10909) + (func $dummy10910) + (func $dummy10911) + (func $dummy10912) + (func $dummy10913) + (func $dummy10914) + (func $dummy10915) + (func $dummy10916) + (func $dummy10917) + (func $dummy10918) + (func $dummy10919) + (func $dummy10920) + (func $dummy10921) + (func $dummy10922) + (func $dummy10923) + (func $dummy10924) + (func $dummy10925) + (func $dummy10926) + (func $dummy10927) + (func $dummy10928) + (func $dummy10929) + (func $dummy10930) + (func $dummy10931) + (func $dummy10932) + (func $dummy10933) + (func $dummy10934) + (func $dummy10935) + (func $dummy10936) + (func $dummy10937) + (func $dummy10938) + (func $dummy10939) + (func $dummy10940) + (func $dummy10941) + (func $dummy10942) + (func $dummy10943) + (func $dummy10944) + (func $dummy10945) + (func $dummy10946) + (func $dummy10947) + (func $dummy10948) + (func $dummy10949) + (func $dummy10950) + (func $dummy10951) + (func $dummy10952) + (func $dummy10953) + (func $dummy10954) + (func $dummy10955) + (func $dummy10956) + (func $dummy10957) + (func $dummy10958) + (func $dummy10959) + (func $dummy10960) + (func $dummy10961) + (func $dummy10962) + (func $dummy10963) + (func $dummy10964) + (func $dummy10965) + (func $dummy10966) + (func $dummy10967) + (func $dummy10968) + (func $dummy10969) + (func $dummy10970) + (func $dummy10971) + (func $dummy10972) + (func $dummy10973) + (func $dummy10974) + (func $dummy10975) + (func $dummy10976) + (func $dummy10977) + (func $dummy10978) + (func $dummy10979) + (func $dummy10980) + (func $dummy10981) + (func $dummy10982) + (func $dummy10983) + (func $dummy10984) + (func $dummy10985) + (func $dummy10986) + (func $dummy10987) + (func $dummy10988) + (func $dummy10989) + (func $dummy10990) + (func $dummy10991) + (func $dummy10992) + (func $dummy10993) + (func $dummy10994) + (func $dummy10995) + (func $dummy10996) + (func $dummy10997) + (func $dummy10998) + (func $dummy10999) + (func $dummy11000) + (func $dummy11001) + (func $dummy11002) + (func $dummy11003) + (func $dummy11004) + (func $dummy11005) + (func $dummy11006) + (func $dummy11007) + (func $dummy11008) + (func $dummy11009) + (func $dummy11010) + (func $dummy11011) + (func $dummy11012) + (func $dummy11013) + (func $dummy11014) + (func $dummy11015) + (func $dummy11016) + (func $dummy11017) + (func $dummy11018) + (func $dummy11019) + (func $dummy11020) + (func $dummy11021) + (func $dummy11022) + (func $dummy11023) + (func $dummy11024) + (func $dummy11025) + (func $dummy11026) + (func $dummy11027) + (func $dummy11028) + (func $dummy11029) + (func $dummy11030) + (func $dummy11031) + (func $dummy11032) + (func $dummy11033) + (func $dummy11034) + (func $dummy11035) + (func $dummy11036) + (func $dummy11037) + (func $dummy11038) + (func $dummy11039) + (func $dummy11040) + (func $dummy11041) + (func $dummy11042) + (func $dummy11043) + (func $dummy11044) + (func $dummy11045) + (func $dummy11046) + (func $dummy11047) + (func $dummy11048) + (func $dummy11049) + (func $dummy11050) + (func $dummy11051) + (func $dummy11052) + (func $dummy11053) + (func $dummy11054) + (func $dummy11055) + (func $dummy11056) + (func $dummy11057) + (func $dummy11058) + (func $dummy11059) + (func $dummy11060) + (func $dummy11061) + (func $dummy11062) + (func $dummy11063) + (func $dummy11064) + (func $dummy11065) + (func $dummy11066) + (func $dummy11067) + (func $dummy11068) + (func $dummy11069) + (func $dummy11070) + (func $dummy11071) + (func $dummy11072) + (func $dummy11073) + (func $dummy11074) + (func $dummy11075) + (func $dummy11076) + (func $dummy11077) + (func $dummy11078) + (func $dummy11079) + (func $dummy11080) + (func $dummy11081) + (func $dummy11082) + (func $dummy11083) + (func $dummy11084) + (func $dummy11085) + (func $dummy11086) + (func $dummy11087) + (func $dummy11088) + (func $dummy11089) + (func $dummy11090) + (func $dummy11091) + (func $dummy11092) + (func $dummy11093) + (func $dummy11094) + (func $dummy11095) + (func $dummy11096) + (func $dummy11097) + (func $dummy11098) + (func $dummy11099) + (func $dummy11100) + (func $dummy11101) + (func $dummy11102) + (func $dummy11103) + (func $dummy11104) + (func $dummy11105) + (func $dummy11106) + (func $dummy11107) + (func $dummy11108) + (func $dummy11109) + (func $dummy11110) + (func $dummy11111) + (func $dummy11112) + (func $dummy11113) + (func $dummy11114) + (func $dummy11115) + (func $dummy11116) + (func $dummy11117) + (func $dummy11118) + (func $dummy11119) + (func $dummy11120) + (func $dummy11121) + (func $dummy11122) + (func $dummy11123) + (func $dummy11124) + (func $dummy11125) + (func $dummy11126) + (func $dummy11127) + (func $dummy11128) + (func $dummy11129) + (func $dummy11130) + (func $dummy11131) + (func $dummy11132) + (func $dummy11133) + (func $dummy11134) + (func $dummy11135) + (func $dummy11136) + (func $dummy11137) + (func $dummy11138) + (func $dummy11139) + (func $dummy11140) + (func $dummy11141) + (func $dummy11142) + (func $dummy11143) + (func $dummy11144) + (func $dummy11145) + (func $dummy11146) + (func $dummy11147) + (func $dummy11148) + (func $dummy11149) + (func $dummy11150) + (func $dummy11151) + (func $dummy11152) + (func $dummy11153) + (func $dummy11154) + (func $dummy11155) + (func $dummy11156) + (func $dummy11157) + (func $dummy11158) + (func $dummy11159) + (func $dummy11160) + (func $dummy11161) + (func $dummy11162) + (func $dummy11163) + (func $dummy11164) + (func $dummy11165) + (func $dummy11166) + (func $dummy11167) + (func $dummy11168) + (func $dummy11169) + (func $dummy11170) + (func $dummy11171) + (func $dummy11172) + (func $dummy11173) + (func $dummy11174) + (func $dummy11175) + (func $dummy11176) + (func $dummy11177) + (func $dummy11178) + (func $dummy11179) + (func $dummy11180) + (func $dummy11181) + (func $dummy11182) + (func $dummy11183) + (func $dummy11184) + (func $dummy11185) + (func $dummy11186) + (func $dummy11187) + (func $dummy11188) + (func $dummy11189) + (func $dummy11190) + (func $dummy11191) + (func $dummy11192) + (func $dummy11193) + (func $dummy11194) + (func $dummy11195) + (func $dummy11196) + (func $dummy11197) + (func $dummy11198) + (func $dummy11199) + (func $dummy11200) + (func $dummy11201) + (func $dummy11202) + (func $dummy11203) + (func $dummy11204) + (func $dummy11205) + (func $dummy11206) + (func $dummy11207) + (func $dummy11208) + (func $dummy11209) + (func $dummy11210) + (func $dummy11211) + (func $dummy11212) + (func $dummy11213) + (func $dummy11214) + (func $dummy11215) + (func $dummy11216) + (func $dummy11217) + (func $dummy11218) + (func $dummy11219) + (func $dummy11220) + (func $dummy11221) + (func $dummy11222) + (func $dummy11223) + (func $dummy11224) + (func $dummy11225) + (func $dummy11226) + (func $dummy11227) + (func $dummy11228) + (func $dummy11229) + (func $dummy11230) + (func $dummy11231) + (func $dummy11232) + (func $dummy11233) + (func $dummy11234) + (func $dummy11235) + (func $dummy11236) + (func $dummy11237) + (func $dummy11238) + (func $dummy11239) + (func $dummy11240) + (func $dummy11241) + (func $dummy11242) + (func $dummy11243) + (func $dummy11244) + (func $dummy11245) + (func $dummy11246) + (func $dummy11247) + (func $dummy11248) + (func $dummy11249) + (func $dummy11250) + (func $dummy11251) + (func $dummy11252) + (func $dummy11253) + (func $dummy11254) + (func $dummy11255) + (func $dummy11256) + (func $dummy11257) + (func $dummy11258) + (func $dummy11259) + (func $dummy11260) + (func $dummy11261) + (func $dummy11262) + (func $dummy11263) + (func $dummy11264) + (func $dummy11265) + (func $dummy11266) + (func $dummy11267) + (func $dummy11268) + (func $dummy11269) + (func $dummy11270) + (func $dummy11271) + (func $dummy11272) + (func $dummy11273) + (func $dummy11274) + (func $dummy11275) + (func $dummy11276) + (func $dummy11277) + (func $dummy11278) + (func $dummy11279) + (func $dummy11280) + (func $dummy11281) + (func $dummy11282) + (func $dummy11283) + (func $dummy11284) + (func $dummy11285) + (func $dummy11286) + (func $dummy11287) + (func $dummy11288) + (func $dummy11289) + (func $dummy11290) + (func $dummy11291) + (func $dummy11292) + (func $dummy11293) + (func $dummy11294) + (func $dummy11295) + (func $dummy11296) + (func $dummy11297) + (func $dummy11298) + (func $dummy11299) + (func $dummy11300) + (func $dummy11301) + (func $dummy11302) + (func $dummy11303) + (func $dummy11304) + (func $dummy11305) + (func $dummy11306) + (func $dummy11307) + (func $dummy11308) + (func $dummy11309) + (func $dummy11310) + (func $dummy11311) + (func $dummy11312) + (func $dummy11313) + (func $dummy11314) + (func $dummy11315) + (func $dummy11316) + (func $dummy11317) + (func $dummy11318) + (func $dummy11319) + (func $dummy11320) + (func $dummy11321) + (func $dummy11322) + (func $dummy11323) + (func $dummy11324) + (func $dummy11325) + (func $dummy11326) + (func $dummy11327) + (func $dummy11328) + (func $dummy11329) + (func $dummy11330) + (func $dummy11331) + (func $dummy11332) + (func $dummy11333) + (func $dummy11334) + (func $dummy11335) + (func $dummy11336) + (func $dummy11337) + (func $dummy11338) + (func $dummy11339) + (func $dummy11340) + (func $dummy11341) + (func $dummy11342) + (func $dummy11343) + (func $dummy11344) + (func $dummy11345) + (func $dummy11346) + (func $dummy11347) + (func $dummy11348) + (func $dummy11349) + (func $dummy11350) + (func $dummy11351) + (func $dummy11352) + (func $dummy11353) + (func $dummy11354) + (func $dummy11355) + (func $dummy11356) + (func $dummy11357) + (func $dummy11358) + (func $dummy11359) + (func $dummy11360) + (func $dummy11361) + (func $dummy11362) + (func $dummy11363) + (func $dummy11364) + (func $dummy11365) + (func $dummy11366) + (func $dummy11367) + (func $dummy11368) + (func $dummy11369) + (func $dummy11370) + (func $dummy11371) + (func $dummy11372) + (func $dummy11373) + (func $dummy11374) + (func $dummy11375) + (func $dummy11376) + (func $dummy11377) + (func $dummy11378) + (func $dummy11379) + (func $dummy11380) + (func $dummy11381) + (func $dummy11382) + (func $dummy11383) + (func $dummy11384) + (func $dummy11385) + (func $dummy11386) + (func $dummy11387) + (func $dummy11388) + (func $dummy11389) + (func $dummy11390) + (func $dummy11391) + (func $dummy11392) + (func $dummy11393) + (func $dummy11394) + (func $dummy11395) + (func $dummy11396) + (func $dummy11397) + (func $dummy11398) + (func $dummy11399) + (func $dummy11400) + (func $dummy11401) + (func $dummy11402) + (func $dummy11403) + (func $dummy11404) + (func $dummy11405) + (func $dummy11406) + (func $dummy11407) + (func $dummy11408) + (func $dummy11409) + (func $dummy11410) + (func $dummy11411) + (func $dummy11412) + (func $dummy11413) + (func $dummy11414) + (func $dummy11415) + (func $dummy11416) + (func $dummy11417) + (func $dummy11418) + (func $dummy11419) + (func $dummy11420) + (func $dummy11421) + (func $dummy11422) + (func $dummy11423) + (func $dummy11424) + (func $dummy11425) + (func $dummy11426) + (func $dummy11427) + (func $dummy11428) + (func $dummy11429) + (func $dummy11430) + (func $dummy11431) + (func $dummy11432) + (func $dummy11433) + (func $dummy11434) + (func $dummy11435) + (func $dummy11436) + (func $dummy11437) + (func $dummy11438) + (func $dummy11439) + (func $dummy11440) + (func $dummy11441) + (func $dummy11442) + (func $dummy11443) + (func $dummy11444) + (func $dummy11445) + (func $dummy11446) + (func $dummy11447) + (func $dummy11448) + (func $dummy11449) + (func $dummy11450) + (func $dummy11451) + (func $dummy11452) + (func $dummy11453) + (func $dummy11454) + (func $dummy11455) + (func $dummy11456) + (func $dummy11457) + (func $dummy11458) + (func $dummy11459) + (func $dummy11460) + (func $dummy11461) + (func $dummy11462) + (func $dummy11463) + (func $dummy11464) + (func $dummy11465) + (func $dummy11466) + (func $dummy11467) + (func $dummy11468) + (func $dummy11469) + (func $dummy11470) + (func $dummy11471) + (func $dummy11472) + (func $dummy11473) + (func $dummy11474) + (func $dummy11475) + (func $dummy11476) + (func $dummy11477) + (func $dummy11478) + (func $dummy11479) + (func $dummy11480) + (func $dummy11481) + (func $dummy11482) + (func $dummy11483) + (func $dummy11484) + (func $dummy11485) + (func $dummy11486) + (func $dummy11487) + (func $dummy11488) + (func $dummy11489) + (func $dummy11490) + (func $dummy11491) + (func $dummy11492) + (func $dummy11493) + (func $dummy11494) + (func $dummy11495) + (func $dummy11496) + (func $dummy11497) + (func $dummy11498) + (func $dummy11499) + (func $dummy11500) + (func $dummy11501) + (func $dummy11502) + (func $dummy11503) + (func $dummy11504) + (func $dummy11505) + (func $dummy11506) + (func $dummy11507) + (func $dummy11508) + (func $dummy11509) + (func $dummy11510) + (func $dummy11511) + (func $dummy11512) + (func $dummy11513) + (func $dummy11514) + (func $dummy11515) + (func $dummy11516) + (func $dummy11517) + (func $dummy11518) + (func $dummy11519) + (func $dummy11520) + (func $dummy11521) + (func $dummy11522) + (func $dummy11523) + (func $dummy11524) + (func $dummy11525) + (func $dummy11526) + (func $dummy11527) + (func $dummy11528) + (func $dummy11529) + (func $dummy11530) + (func $dummy11531) + (func $dummy11532) + (func $dummy11533) + (func $dummy11534) + (func $dummy11535) + (func $dummy11536) + (func $dummy11537) + (func $dummy11538) + (func $dummy11539) + (func $dummy11540) + (func $dummy11541) + (func $dummy11542) + (func $dummy11543) + (func $dummy11544) + (func $dummy11545) + (func $dummy11546) + (func $dummy11547) + (func $dummy11548) + (func $dummy11549) + (func $dummy11550) + (func $dummy11551) + (func $dummy11552) + (func $dummy11553) + (func $dummy11554) + (func $dummy11555) + (func $dummy11556) + (func $dummy11557) + (func $dummy11558) + (func $dummy11559) + (func $dummy11560) + (func $dummy11561) + (func $dummy11562) + (func $dummy11563) + (func $dummy11564) + (func $dummy11565) + (func $dummy11566) + (func $dummy11567) + (func $dummy11568) + (func $dummy11569) + (func $dummy11570) + (func $dummy11571) + (func $dummy11572) + (func $dummy11573) + (func $dummy11574) + (func $dummy11575) + (func $dummy11576) + (func $dummy11577) + (func $dummy11578) + (func $dummy11579) + (func $dummy11580) + (func $dummy11581) + (func $dummy11582) + (func $dummy11583) + (func $dummy11584) + (func $dummy11585) + (func $dummy11586) + (func $dummy11587) + (func $dummy11588) + (func $dummy11589) + (func $dummy11590) + (func $dummy11591) + (func $dummy11592) + (func $dummy11593) + (func $dummy11594) + (func $dummy11595) + (func $dummy11596) + (func $dummy11597) + (func $dummy11598) + (func $dummy11599) + (func $dummy11600) + (func $dummy11601) + (func $dummy11602) + (func $dummy11603) + (func $dummy11604) + (func $dummy11605) + (func $dummy11606) + (func $dummy11607) + (func $dummy11608) + (func $dummy11609) + (func $dummy11610) + (func $dummy11611) + (func $dummy11612) + (func $dummy11613) + (func $dummy11614) + (func $dummy11615) + (func $dummy11616) + (func $dummy11617) + (func $dummy11618) + (func $dummy11619) + (func $dummy11620) + (func $dummy11621) + (func $dummy11622) + (func $dummy11623) + (func $dummy11624) + (func $dummy11625) + (func $dummy11626) + (func $dummy11627) + (func $dummy11628) + (func $dummy11629) + (func $dummy11630) + (func $dummy11631) + (func $dummy11632) + (func $dummy11633) + (func $dummy11634) + (func $dummy11635) + (func $dummy11636) + (func $dummy11637) + (func $dummy11638) + (func $dummy11639) + (func $dummy11640) + (func $dummy11641) + (func $dummy11642) + (func $dummy11643) + (func $dummy11644) + (func $dummy11645) + (func $dummy11646) + (func $dummy11647) + (func $dummy11648) + (func $dummy11649) + (func $dummy11650) + (func $dummy11651) + (func $dummy11652) + (func $dummy11653) + (func $dummy11654) + (func $dummy11655) + (func $dummy11656) + (func $dummy11657) + (func $dummy11658) + (func $dummy11659) + (func $dummy11660) + (func $dummy11661) + (func $dummy11662) + (func $dummy11663) + (func $dummy11664) + (func $dummy11665) + (func $dummy11666) + (func $dummy11667) + (func $dummy11668) + (func $dummy11669) + (func $dummy11670) + (func $dummy11671) + (func $dummy11672) + (func $dummy11673) + (func $dummy11674) + (func $dummy11675) + (func $dummy11676) + (func $dummy11677) + (func $dummy11678) + (func $dummy11679) + (func $dummy11680) + (func $dummy11681) + (func $dummy11682) + (func $dummy11683) + (func $dummy11684) + (func $dummy11685) + (func $dummy11686) + (func $dummy11687) + (func $dummy11688) + (func $dummy11689) + (func $dummy11690) + (func $dummy11691) + (func $dummy11692) + (func $dummy11693) + (func $dummy11694) + (func $dummy11695) + (func $dummy11696) + (func $dummy11697) + (func $dummy11698) + (func $dummy11699) + (func $dummy11700) + (func $dummy11701) + (func $dummy11702) + (func $dummy11703) + (func $dummy11704) + (func $dummy11705) + (func $dummy11706) + (func $dummy11707) + (func $dummy11708) + (func $dummy11709) + (func $dummy11710) + (func $dummy11711) + (func $dummy11712) + (func $dummy11713) + (func $dummy11714) + (func $dummy11715) + (func $dummy11716) + (func $dummy11717) + (func $dummy11718) + (func $dummy11719) + (func $dummy11720) + (func $dummy11721) + (func $dummy11722) + (func $dummy11723) + (func $dummy11724) + (func $dummy11725) + (func $dummy11726) + (func $dummy11727) + (func $dummy11728) + (func $dummy11729) + (func $dummy11730) + (func $dummy11731) + (func $dummy11732) + (func $dummy11733) + (func $dummy11734) + (func $dummy11735) + (func $dummy11736) + (func $dummy11737) + (func $dummy11738) + (func $dummy11739) + (func $dummy11740) + (func $dummy11741) + (func $dummy11742) + (func $dummy11743) + (func $dummy11744) + (func $dummy11745) + (func $dummy11746) + (func $dummy11747) + (func $dummy11748) + (func $dummy11749) + (func $dummy11750) + (func $dummy11751) + (func $dummy11752) + (func $dummy11753) + (func $dummy11754) + (func $dummy11755) + (func $dummy11756) + (func $dummy11757) + (func $dummy11758) + (func $dummy11759) + (func $dummy11760) + (func $dummy11761) + (func $dummy11762) + (func $dummy11763) + (func $dummy11764) + (func $dummy11765) + (func $dummy11766) + (func $dummy11767) + (func $dummy11768) + (func $dummy11769) + (func $dummy11770) + (func $dummy11771) + (func $dummy11772) + (func $dummy11773) + (func $dummy11774) + (func $dummy11775) + (func $dummy11776) + (func $dummy11777) + (func $dummy11778) + (func $dummy11779) + (func $dummy11780) + (func $dummy11781) + (func $dummy11782) + (func $dummy11783) + (func $dummy11784) + (func $dummy11785) + (func $dummy11786) + (func $dummy11787) + (func $dummy11788) + (func $dummy11789) + (func $dummy11790) + (func $dummy11791) + (func $dummy11792) + (func $dummy11793) + (func $dummy11794) + (func $dummy11795) + (func $dummy11796) + (func $dummy11797) + (func $dummy11798) + (func $dummy11799) + (func $dummy11800) + (func $dummy11801) + (func $dummy11802) + (func $dummy11803) + (func $dummy11804) + (func $dummy11805) + (func $dummy11806) + (func $dummy11807) + (func $dummy11808) + (func $dummy11809) + (func $dummy11810) + (func $dummy11811) + (func $dummy11812) + (func $dummy11813) + (func $dummy11814) + (func $dummy11815) + (func $dummy11816) + (func $dummy11817) + (func $dummy11818) + (func $dummy11819) + (func $dummy11820) + (func $dummy11821) + (func $dummy11822) + (func $dummy11823) + (func $dummy11824) + (func $dummy11825) + (func $dummy11826) + (func $dummy11827) + (func $dummy11828) + (func $dummy11829) + (func $dummy11830) + (func $dummy11831) + (func $dummy11832) + (func $dummy11833) + (func $dummy11834) + (func $dummy11835) + (func $dummy11836) + (func $dummy11837) + (func $dummy11838) + (func $dummy11839) + (func $dummy11840) + (func $dummy11841) + (func $dummy11842) + (func $dummy11843) + (func $dummy11844) + (func $dummy11845) + (func $dummy11846) + (func $dummy11847) + (func $dummy11848) + (func $dummy11849) + (func $dummy11850) + (func $dummy11851) + (func $dummy11852) + (func $dummy11853) + (func $dummy11854) + (func $dummy11855) + (func $dummy11856) + (func $dummy11857) + (func $dummy11858) + (func $dummy11859) + (func $dummy11860) + (func $dummy11861) + (func $dummy11862) + (func $dummy11863) + (func $dummy11864) + (func $dummy11865) + (func $dummy11866) + (func $dummy11867) + (func $dummy11868) + (func $dummy11869) + (func $dummy11870) + (func $dummy11871) + (func $dummy11872) + (func $dummy11873) + (func $dummy11874) + (func $dummy11875) + (func $dummy11876) + (func $dummy11877) + (func $dummy11878) + (func $dummy11879) + (func $dummy11880) + (func $dummy11881) + (func $dummy11882) + (func $dummy11883) + (func $dummy11884) + (func $dummy11885) + (func $dummy11886) + (func $dummy11887) + (func $dummy11888) + (func $dummy11889) + (func $dummy11890) + (func $dummy11891) + (func $dummy11892) + (func $dummy11893) + (func $dummy11894) + (func $dummy11895) + (func $dummy11896) + (func $dummy11897) + (func $dummy11898) + (func $dummy11899) + (func $dummy11900) + (func $dummy11901) + (func $dummy11902) + (func $dummy11903) + (func $dummy11904) + (func $dummy11905) + (func $dummy11906) + (func $dummy11907) + (func $dummy11908) + (func $dummy11909) + (func $dummy11910) + (func $dummy11911) + (func $dummy11912) + (func $dummy11913) + (func $dummy11914) + (func $dummy11915) + (func $dummy11916) + (func $dummy11917) + (func $dummy11918) + (func $dummy11919) + (func $dummy11920) + (func $dummy11921) + (func $dummy11922) + (func $dummy11923) + (func $dummy11924) + (func $dummy11925) + (func $dummy11926) + (func $dummy11927) + (func $dummy11928) + (func $dummy11929) + (func $dummy11930) + (func $dummy11931) + (func $dummy11932) + (func $dummy11933) + (func $dummy11934) + (func $dummy11935) + (func $dummy11936) + (func $dummy11937) + (func $dummy11938) + (func $dummy11939) + (func $dummy11940) + (func $dummy11941) + (func $dummy11942) + (func $dummy11943) + (func $dummy11944) + (func $dummy11945) + (func $dummy11946) + (func $dummy11947) + (func $dummy11948) + (func $dummy11949) + (func $dummy11950) + (func $dummy11951) + (func $dummy11952) + (func $dummy11953) + (func $dummy11954) + (func $dummy11955) + (func $dummy11956) + (func $dummy11957) + (func $dummy11958) + (func $dummy11959) + (func $dummy11960) + (func $dummy11961) + (func $dummy11962) + (func $dummy11963) + (func $dummy11964) + (func $dummy11965) + (func $dummy11966) + (func $dummy11967) + (func $dummy11968) + (func $dummy11969) + (func $dummy11970) + (func $dummy11971) + (func $dummy11972) + (func $dummy11973) + (func $dummy11974) + (func $dummy11975) + (func $dummy11976) + (func $dummy11977) + (func $dummy11978) + (func $dummy11979) + (func $dummy11980) + (func $dummy11981) + (func $dummy11982) + (func $dummy11983) + (func $dummy11984) + (func $dummy11985) + (func $dummy11986) + (func $dummy11987) + (func $dummy11988) + (func $dummy11989) + (func $dummy11990) + (func $dummy11991) + (func $dummy11992) + (func $dummy11993) + (func $dummy11994) + (func $dummy11995) + (func $dummy11996) + (func $dummy11997) + (func $dummy11998) + (func $dummy11999) + (func $dummy12000) + (func $dummy12001) + (func $dummy12002) + (func $dummy12003) + (func $dummy12004) + (func $dummy12005) + (func $dummy12006) + (func $dummy12007) + (func $dummy12008) + (func $dummy12009) + (func $dummy12010) + (func $dummy12011) + (func $dummy12012) + (func $dummy12013) + (func $dummy12014) + (func $dummy12015) + (func $dummy12016) + (func $dummy12017) + (func $dummy12018) + (func $dummy12019) + (func $dummy12020) + (func $dummy12021) + (func $dummy12022) + (func $dummy12023) + (func $dummy12024) + (func $dummy12025) + (func $dummy12026) + (func $dummy12027) + (func $dummy12028) + (func $dummy12029) + (func $dummy12030) + (func $dummy12031) + (func $dummy12032) + (func $dummy12033) + (func $dummy12034) + (func $dummy12035) + (func $dummy12036) + (func $dummy12037) + (func $dummy12038) + (func $dummy12039) + (func $dummy12040) + (func $dummy12041) + (func $dummy12042) + (func $dummy12043) + (func $dummy12044) + (func $dummy12045) + (func $dummy12046) + (func $dummy12047) + (func $dummy12048) + (func $dummy12049) + (func $dummy12050) + (func $dummy12051) + (func $dummy12052) + (func $dummy12053) + (func $dummy12054) + (func $dummy12055) + (func $dummy12056) + (func $dummy12057) + (func $dummy12058) + (func $dummy12059) + (func $dummy12060) + (func $dummy12061) + (func $dummy12062) + (func $dummy12063) + (func $dummy12064) + (func $dummy12065) + (func $dummy12066) + (func $dummy12067) + (func $dummy12068) + (func $dummy12069) + (func $dummy12070) + (func $dummy12071) + (func $dummy12072) + (func $dummy12073) + (func $dummy12074) + (func $dummy12075) + (func $dummy12076) + (func $dummy12077) + (func $dummy12078) + (func $dummy12079) + (func $dummy12080) + (func $dummy12081) + (func $dummy12082) + (func $dummy12083) + (func $dummy12084) + (func $dummy12085) + (func $dummy12086) + (func $dummy12087) + (func $dummy12088) + (func $dummy12089) + (func $dummy12090) + (func $dummy12091) + (func $dummy12092) + (func $dummy12093) + (func $dummy12094) + (func $dummy12095) + (func $dummy12096) + (func $dummy12097) + (func $dummy12098) + (func $dummy12099) + (func $dummy12100) + (func $dummy12101) + (func $dummy12102) + (func $dummy12103) + (func $dummy12104) + (func $dummy12105) + (func $dummy12106) + (func $dummy12107) + (func $dummy12108) + (func $dummy12109) + (func $dummy12110) + (func $dummy12111) + (func $dummy12112) + (func $dummy12113) + (func $dummy12114) + (func $dummy12115) + (func $dummy12116) + (func $dummy12117) + (func $dummy12118) + (func $dummy12119) + (func $dummy12120) + (func $dummy12121) + (func $dummy12122) + (func $dummy12123) + (func $dummy12124) + (func $dummy12125) + (func $dummy12126) + (func $dummy12127) + (func $dummy12128) + (func $dummy12129) + (func $dummy12130) + (func $dummy12131) + (func $dummy12132) + (func $dummy12133) + (func $dummy12134) + (func $dummy12135) + (func $dummy12136) + (func $dummy12137) + (func $dummy12138) + (func $dummy12139) + (func $dummy12140) + (func $dummy12141) + (func $dummy12142) + (func $dummy12143) + (func $dummy12144) + (func $dummy12145) + (func $dummy12146) + (func $dummy12147) + (func $dummy12148) + (func $dummy12149) + (func $dummy12150) + (func $dummy12151) + (func $dummy12152) + (func $dummy12153) + (func $dummy12154) + (func $dummy12155) + (func $dummy12156) + (func $dummy12157) + (func $dummy12158) + (func $dummy12159) + (func $dummy12160) + (func $dummy12161) + (func $dummy12162) + (func $dummy12163) + (func $dummy12164) + (func $dummy12165) + (func $dummy12166) + (func $dummy12167) + (func $dummy12168) + (func $dummy12169) + (func $dummy12170) + (func $dummy12171) + (func $dummy12172) + (func $dummy12173) + (func $dummy12174) + (func $dummy12175) + (func $dummy12176) + (func $dummy12177) + (func $dummy12178) + (func $dummy12179) + (func $dummy12180) + (func $dummy12181) + (func $dummy12182) + (func $dummy12183) + (func $dummy12184) + (func $dummy12185) + (func $dummy12186) + (func $dummy12187) + (func $dummy12188) + (func $dummy12189) + (func $dummy12190) + (func $dummy12191) + (func $dummy12192) + (func $dummy12193) + (func $dummy12194) + (func $dummy12195) + (func $dummy12196) + (func $dummy12197) + (func $dummy12198) + (func $dummy12199) + (func $dummy12200) + (func $dummy12201) + (func $dummy12202) + (func $dummy12203) + (func $dummy12204) + (func $dummy12205) + (func $dummy12206) + (func $dummy12207) + (func $dummy12208) + (func $dummy12209) + (func $dummy12210) + (func $dummy12211) + (func $dummy12212) + (func $dummy12213) + (func $dummy12214) + (func $dummy12215) + (func $dummy12216) + (func $dummy12217) + (func $dummy12218) + (func $dummy12219) + (func $dummy12220) + (func $dummy12221) + (func $dummy12222) + (func $dummy12223) + (func $dummy12224) + (func $dummy12225) + (func $dummy12226) + (func $dummy12227) + (func $dummy12228) + (func $dummy12229) + (func $dummy12230) + (func $dummy12231) + (func $dummy12232) + (func $dummy12233) + (func $dummy12234) + (func $dummy12235) + (func $dummy12236) + (func $dummy12237) + (func $dummy12238) + (func $dummy12239) + (func $dummy12240) + (func $dummy12241) + (func $dummy12242) + (func $dummy12243) + (func $dummy12244) + (func $dummy12245) + (func $dummy12246) + (func $dummy12247) + (func $dummy12248) + (func $dummy12249) + (func $dummy12250) + (func $dummy12251) + (func $dummy12252) + (func $dummy12253) + (func $dummy12254) + (func $dummy12255) + (func $dummy12256) + (func $dummy12257) + (func $dummy12258) + (func $dummy12259) + (func $dummy12260) + (func $dummy12261) + (func $dummy12262) + (func $dummy12263) + (func $dummy12264) + (func $dummy12265) + (func $dummy12266) + (func $dummy12267) + (func $dummy12268) + (func $dummy12269) + (func $dummy12270) + (func $dummy12271) + (func $dummy12272) + (func $dummy12273) + (func $dummy12274) + (func $dummy12275) + (func $dummy12276) + (func $dummy12277) + (func $dummy12278) + (func $dummy12279) + (func $dummy12280) + (func $dummy12281) + (func $dummy12282) + (func $dummy12283) + (func $dummy12284) + (func $dummy12285) + (func $dummy12286) + (func $dummy12287) + (func $dummy12288) + (func $dummy12289) + (func $dummy12290) + (func $dummy12291) + (func $dummy12292) + (func $dummy12293) + (func $dummy12294) + (func $dummy12295) + (func $dummy12296) + (func $dummy12297) + (func $dummy12298) + (func $dummy12299) + (func $dummy12300) + (func $dummy12301) + (func $dummy12302) + (func $dummy12303) + (func $dummy12304) + (func $dummy12305) + (func $dummy12306) + (func $dummy12307) + (func $dummy12308) + (func $dummy12309) + (func $dummy12310) + (func $dummy12311) + (func $dummy12312) + (func $dummy12313) + (func $dummy12314) + (func $dummy12315) + (func $dummy12316) + (func $dummy12317) + (func $dummy12318) + (func $dummy12319) + (func $dummy12320) + (func $dummy12321) + (func $dummy12322) + (func $dummy12323) + (func $dummy12324) + (func $dummy12325) + (func $dummy12326) + (func $dummy12327) + (func $dummy12328) + (func $dummy12329) + (func $dummy12330) + (func $dummy12331) + (func $dummy12332) + (func $dummy12333) + (func $dummy12334) + (func $dummy12335) + (func $dummy12336) + (func $dummy12337) + (func $dummy12338) + (func $dummy12339) + (func $dummy12340) + (func $dummy12341) + (func $dummy12342) + (func $dummy12343) + (func $dummy12344) + (func $dummy12345) + (func $dummy12346) + (func $dummy12347) + (func $dummy12348) + (func $dummy12349) + (func $dummy12350) + (func $dummy12351) + (func $dummy12352) + (func $dummy12353) + (func $dummy12354) + (func $dummy12355) + (func $dummy12356) + (func $dummy12357) + (func $dummy12358) + (func $dummy12359) + (func $dummy12360) + (func $dummy12361) + (func $dummy12362) + (func $dummy12363) + (func $dummy12364) + (func $dummy12365) + (func $dummy12366) + (func $dummy12367) + (func $dummy12368) + (func $dummy12369) + (func $dummy12370) + (func $dummy12371) + (func $dummy12372) + (func $dummy12373) + (func $dummy12374) + (func $dummy12375) + (func $dummy12376) + (func $dummy12377) + (func $dummy12378) + (func $dummy12379) + (func $dummy12380) + (func $dummy12381) + (func $dummy12382) + (func $dummy12383) + (func $dummy12384) + (func $dummy12385) + (func $dummy12386) + (func $dummy12387) + (func $dummy12388) + (func $dummy12389) + (func $dummy12390) + (func $dummy12391) + (func $dummy12392) + (func $dummy12393) + (func $dummy12394) + (func $dummy12395) + (func $dummy12396) + (func $dummy12397) + (func $dummy12398) + (func $dummy12399) + (func $dummy12400) + (func $dummy12401) + (func $dummy12402) + (func $dummy12403) + (func $dummy12404) + (func $dummy12405) + (func $dummy12406) + (func $dummy12407) + (func $dummy12408) + (func $dummy12409) + (func $dummy12410) + (func $dummy12411) + (func $dummy12412) + (func $dummy12413) + (func $dummy12414) + (func $dummy12415) + (func $dummy12416) + (func $dummy12417) + (func $dummy12418) + (func $dummy12419) + (func $dummy12420) + (func $dummy12421) + (func $dummy12422) + (func $dummy12423) + (func $dummy12424) + (func $dummy12425) + (func $dummy12426) + (func $dummy12427) + (func $dummy12428) + (func $dummy12429) + (func $dummy12430) + (func $dummy12431) + (func $dummy12432) + (func $dummy12433) + (func $dummy12434) + (func $dummy12435) + (func $dummy12436) + (func $dummy12437) + (func $dummy12438) + (func $dummy12439) + (func $dummy12440) + (func $dummy12441) + (func $dummy12442) + (func $dummy12443) + (func $dummy12444) + (func $dummy12445) + (func $dummy12446) + (func $dummy12447) + (func $dummy12448) + (func $dummy12449) + (func $dummy12450) + (func $dummy12451) + (func $dummy12452) + (func $dummy12453) + (func $dummy12454) + (func $dummy12455) + (func $dummy12456) + (func $dummy12457) + (func $dummy12458) + (func $dummy12459) + (func $dummy12460) + (func $dummy12461) + (func $dummy12462) + (func $dummy12463) + (func $dummy12464) + (func $dummy12465) + (func $dummy12466) + (func $dummy12467) + (func $dummy12468) + (func $dummy12469) + (func $dummy12470) + (func $dummy12471) + (func $dummy12472) + (func $dummy12473) + (func $dummy12474) + (func $dummy12475) + (func $dummy12476) + (func $dummy12477) + (func $dummy12478) + (func $dummy12479) + (func $dummy12480) + (func $dummy12481) + (func $dummy12482) + (func $dummy12483) + (func $dummy12484) + (func $dummy12485) + (func $dummy12486) + (func $dummy12487) + (func $dummy12488) + (func $dummy12489) + (func $dummy12490) + (func $dummy12491) + (func $dummy12492) + (func $dummy12493) + (func $dummy12494) + (func $dummy12495) + (func $dummy12496) + (func $dummy12497) + (func $dummy12498) + (func $dummy12499) + (func $dummy12500) + (func $dummy12501) + (func $dummy12502) + (func $dummy12503) + (func $dummy12504) + (func $dummy12505) + (func $dummy12506) + (func $dummy12507) + (func $dummy12508) + (func $dummy12509) + (func $dummy12510) + (func $dummy12511) + (func $dummy12512) + (func $dummy12513) + (func $dummy12514) + (func $dummy12515) + (func $dummy12516) + (func $dummy12517) + (func $dummy12518) + (func $dummy12519) + (func $dummy12520) + (func $dummy12521) + (func $dummy12522) + (func $dummy12523) + (func $dummy12524) + (func $dummy12525) + (func $dummy12526) + (func $dummy12527) + (func $dummy12528) + (func $dummy12529) + (func $dummy12530) + (func $dummy12531) + (func $dummy12532) + (func $dummy12533) + (func $dummy12534) + (func $dummy12535) + (func $dummy12536) + (func $dummy12537) + (func $dummy12538) + (func $dummy12539) + (func $dummy12540) + (func $dummy12541) + (func $dummy12542) + (func $dummy12543) + (func $dummy12544) + (func $dummy12545) + (func $dummy12546) + (func $dummy12547) + (func $dummy12548) + (func $dummy12549) + (func $dummy12550) + (func $dummy12551) + (func $dummy12552) + (func $dummy12553) + (func $dummy12554) + (func $dummy12555) + (func $dummy12556) + (func $dummy12557) + (func $dummy12558) + (func $dummy12559) + (func $dummy12560) + (func $dummy12561) + (func $dummy12562) + (func $dummy12563) + (func $dummy12564) + (func $dummy12565) + (func $dummy12566) + (func $dummy12567) + (func $dummy12568) + (func $dummy12569) + (func $dummy12570) + (func $dummy12571) + (func $dummy12572) + (func $dummy12573) + (func $dummy12574) + (func $dummy12575) + (func $dummy12576) + (func $dummy12577) + (func $dummy12578) + (func $dummy12579) + (func $dummy12580) + (func $dummy12581) + (func $dummy12582) + (func $dummy12583) + (func $dummy12584) + (func $dummy12585) + (func $dummy12586) + (func $dummy12587) + (func $dummy12588) + (func $dummy12589) + (func $dummy12590) + (func $dummy12591) + (func $dummy12592) + (func $dummy12593) + (func $dummy12594) + (func $dummy12595) + (func $dummy12596) + (func $dummy12597) + (func $dummy12598) + (func $dummy12599) + (func $dummy12600) + (func $dummy12601) + (func $dummy12602) + (func $dummy12603) + (func $dummy12604) + (func $dummy12605) + (func $dummy12606) + (func $dummy12607) + (func $dummy12608) + (func $dummy12609) + (func $dummy12610) + (func $dummy12611) + (func $dummy12612) + (func $dummy12613) + (func $dummy12614) + (func $dummy12615) + (func $dummy12616) + (func $dummy12617) + (func $dummy12618) + (func $dummy12619) + (func $dummy12620) + (func $dummy12621) + (func $dummy12622) + (func $dummy12623) + (func $dummy12624) + (func $dummy12625) + (func $dummy12626) + (func $dummy12627) + (func $dummy12628) + (func $dummy12629) + (func $dummy12630) + (func $dummy12631) + (func $dummy12632) + (func $dummy12633) + (func $dummy12634) + (func $dummy12635) + (func $dummy12636) + (func $dummy12637) + (func $dummy12638) + (func $dummy12639) + (func $dummy12640) + (func $dummy12641) + (func $dummy12642) + (func $dummy12643) + (func $dummy12644) + (func $dummy12645) + (func $dummy12646) + (func $dummy12647) + (func $dummy12648) + (func $dummy12649) + (func $dummy12650) + (func $dummy12651) + (func $dummy12652) + (func $dummy12653) + (func $dummy12654) + (func $dummy12655) + (func $dummy12656) + (func $dummy12657) + (func $dummy12658) + (func $dummy12659) + (func $dummy12660) + (func $dummy12661) + (func $dummy12662) + (func $dummy12663) + (func $dummy12664) + (func $dummy12665) + (func $dummy12666) + (func $dummy12667) + (func $dummy12668) + (func $dummy12669) + (func $dummy12670) + (func $dummy12671) + (func $dummy12672) + (func $dummy12673) + (func $dummy12674) + (func $dummy12675) + (func $dummy12676) + (func $dummy12677) + (func $dummy12678) + (func $dummy12679) + (func $dummy12680) + (func $dummy12681) + (func $dummy12682) + (func $dummy12683) + (func $dummy12684) + (func $dummy12685) + (func $dummy12686) + (func $dummy12687) + (func $dummy12688) + (func $dummy12689) + (func $dummy12690) + (func $dummy12691) + (func $dummy12692) + (func $dummy12693) + (func $dummy12694) + (func $dummy12695) + (func $dummy12696) + (func $dummy12697) + (func $dummy12698) + (func $dummy12699) + (func $dummy12700) + (func $dummy12701) + (func $dummy12702) + (func $dummy12703) + (func $dummy12704) + (func $dummy12705) + (func $dummy12706) + (func $dummy12707) + (func $dummy12708) + (func $dummy12709) + (func $dummy12710) + (func $dummy12711) + (func $dummy12712) + (func $dummy12713) + (func $dummy12714) + (func $dummy12715) + (func $dummy12716) + (func $dummy12717) + (func $dummy12718) + (func $dummy12719) + (func $dummy12720) + (func $dummy12721) + (func $dummy12722) + (func $dummy12723) + (func $dummy12724) + (func $dummy12725) + (func $dummy12726) + (func $dummy12727) + (func $dummy12728) + (func $dummy12729) + (func $dummy12730) + (func $dummy12731) + (func $dummy12732) + (func $dummy12733) + (func $dummy12734) + (func $dummy12735) + (func $dummy12736) + (func $dummy12737) + (func $dummy12738) + (func $dummy12739) + (func $dummy12740) + (func $dummy12741) + (func $dummy12742) + (func $dummy12743) + (func $dummy12744) + (func $dummy12745) + (func $dummy12746) + (func $dummy12747) + (func $dummy12748) + (func $dummy12749) + (func $dummy12750) + (func $dummy12751) + (func $dummy12752) + (func $dummy12753) + (func $dummy12754) + (func $dummy12755) + (func $dummy12756) + (func $dummy12757) + (func $dummy12758) + (func $dummy12759) + (func $dummy12760) + (func $dummy12761) + (func $dummy12762) + (func $dummy12763) + (func $dummy12764) + (func $dummy12765) + (func $dummy12766) + (func $dummy12767) + (func $dummy12768) + (func $dummy12769) + (func $dummy12770) + (func $dummy12771) + (func $dummy12772) + (func $dummy12773) + (func $dummy12774) + (func $dummy12775) + (func $dummy12776) + (func $dummy12777) + (func $dummy12778) + (func $dummy12779) + (func $dummy12780) + (func $dummy12781) + (func $dummy12782) + (func $dummy12783) + (func $dummy12784) + (func $dummy12785) + (func $dummy12786) + (func $dummy12787) + (func $dummy12788) + (func $dummy12789) + (func $dummy12790) + (func $dummy12791) + (func $dummy12792) + (func $dummy12793) + (func $dummy12794) + (func $dummy12795) + (func $dummy12796) + (func $dummy12797) + (func $dummy12798) + (func $dummy12799) + (func $dummy12800) + (func $dummy12801) + (func $dummy12802) + (func $dummy12803) + (func $dummy12804) + (func $dummy12805) + (func $dummy12806) + (func $dummy12807) + (func $dummy12808) + (func $dummy12809) + (func $dummy12810) + (func $dummy12811) + (func $dummy12812) + (func $dummy12813) + (func $dummy12814) + (func $dummy12815) + (func $dummy12816) + (func $dummy12817) + (func $dummy12818) + (func $dummy12819) + (func $dummy12820) + (func $dummy12821) + (func $dummy12822) + (func $dummy12823) + (func $dummy12824) + (func $dummy12825) + (func $dummy12826) + (func $dummy12827) + (func $dummy12828) + (func $dummy12829) + (func $dummy12830) + (func $dummy12831) + (func $dummy12832) + (func $dummy12833) + (func $dummy12834) + (func $dummy12835) + (func $dummy12836) + (func $dummy12837) + (func $dummy12838) + (func $dummy12839) + (func $dummy12840) + (func $dummy12841) + (func $dummy12842) + (func $dummy12843) + (func $dummy12844) + (func $dummy12845) + (func $dummy12846) + (func $dummy12847) + (func $dummy12848) + (func $dummy12849) + (func $dummy12850) + (func $dummy12851) + (func $dummy12852) + (func $dummy12853) + (func $dummy12854) + (func $dummy12855) + (func $dummy12856) + (func $dummy12857) + (func $dummy12858) + (func $dummy12859) + (func $dummy12860) + (func $dummy12861) + (func $dummy12862) + (func $dummy12863) + (func $dummy12864) + (func $dummy12865) + (func $dummy12866) + (func $dummy12867) + (func $dummy12868) + (func $dummy12869) + (func $dummy12870) + (func $dummy12871) + (func $dummy12872) + (func $dummy12873) + (func $dummy12874) + (func $dummy12875) + (func $dummy12876) + (func $dummy12877) + (func $dummy12878) + (func $dummy12879) + (func $dummy12880) + (func $dummy12881) + (func $dummy12882) + (func $dummy12883) + (func $dummy12884) + (func $dummy12885) + (func $dummy12886) + (func $dummy12887) + (func $dummy12888) + (func $dummy12889) + (func $dummy12890) + (func $dummy12891) + (func $dummy12892) + (func $dummy12893) + (func $dummy12894) + (func $dummy12895) + (func $dummy12896) + (func $dummy12897) + (func $dummy12898) + (func $dummy12899) + (func $dummy12900) + (func $dummy12901) + (func $dummy12902) + (func $dummy12903) + (func $dummy12904) + (func $dummy12905) + (func $dummy12906) + (func $dummy12907) + (func $dummy12908) + (func $dummy12909) + (func $dummy12910) + (func $dummy12911) + (func $dummy12912) + (func $dummy12913) + (func $dummy12914) + (func $dummy12915) + (func $dummy12916) + (func $dummy12917) + (func $dummy12918) + (func $dummy12919) + (func $dummy12920) + (func $dummy12921) + (func $dummy12922) + (func $dummy12923) + (func $dummy12924) + (func $dummy12925) + (func $dummy12926) + (func $dummy12927) + (func $dummy12928) + (func $dummy12929) + (func $dummy12930) + (func $dummy12931) + (func $dummy12932) + (func $dummy12933) + (func $dummy12934) + (func $dummy12935) + (func $dummy12936) + (func $dummy12937) + (func $dummy12938) + (func $dummy12939) + (func $dummy12940) + (func $dummy12941) + (func $dummy12942) + (func $dummy12943) + (func $dummy12944) + (func $dummy12945) + (func $dummy12946) + (func $dummy12947) + (func $dummy12948) + (func $dummy12949) + (func $dummy12950) + (func $dummy12951) + (func $dummy12952) + (func $dummy12953) + (func $dummy12954) + (func $dummy12955) + (func $dummy12956) + (func $dummy12957) + (func $dummy12958) + (func $dummy12959) + (func $dummy12960) + (func $dummy12961) + (func $dummy12962) + (func $dummy12963) + (func $dummy12964) + (func $dummy12965) + (func $dummy12966) + (func $dummy12967) + (func $dummy12968) + (func $dummy12969) + (func $dummy12970) + (func $dummy12971) + (func $dummy12972) + (func $dummy12973) + (func $dummy12974) + (func $dummy12975) + (func $dummy12976) + (func $dummy12977) + (func $dummy12978) + (func $dummy12979) + (func $dummy12980) + (func $dummy12981) + (func $dummy12982) + (func $dummy12983) + (func $dummy12984) + (func $dummy12985) + (func $dummy12986) + (func $dummy12987) + (func $dummy12988) + (func $dummy12989) + (func $dummy12990) + (func $dummy12991) + (func $dummy12992) + (func $dummy12993) + (func $dummy12994) + (func $dummy12995) + (func $dummy12996) + (func $dummy12997) + (func $dummy12998) + (func $dummy12999) + (func $dummy13000) + (func $dummy13001) + (func $dummy13002) + (func $dummy13003) + (func $dummy13004) + (func $dummy13005) + (func $dummy13006) + (func $dummy13007) + (func $dummy13008) + (func $dummy13009) + (func $dummy13010) + (func $dummy13011) + (func $dummy13012) + (func $dummy13013) + (func $dummy13014) + (func $dummy13015) + (func $dummy13016) + (func $dummy13017) + (func $dummy13018) + (func $dummy13019) + (func $dummy13020) + (func $dummy13021) + (func $dummy13022) + (func $dummy13023) + (func $dummy13024) + (func $dummy13025) + (func $dummy13026) + (func $dummy13027) + (func $dummy13028) + (func $dummy13029) + (func $dummy13030) + (func $dummy13031) + (func $dummy13032) + (func $dummy13033) + (func $dummy13034) + (func $dummy13035) + (func $dummy13036) + (func $dummy13037) + (func $dummy13038) + (func $dummy13039) + (func $dummy13040) + (func $dummy13041) + (func $dummy13042) + (func $dummy13043) + (func $dummy13044) + (func $dummy13045) + (func $dummy13046) + (func $dummy13047) + (func $dummy13048) + (func $dummy13049) + (func $dummy13050) + (func $dummy13051) + (func $dummy13052) + (func $dummy13053) + (func $dummy13054) + (func $dummy13055) + (func $dummy13056) + (func $dummy13057) + (func $dummy13058) + (func $dummy13059) + (func $dummy13060) + (func $dummy13061) + (func $dummy13062) + (func $dummy13063) + (func $dummy13064) + (func $dummy13065) + (func $dummy13066) + (func $dummy13067) + (func $dummy13068) + (func $dummy13069) + (func $dummy13070) + (func $dummy13071) + (func $dummy13072) + (func $dummy13073) + (func $dummy13074) + (func $dummy13075) + (func $dummy13076) + (func $dummy13077) + (func $dummy13078) + (func $dummy13079) + (func $dummy13080) + (func $dummy13081) + (func $dummy13082) + (func $dummy13083) + (func $dummy13084) + (func $dummy13085) + (func $dummy13086) + (func $dummy13087) + (func $dummy13088) + (func $dummy13089) + (func $dummy13090) + (func $dummy13091) + (func $dummy13092) + (func $dummy13093) + (func $dummy13094) + (func $dummy13095) + (func $dummy13096) + (func $dummy13097) + (func $dummy13098) + (func $dummy13099) + (func $dummy13100) + (func $dummy13101) + (func $dummy13102) + (func $dummy13103) + (func $dummy13104) + (func $dummy13105) + (func $dummy13106) + (func $dummy13107) + (func $dummy13108) + (func $dummy13109) + (func $dummy13110) + (func $dummy13111) + (func $dummy13112) + (func $dummy13113) + (func $dummy13114) + (func $dummy13115) + (func $dummy13116) + (func $dummy13117) + (func $dummy13118) + (func $dummy13119) + (func $dummy13120) + (func $dummy13121) + (func $dummy13122) + (func $dummy13123) + (func $dummy13124) + (func $dummy13125) + (func $dummy13126) + (func $dummy13127) + (func $dummy13128) + (func $dummy13129) + (func $dummy13130) + (func $dummy13131) + (func $dummy13132) + (func $dummy13133) + (func $dummy13134) + (func $dummy13135) + (func $dummy13136) + (func $dummy13137) + (func $dummy13138) + (func $dummy13139) + (func $dummy13140) + (func $dummy13141) + (func $dummy13142) + (func $dummy13143) + (func $dummy13144) + (func $dummy13145) + (func $dummy13146) + (func $dummy13147) + (func $dummy13148) + (func $dummy13149) + (func $dummy13150) + (func $dummy13151) + (func $dummy13152) + (func $dummy13153) + (func $dummy13154) + (func $dummy13155) + (func $dummy13156) + (func $dummy13157) + (func $dummy13158) + (func $dummy13159) + (func $dummy13160) + (func $dummy13161) + (func $dummy13162) + (func $dummy13163) + (func $dummy13164) + (func $dummy13165) + (func $dummy13166) + (func $dummy13167) + (func $dummy13168) + (func $dummy13169) + (func $dummy13170) + (func $dummy13171) + (func $dummy13172) + (func $dummy13173) + (func $dummy13174) + (func $dummy13175) + (func $dummy13176) + (func $dummy13177) + (func $dummy13178) + (func $dummy13179) + (func $dummy13180) + (func $dummy13181) + (func $dummy13182) + (func $dummy13183) + (func $dummy13184) + (func $dummy13185) + (func $dummy13186) + (func $dummy13187) + (func $dummy13188) + (func $dummy13189) + (func $dummy13190) + (func $dummy13191) + (func $dummy13192) + (func $dummy13193) + (func $dummy13194) + (func $dummy13195) + (func $dummy13196) + (func $dummy13197) + (func $dummy13198) + (func $dummy13199) + (func $dummy13200) + (func $dummy13201) + (func $dummy13202) + (func $dummy13203) + (func $dummy13204) + (func $dummy13205) + (func $dummy13206) + (func $dummy13207) + (func $dummy13208) + (func $dummy13209) + (func $dummy13210) + (func $dummy13211) + (func $dummy13212) + (func $dummy13213) + (func $dummy13214) + (func $dummy13215) + (func $dummy13216) + (func $dummy13217) + (func $dummy13218) + (func $dummy13219) + (func $dummy13220) + (func $dummy13221) + (func $dummy13222) + (func $dummy13223) + (func $dummy13224) + (func $dummy13225) + (func $dummy13226) + (func $dummy13227) + (func $dummy13228) + (func $dummy13229) + (func $dummy13230) + (func $dummy13231) + (func $dummy13232) + (func $dummy13233) + (func $dummy13234) + (func $dummy13235) + (func $dummy13236) + (func $dummy13237) + (func $dummy13238) + (func $dummy13239) + (func $dummy13240) + (func $dummy13241) + (func $dummy13242) + (func $dummy13243) + (func $dummy13244) + (func $dummy13245) + (func $dummy13246) + (func $dummy13247) + (func $dummy13248) + (func $dummy13249) + (func $dummy13250) + (func $dummy13251) + (func $dummy13252) + (func $dummy13253) + (func $dummy13254) + (func $dummy13255) + (func $dummy13256) + (func $dummy13257) + (func $dummy13258) + (func $dummy13259) + (func $dummy13260) + (func $dummy13261) + (func $dummy13262) + (func $dummy13263) + (func $dummy13264) + (func $dummy13265) + (func $dummy13266) + (func $dummy13267) + (func $dummy13268) + (func $dummy13269) + (func $dummy13270) + (func $dummy13271) + (func $dummy13272) + (func $dummy13273) + (func $dummy13274) + (func $dummy13275) + (func $dummy13276) + (func $dummy13277) + (func $dummy13278) + (func $dummy13279) + (func $dummy13280) + (func $dummy13281) + (func $dummy13282) + (func $dummy13283) + (func $dummy13284) + (func $dummy13285) + (func $dummy13286) + (func $dummy13287) + (func $dummy13288) + (func $dummy13289) + (func $dummy13290) + (func $dummy13291) + (func $dummy13292) + (func $dummy13293) + (func $dummy13294) + (func $dummy13295) + (func $dummy13296) + (func $dummy13297) + (func $dummy13298) + (func $dummy13299) + (func $dummy13300) + (func $dummy13301) + (func $dummy13302) + (func $dummy13303) + (func $dummy13304) + (func $dummy13305) + (func $dummy13306) + (func $dummy13307) + (func $dummy13308) + (func $dummy13309) + (func $dummy13310) + (func $dummy13311) + (func $dummy13312) + (func $dummy13313) + (func $dummy13314) + (func $dummy13315) + (func $dummy13316) + (func $dummy13317) + (func $dummy13318) + (func $dummy13319) + (func $dummy13320) + (func $dummy13321) + (func $dummy13322) + (func $dummy13323) + (func $dummy13324) + (func $dummy13325) + (func $dummy13326) + (func $dummy13327) + (func $dummy13328) + (func $dummy13329) + (func $dummy13330) + (func $dummy13331) + (func $dummy13332) + (func $dummy13333) + (func $dummy13334) + (func $dummy13335) + (func $dummy13336) + (func $dummy13337) + (func $dummy13338) + (func $dummy13339) + (func $dummy13340) + (func $dummy13341) + (func $dummy13342) + (func $dummy13343) + (func $dummy13344) + (func $dummy13345) + (func $dummy13346) + (func $dummy13347) + (func $dummy13348) + (func $dummy13349) + (func $dummy13350) + (func $dummy13351) + (func $dummy13352) + (func $dummy13353) + (func $dummy13354) + (func $dummy13355) + (func $dummy13356) + (func $dummy13357) + (func $dummy13358) + (func $dummy13359) + (func $dummy13360) + (func $dummy13361) + (func $dummy13362) + (func $dummy13363) + (func $dummy13364) + (func $dummy13365) + (func $dummy13366) + (func $dummy13367) + (func $dummy13368) + (func $dummy13369) + (func $dummy13370) + (func $dummy13371) + (func $dummy13372) + (func $dummy13373) + (func $dummy13374) + (func $dummy13375) + (func $dummy13376) + (func $dummy13377) + (func $dummy13378) + (func $dummy13379) + (func $dummy13380) + (func $dummy13381) + (func $dummy13382) + (func $dummy13383) + (func $dummy13384) + (func $dummy13385) + (func $dummy13386) + (func $dummy13387) + (func $dummy13388) + (func $dummy13389) + (func $dummy13390) + (func $dummy13391) + (func $dummy13392) + (func $dummy13393) + (func $dummy13394) + (func $dummy13395) + (func $dummy13396) + (func $dummy13397) + (func $dummy13398) + (func $dummy13399) + (func $dummy13400) + (func $dummy13401) + (func $dummy13402) + (func $dummy13403) + (func $dummy13404) + (func $dummy13405) + (func $dummy13406) + (func $dummy13407) + (func $dummy13408) + (func $dummy13409) + (func $dummy13410) + (func $dummy13411) + (func $dummy13412) + (func $dummy13413) + (func $dummy13414) + (func $dummy13415) + (func $dummy13416) + (func $dummy13417) + (func $dummy13418) + (func $dummy13419) + (func $dummy13420) + (func $dummy13421) + (func $dummy13422) + (func $dummy13423) + (func $dummy13424) + (func $dummy13425) + (func $dummy13426) + (func $dummy13427) + (func $dummy13428) + (func $dummy13429) + (func $dummy13430) + (func $dummy13431) + (func $dummy13432) + (func $dummy13433) + (func $dummy13434) + (func $dummy13435) + (func $dummy13436) + (func $dummy13437) + (func $dummy13438) + (func $dummy13439) + (func $dummy13440) + (func $dummy13441) + (func $dummy13442) + (func $dummy13443) + (func $dummy13444) + (func $dummy13445) + (func $dummy13446) + (func $dummy13447) + (func $dummy13448) + (func $dummy13449) + (func $dummy13450) + (func $dummy13451) + (func $dummy13452) + (func $dummy13453) + (func $dummy13454) + (func $dummy13455) + (func $dummy13456) + (func $dummy13457) + (func $dummy13458) + (func $dummy13459) + (func $dummy13460) + (func $dummy13461) + (func $dummy13462) + (func $dummy13463) + (func $dummy13464) + (func $dummy13465) + (func $dummy13466) + (func $dummy13467) + (func $dummy13468) + (func $dummy13469) + (func $dummy13470) + (func $dummy13471) + (func $dummy13472) + (func $dummy13473) + (func $dummy13474) + (func $dummy13475) + (func $dummy13476) + (func $dummy13477) + (func $dummy13478) + (func $dummy13479) + (func $dummy13480) + (func $dummy13481) + (func $dummy13482) + (func $dummy13483) + (func $dummy13484) + (func $dummy13485) + (func $dummy13486) + (func $dummy13487) + (func $dummy13488) + (func $dummy13489) + (func $dummy13490) + (func $dummy13491) + (func $dummy13492) + (func $dummy13493) + (func $dummy13494) + (func $dummy13495) + (func $dummy13496) + (func $dummy13497) + (func $dummy13498) + (func $dummy13499) + (func $dummy13500) + (func $dummy13501) + (func $dummy13502) + (func $dummy13503) + (func $dummy13504) + (func $dummy13505) + (func $dummy13506) + (func $dummy13507) + (func $dummy13508) + (func $dummy13509) + (func $dummy13510) + (func $dummy13511) + (func $dummy13512) + (func $dummy13513) + (func $dummy13514) + (func $dummy13515) + (func $dummy13516) + (func $dummy13517) + (func $dummy13518) + (func $dummy13519) + (func $dummy13520) + (func $dummy13521) + (func $dummy13522) + (func $dummy13523) + (func $dummy13524) + (func $dummy13525) + (func $dummy13526) + (func $dummy13527) + (func $dummy13528) + (func $dummy13529) + (func $dummy13530) + (func $dummy13531) + (func $dummy13532) + (func $dummy13533) + (func $dummy13534) + (func $dummy13535) + (func $dummy13536) + (func $dummy13537) + (func $dummy13538) + (func $dummy13539) + (func $dummy13540) + (func $dummy13541) + (func $dummy13542) + (func $dummy13543) + (func $dummy13544) + (func $dummy13545) + (func $dummy13546) + (func $dummy13547) + (func $dummy13548) + (func $dummy13549) + (func $dummy13550) + (func $dummy13551) + (func $dummy13552) + (func $dummy13553) + (func $dummy13554) + (func $dummy13555) + (func $dummy13556) + (func $dummy13557) + (func $dummy13558) + (func $dummy13559) + (func $dummy13560) + (func $dummy13561) + (func $dummy13562) + (func $dummy13563) + (func $dummy13564) + (func $dummy13565) + (func $dummy13566) + (func $dummy13567) + (func $dummy13568) + (func $dummy13569) + (func $dummy13570) + (func $dummy13571) + (func $dummy13572) + (func $dummy13573) + (func $dummy13574) + (func $dummy13575) + (func $dummy13576) + (func $dummy13577) + (func $dummy13578) + (func $dummy13579) + (func $dummy13580) + (func $dummy13581) + (func $dummy13582) + (func $dummy13583) + (func $dummy13584) + (func $dummy13585) + (func $dummy13586) + (func $dummy13587) + (func $dummy13588) + (func $dummy13589) + (func $dummy13590) + (func $dummy13591) + (func $dummy13592) + (func $dummy13593) + (func $dummy13594) + (func $dummy13595) + (func $dummy13596) + (func $dummy13597) + (func $dummy13598) + (func $dummy13599) + (func $dummy13600) + (func $dummy13601) + (func $dummy13602) + (func $dummy13603) + (func $dummy13604) + (func $dummy13605) + (func $dummy13606) + (func $dummy13607) + (func $dummy13608) + (func $dummy13609) + (func $dummy13610) + (func $dummy13611) + (func $dummy13612) + (func $dummy13613) + (func $dummy13614) + (func $dummy13615) + (func $dummy13616) + (func $dummy13617) + (func $dummy13618) + (func $dummy13619) + (func $dummy13620) + (func $dummy13621) + (func $dummy13622) + (func $dummy13623) + (func $dummy13624) + (func $dummy13625) + (func $dummy13626) + (func $dummy13627) + (func $dummy13628) + (func $dummy13629) + (func $dummy13630) + (func $dummy13631) + (func $dummy13632) + (func $dummy13633) + (func $dummy13634) + (func $dummy13635) + (func $dummy13636) + (func $dummy13637) + (func $dummy13638) + (func $dummy13639) + (func $dummy13640) + (func $dummy13641) + (func $dummy13642) + (func $dummy13643) + (func $dummy13644) + (func $dummy13645) + (func $dummy13646) + (func $dummy13647) + (func $dummy13648) + (func $dummy13649) + (func $dummy13650) + (func $dummy13651) + (func $dummy13652) + (func $dummy13653) + (func $dummy13654) + (func $dummy13655) + (func $dummy13656) + (func $dummy13657) + (func $dummy13658) + (func $dummy13659) + (func $dummy13660) + (func $dummy13661) + (func $dummy13662) + (func $dummy13663) + (func $dummy13664) + (func $dummy13665) + (func $dummy13666) + (func $dummy13667) + (func $dummy13668) + (func $dummy13669) + (func $dummy13670) + (func $dummy13671) + (func $dummy13672) + (func $dummy13673) + (func $dummy13674) + (func $dummy13675) + (func $dummy13676) + (func $dummy13677) + (func $dummy13678) + (func $dummy13679) + (func $dummy13680) + (func $dummy13681) + (func $dummy13682) + (func $dummy13683) + (func $dummy13684) + (func $dummy13685) + (func $dummy13686) + (func $dummy13687) + (func $dummy13688) + (func $dummy13689) + (func $dummy13690) + (func $dummy13691) + (func $dummy13692) + (func $dummy13693) + (func $dummy13694) + (func $dummy13695) + (func $dummy13696) + (func $dummy13697) + (func $dummy13698) + (func $dummy13699) + (func $dummy13700) + (func $dummy13701) + (func $dummy13702) + (func $dummy13703) + (func $dummy13704) + (func $dummy13705) + (func $dummy13706) + (func $dummy13707) + (func $dummy13708) + (func $dummy13709) + (func $dummy13710) + (func $dummy13711) + (func $dummy13712) + (func $dummy13713) + (func $dummy13714) + (func $dummy13715) + (func $dummy13716) + (func $dummy13717) + (func $dummy13718) + (func $dummy13719) + (func $dummy13720) + (func $dummy13721) + (func $dummy13722) + (func $dummy13723) + (func $dummy13724) + (func $dummy13725) + (func $dummy13726) + (func $dummy13727) + (func $dummy13728) + (func $dummy13729) + (func $dummy13730) + (func $dummy13731) + (func $dummy13732) + (func $dummy13733) + (func $dummy13734) + (func $dummy13735) + (func $dummy13736) + (func $dummy13737) + (func $dummy13738) + (func $dummy13739) + (func $dummy13740) + (func $dummy13741) + (func $dummy13742) + (func $dummy13743) + (func $dummy13744) + (func $dummy13745) + (func $dummy13746) + (func $dummy13747) + (func $dummy13748) + (func $dummy13749) + (func $dummy13750) + (func $dummy13751) + (func $dummy13752) + (func $dummy13753) + (func $dummy13754) + (func $dummy13755) + (func $dummy13756) + (func $dummy13757) + (func $dummy13758) + (func $dummy13759) + (func $dummy13760) + (func $dummy13761) + (func $dummy13762) + (func $dummy13763) + (func $dummy13764) + (func $dummy13765) + (func $dummy13766) + (func $dummy13767) + (func $dummy13768) + (func $dummy13769) + (func $dummy13770) + (func $dummy13771) + (func $dummy13772) + (func $dummy13773) + (func $dummy13774) + (func $dummy13775) + (func $dummy13776) + (func $dummy13777) + (func $dummy13778) + (func $dummy13779) + (func $dummy13780) + (func $dummy13781) + (func $dummy13782) + (func $dummy13783) + (func $dummy13784) + (func $dummy13785) + (func $dummy13786) + (func $dummy13787) + (func $dummy13788) + (func $dummy13789) + (func $dummy13790) + (func $dummy13791) + (func $dummy13792) + (func $dummy13793) + (func $dummy13794) + (func $dummy13795) + (func $dummy13796) + (func $dummy13797) + (func $dummy13798) + (func $dummy13799) + (func $dummy13800) + (func $dummy13801) + (func $dummy13802) + (func $dummy13803) + (func $dummy13804) + (func $dummy13805) + (func $dummy13806) + (func $dummy13807) + (func $dummy13808) + (func $dummy13809) + (func $dummy13810) + (func $dummy13811) + (func $dummy13812) + (func $dummy13813) + (func $dummy13814) + (func $dummy13815) + (func $dummy13816) + (func $dummy13817) + (func $dummy13818) + (func $dummy13819) + (func $dummy13820) + (func $dummy13821) + (func $dummy13822) + (func $dummy13823) + (func $dummy13824) + (func $dummy13825) + (func $dummy13826) + (func $dummy13827) + (func $dummy13828) + (func $dummy13829) + (func $dummy13830) + (func $dummy13831) + (func $dummy13832) + (func $dummy13833) + (func $dummy13834) + (func $dummy13835) + (func $dummy13836) + (func $dummy13837) + (func $dummy13838) + (func $dummy13839) + (func $dummy13840) + (func $dummy13841) + (func $dummy13842) + (func $dummy13843) + (func $dummy13844) + (func $dummy13845) + (func $dummy13846) + (func $dummy13847) + (func $dummy13848) + (func $dummy13849) + (func $dummy13850) + (func $dummy13851) + (func $dummy13852) + (func $dummy13853) + (func $dummy13854) + (func $dummy13855) + (func $dummy13856) + (func $dummy13857) + (func $dummy13858) + (func $dummy13859) + (func $dummy13860) + (func $dummy13861) + (func $dummy13862) + (func $dummy13863) + (func $dummy13864) + (func $dummy13865) + (func $dummy13866) + (func $dummy13867) + (func $dummy13868) + (func $dummy13869) + (func $dummy13870) + (func $dummy13871) + (func $dummy13872) + (func $dummy13873) + (func $dummy13874) + (func $dummy13875) + (func $dummy13876) + (func $dummy13877) + (func $dummy13878) + (func $dummy13879) + (func $dummy13880) + (func $dummy13881) + (func $dummy13882) + (func $dummy13883) + (func $dummy13884) + (func $dummy13885) + (func $dummy13886) + (func $dummy13887) + (func $dummy13888) + (func $dummy13889) + (func $dummy13890) + (func $dummy13891) + (func $dummy13892) + (func $dummy13893) + (func $dummy13894) + (func $dummy13895) + (func $dummy13896) + (func $dummy13897) + (func $dummy13898) + (func $dummy13899) + (func $dummy13900) + (func $dummy13901) + (func $dummy13902) + (func $dummy13903) + (func $dummy13904) + (func $dummy13905) + (func $dummy13906) + (func $dummy13907) + (func $dummy13908) + (func $dummy13909) + (func $dummy13910) + (func $dummy13911) + (func $dummy13912) + (func $dummy13913) + (func $dummy13914) + (func $dummy13915) + (func $dummy13916) + (func $dummy13917) + (func $dummy13918) + (func $dummy13919) + (func $dummy13920) + (func $dummy13921) + (func $dummy13922) + (func $dummy13923) + (func $dummy13924) + (func $dummy13925) + (func $dummy13926) + (func $dummy13927) + (func $dummy13928) + (func $dummy13929) + (func $dummy13930) + (func $dummy13931) + (func $dummy13932) + (func $dummy13933) + (func $dummy13934) + (func $dummy13935) + (func $dummy13936) + (func $dummy13937) + (func $dummy13938) + (func $dummy13939) + (func $dummy13940) + (func $dummy13941) + (func $dummy13942) + (func $dummy13943) + (func $dummy13944) + (func $dummy13945) + (func $dummy13946) + (func $dummy13947) + (func $dummy13948) + (func $dummy13949) + (func $dummy13950) + (func $dummy13951) + (func $dummy13952) + (func $dummy13953) + (func $dummy13954) + (func $dummy13955) + (func $dummy13956) + (func $dummy13957) + (func $dummy13958) + (func $dummy13959) + (func $dummy13960) + (func $dummy13961) + (func $dummy13962) + (func $dummy13963) + (func $dummy13964) + (func $dummy13965) + (func $dummy13966) + (func $dummy13967) + (func $dummy13968) + (func $dummy13969) + (func $dummy13970) + (func $dummy13971) + (func $dummy13972) + (func $dummy13973) + (func $dummy13974) + (func $dummy13975) + (func $dummy13976) + (func $dummy13977) + (func $dummy13978) + (func $dummy13979) + (func $dummy13980) + (func $dummy13981) + (func $dummy13982) + (func $dummy13983) + (func $dummy13984) + (func $dummy13985) + (func $dummy13986) + (func $dummy13987) + (func $dummy13988) + (func $dummy13989) + (func $dummy13990) + (func $dummy13991) + (func $dummy13992) + (func $dummy13993) + (func $dummy13994) + (func $dummy13995) + (func $dummy13996) + (func $dummy13997) + (func $dummy13998) + (func $dummy13999) + (func $dummy14000) + (func $dummy14001) + (func $dummy14002) + (func $dummy14003) + (func $dummy14004) + (func $dummy14005) + (func $dummy14006) + (func $dummy14007) + (func $dummy14008) + (func $dummy14009) + (func $dummy14010) + (func $dummy14011) + (func $dummy14012) + (func $dummy14013) + (func $dummy14014) + (func $dummy14015) + (func $dummy14016) + (func $dummy14017) + (func $dummy14018) + (func $dummy14019) + (func $dummy14020) + (func $dummy14021) + (func $dummy14022) + (func $dummy14023) + (func $dummy14024) + (func $dummy14025) + (func $dummy14026) + (func $dummy14027) + (func $dummy14028) + (func $dummy14029) + (func $dummy14030) + (func $dummy14031) + (func $dummy14032) + (func $dummy14033) + (func $dummy14034) + (func $dummy14035) + (func $dummy14036) + (func $dummy14037) + (func $dummy14038) + (func $dummy14039) + (func $dummy14040) + (func $dummy14041) + (func $dummy14042) + (func $dummy14043) + (func $dummy14044) + (func $dummy14045) + (func $dummy14046) + (func $dummy14047) + (func $dummy14048) + (func $dummy14049) + (func $dummy14050) + (func $dummy14051) + (func $dummy14052) + (func $dummy14053) + (func $dummy14054) + (func $dummy14055) + (func $dummy14056) + (func $dummy14057) + (func $dummy14058) + (func $dummy14059) + (func $dummy14060) + (func $dummy14061) + (func $dummy14062) + (func $dummy14063) + (func $dummy14064) + (func $dummy14065) + (func $dummy14066) + (func $dummy14067) + (func $dummy14068) + (func $dummy14069) + (func $dummy14070) + (func $dummy14071) + (func $dummy14072) + (func $dummy14073) + (func $dummy14074) + (func $dummy14075) + (func $dummy14076) + (func $dummy14077) + (func $dummy14078) + (func $dummy14079) + (func $dummy14080) + (func $dummy14081) + (func $dummy14082) + (func $dummy14083) + (func $dummy14084) + (func $dummy14085) + (func $dummy14086) + (func $dummy14087) + (func $dummy14088) + (func $dummy14089) + (func $dummy14090) + (func $dummy14091) + (func $dummy14092) + (func $dummy14093) + (func $dummy14094) + (func $dummy14095) + (func $dummy14096) + (func $dummy14097) + (func $dummy14098) + (func $dummy14099) + (func $dummy14100) + (func $dummy14101) + (func $dummy14102) + (func $dummy14103) + (func $dummy14104) + (func $dummy14105) + (func $dummy14106) + (func $dummy14107) + (func $dummy14108) + (func $dummy14109) + (func $dummy14110) + (func $dummy14111) + (func $dummy14112) + (func $dummy14113) + (func $dummy14114) + (func $dummy14115) + (func $dummy14116) + (func $dummy14117) + (func $dummy14118) + (func $dummy14119) + (func $dummy14120) + (func $dummy14121) + (func $dummy14122) + (func $dummy14123) + (func $dummy14124) + (func $dummy14125) + (func $dummy14126) + (func $dummy14127) + (func $dummy14128) + (func $dummy14129) + (func $dummy14130) + (func $dummy14131) + (func $dummy14132) + (func $dummy14133) + (func $dummy14134) + (func $dummy14135) + (func $dummy14136) + (func $dummy14137) + (func $dummy14138) + (func $dummy14139) + (func $dummy14140) + (func $dummy14141) + (func $dummy14142) + (func $dummy14143) + (func $dummy14144) + (func $dummy14145) + (func $dummy14146) + (func $dummy14147) + (func $dummy14148) + (func $dummy14149) + (func $dummy14150) + (func $dummy14151) + (func $dummy14152) + (func $dummy14153) + (func $dummy14154) + (func $dummy14155) + (func $dummy14156) + (func $dummy14157) + (func $dummy14158) + (func $dummy14159) + (func $dummy14160) + (func $dummy14161) + (func $dummy14162) + (func $dummy14163) + (func $dummy14164) + (func $dummy14165) + (func $dummy14166) + (func $dummy14167) + (func $dummy14168) + (func $dummy14169) + (func $dummy14170) + (func $dummy14171) + (func $dummy14172) + (func $dummy14173) + (func $dummy14174) + (func $dummy14175) + (func $dummy14176) + (func $dummy14177) + (func $dummy14178) + (func $dummy14179) + (func $dummy14180) + (func $dummy14181) + (func $dummy14182) + (func $dummy14183) + (func $dummy14184) + (func $dummy14185) + (func $dummy14186) + (func $dummy14187) + (func $dummy14188) + (func $dummy14189) + (func $dummy14190) + (func $dummy14191) + (func $dummy14192) + (func $dummy14193) + (func $dummy14194) + (func $dummy14195) + (func $dummy14196) + (func $dummy14197) + (func $dummy14198) + (func $dummy14199) + (func $dummy14200) + (func $dummy14201) + (func $dummy14202) + (func $dummy14203) + (func $dummy14204) + (func $dummy14205) + (func $dummy14206) + (func $dummy14207) + (func $dummy14208) + (func $dummy14209) + (func $dummy14210) + (func $dummy14211) + (func $dummy14212) + (func $dummy14213) + (func $dummy14214) + (func $dummy14215) + (func $dummy14216) + (func $dummy14217) + (func $dummy14218) + (func $dummy14219) + (func $dummy14220) + (func $dummy14221) + (func $dummy14222) + (func $dummy14223) + (func $dummy14224) + (func $dummy14225) + (func $dummy14226) + (func $dummy14227) + (func $dummy14228) + (func $dummy14229) + (func $dummy14230) + (func $dummy14231) + (func $dummy14232) + (func $dummy14233) + (func $dummy14234) + (func $dummy14235) + (func $dummy14236) + (func $dummy14237) + (func $dummy14238) + (func $dummy14239) + (func $dummy14240) + (func $dummy14241) + (func $dummy14242) + (func $dummy14243) + (func $dummy14244) + (func $dummy14245) + (func $dummy14246) + (func $dummy14247) + (func $dummy14248) + (func $dummy14249) + (func $dummy14250) + (func $dummy14251) + (func $dummy14252) + (func $dummy14253) + (func $dummy14254) + (func $dummy14255) + (func $dummy14256) + (func $dummy14257) + (func $dummy14258) + (func $dummy14259) + (func $dummy14260) + (func $dummy14261) + (func $dummy14262) + (func $dummy14263) + (func $dummy14264) + (func $dummy14265) + (func $dummy14266) + (func $dummy14267) + (func $dummy14268) + (func $dummy14269) + (func $dummy14270) + (func $dummy14271) + (func $dummy14272) + (func $dummy14273) + (func $dummy14274) + (func $dummy14275) + (func $dummy14276) + (func $dummy14277) + (func $dummy14278) + (func $dummy14279) + (func $dummy14280) + (func $dummy14281) + (func $dummy14282) + (func $dummy14283) + (func $dummy14284) + (func $dummy14285) + (func $dummy14286) + (func $dummy14287) + (func $dummy14288) + (func $dummy14289) + (func $dummy14290) + (func $dummy14291) + (func $dummy14292) + (func $dummy14293) + (func $dummy14294) + (func $dummy14295) + (func $dummy14296) + (func $dummy14297) + (func $dummy14298) + (func $dummy14299) + (func $dummy14300) + (func $dummy14301) + (func $dummy14302) + (func $dummy14303) + (func $dummy14304) + (func $dummy14305) + (func $dummy14306) + (func $dummy14307) + (func $dummy14308) + (func $dummy14309) + (func $dummy14310) + (func $dummy14311) + (func $dummy14312) + (func $dummy14313) + (func $dummy14314) + (func $dummy14315) + (func $dummy14316) + (func $dummy14317) + (func $dummy14318) + (func $dummy14319) + (func $dummy14320) + (func $dummy14321) + (func $dummy14322) + (func $dummy14323) + (func $dummy14324) + (func $dummy14325) + (func $dummy14326) + (func $dummy14327) + (func $dummy14328) + (func $dummy14329) + (func $dummy14330) + (func $dummy14331) + (func $dummy14332) + (func $dummy14333) + (func $dummy14334) + (func $dummy14335) + (func $dummy14336) + (func $dummy14337) + (func $dummy14338) + (func $dummy14339) + (func $dummy14340) + (func $dummy14341) + (func $dummy14342) + (func $dummy14343) + (func $dummy14344) + (func $dummy14345) + (func $dummy14346) + (func $dummy14347) + (func $dummy14348) + (func $dummy14349) + (func $dummy14350) + (func $dummy14351) + (func $dummy14352) + (func $dummy14353) + (func $dummy14354) + (func $dummy14355) + (func $dummy14356) + (func $dummy14357) + (func $dummy14358) + (func $dummy14359) + (func $dummy14360) + (func $dummy14361) + (func $dummy14362) + (func $dummy14363) + (func $dummy14364) + (func $dummy14365) + (func $dummy14366) + (func $dummy14367) + (func $dummy14368) + (func $dummy14369) + (func $dummy14370) + (func $dummy14371) + (func $dummy14372) + (func $dummy14373) + (func $dummy14374) + (func $dummy14375) + (func $dummy14376) + (func $dummy14377) + (func $dummy14378) + (func $dummy14379) + (func $dummy14380) + (func $dummy14381) + (func $dummy14382) + (func $dummy14383) + (func $dummy14384) + (func $dummy14385) + (func $dummy14386) + (func $dummy14387) + (func $dummy14388) + (func $dummy14389) + (func $dummy14390) + (func $dummy14391) + (func $dummy14392) + (func $dummy14393) + (func $dummy14394) + (func $dummy14395) + (func $dummy14396) + (func $dummy14397) + (func $dummy14398) + (func $dummy14399) + (func $dummy14400) + (func $dummy14401) + (func $dummy14402) + (func $dummy14403) + (func $dummy14404) + (func $dummy14405) + (func $dummy14406) + (func $dummy14407) + (func $dummy14408) + (func $dummy14409) + (func $dummy14410) + (func $dummy14411) + (func $dummy14412) + (func $dummy14413) + (func $dummy14414) + (func $dummy14415) + (func $dummy14416) + (func $dummy14417) + (func $dummy14418) + (func $dummy14419) + (func $dummy14420) + (func $dummy14421) + (func $dummy14422) + (func $dummy14423) + (func $dummy14424) + (func $dummy14425) + (func $dummy14426) + (func $dummy14427) + (func $dummy14428) + (func $dummy14429) + (func $dummy14430) + (func $dummy14431) + (func $dummy14432) + (func $dummy14433) + (func $dummy14434) + (func $dummy14435) + (func $dummy14436) + (func $dummy14437) + (func $dummy14438) + (func $dummy14439) + (func $dummy14440) + (func $dummy14441) + (func $dummy14442) + (func $dummy14443) + (func $dummy14444) + (func $dummy14445) + (func $dummy14446) + (func $dummy14447) + (func $dummy14448) + (func $dummy14449) + (func $dummy14450) + (func $dummy14451) + (func $dummy14452) + (func $dummy14453) + (func $dummy14454) + (func $dummy14455) + (func $dummy14456) + (func $dummy14457) + (func $dummy14458) + (func $dummy14459) + (func $dummy14460) + (func $dummy14461) + (func $dummy14462) + (func $dummy14463) + (func $dummy14464) + (func $dummy14465) + (func $dummy14466) + (func $dummy14467) + (func $dummy14468) + (func $dummy14469) + (func $dummy14470) + (func $dummy14471) + (func $dummy14472) + (func $dummy14473) + (func $dummy14474) + (func $dummy14475) + (func $dummy14476) + (func $dummy14477) + (func $dummy14478) + (func $dummy14479) + (func $dummy14480) + (func $dummy14481) + (func $dummy14482) + (func $dummy14483) + (func $dummy14484) + (func $dummy14485) + (func $dummy14486) + (func $dummy14487) + (func $dummy14488) + (func $dummy14489) + (func $dummy14490) + (func $dummy14491) + (func $dummy14492) + (func $dummy14493) + (func $dummy14494) + (func $dummy14495) + (func $dummy14496) + (func $dummy14497) + (func $dummy14498) + (func $dummy14499) + (func $dummy14500) + (func $dummy14501) + (func $dummy14502) + (func $dummy14503) + (func $dummy14504) + (func $dummy14505) + (func $dummy14506) + (func $dummy14507) + (func $dummy14508) + (func $dummy14509) + (func $dummy14510) + (func $dummy14511) + (func $dummy14512) + (func $dummy14513) + (func $dummy14514) + (func $dummy14515) + (func $dummy14516) + (func $dummy14517) + (func $dummy14518) + (func $dummy14519) + (func $dummy14520) + (func $dummy14521) + (func $dummy14522) + (func $dummy14523) + (func $dummy14524) + (func $dummy14525) + (func $dummy14526) + (func $dummy14527) + (func $dummy14528) + (func $dummy14529) + (func $dummy14530) + (func $dummy14531) + (func $dummy14532) + (func $dummy14533) + (func $dummy14534) + (func $dummy14535) + (func $dummy14536) + (func $dummy14537) + (func $dummy14538) + (func $dummy14539) + (func $dummy14540) + (func $dummy14541) + (func $dummy14542) + (func $dummy14543) + (func $dummy14544) + (func $dummy14545) + (func $dummy14546) + (func $dummy14547) + (func $dummy14548) + (func $dummy14549) + (func $dummy14550) + (func $dummy14551) + (func $dummy14552) + (func $dummy14553) + (func $dummy14554) + (func $dummy14555) + (func $dummy14556) + (func $dummy14557) + (func $dummy14558) + (func $dummy14559) + (func $dummy14560) + (func $dummy14561) + (func $dummy14562) + (func $dummy14563) + (func $dummy14564) + (func $dummy14565) + (func $dummy14566) + (func $dummy14567) + (func $dummy14568) + (func $dummy14569) + (func $dummy14570) + (func $dummy14571) + (func $dummy14572) + (func $dummy14573) + (func $dummy14574) + (func $dummy14575) + (func $dummy14576) + (func $dummy14577) + (func $dummy14578) + (func $dummy14579) + (func $dummy14580) + (func $dummy14581) + (func $dummy14582) + (func $dummy14583) + (func $dummy14584) + (func $dummy14585) + (func $dummy14586) + (func $dummy14587) + (func $dummy14588) + (func $dummy14589) + (func $dummy14590) + (func $dummy14591) + (func $dummy14592) + (func $dummy14593) + (func $dummy14594) + (func $dummy14595) + (func $dummy14596) + (func $dummy14597) + (func $dummy14598) + (func $dummy14599) + (func $dummy14600) + (func $dummy14601) + (func $dummy14602) + (func $dummy14603) + (func $dummy14604) + (func $dummy14605) + (func $dummy14606) + (func $dummy14607) + (func $dummy14608) + (func $dummy14609) + (func $dummy14610) + (func $dummy14611) + (func $dummy14612) + (func $dummy14613) + (func $dummy14614) + (func $dummy14615) + (func $dummy14616) + (func $dummy14617) + (func $dummy14618) + (func $dummy14619) + (func $dummy14620) + (func $dummy14621) + (func $dummy14622) + (func $dummy14623) + (func $dummy14624) + (func $dummy14625) + (func $dummy14626) + (func $dummy14627) + (func $dummy14628) + (func $dummy14629) + (func $dummy14630) + (func $dummy14631) + (func $dummy14632) + (func $dummy14633) + (func $dummy14634) + (func $dummy14635) + (func $dummy14636) + (func $dummy14637) + (func $dummy14638) + (func $dummy14639) + (func $dummy14640) + (func $dummy14641) + (func $dummy14642) + (func $dummy14643) + (func $dummy14644) + (func $dummy14645) + (func $dummy14646) + (func $dummy14647) + (func $dummy14648) + (func $dummy14649) + (func $dummy14650) + (func $dummy14651) + (func $dummy14652) + (func $dummy14653) + (func $dummy14654) + (func $dummy14655) + (func $dummy14656) + (func $dummy14657) + (func $dummy14658) + (func $dummy14659) + (func $dummy14660) + (func $dummy14661) + (func $dummy14662) + (func $dummy14663) + (func $dummy14664) + (func $dummy14665) + (func $dummy14666) + (func $dummy14667) + (func $dummy14668) + (func $dummy14669) + (func $dummy14670) + (func $dummy14671) + (func $dummy14672) + (func $dummy14673) + (func $dummy14674) + (func $dummy14675) + (func $dummy14676) + (func $dummy14677) + (func $dummy14678) + (func $dummy14679) + (func $dummy14680) + (func $dummy14681) + (func $dummy14682) + (func $dummy14683) + (func $dummy14684) + (func $dummy14685) + (func $dummy14686) + (func $dummy14687) + (func $dummy14688) + (func $dummy14689) + (func $dummy14690) + (func $dummy14691) + (func $dummy14692) + (func $dummy14693) + (func $dummy14694) + (func $dummy14695) + (func $dummy14696) + (func $dummy14697) + (func $dummy14698) + (func $dummy14699) + (func $dummy14700) + (func $dummy14701) + (func $dummy14702) + (func $dummy14703) + (func $dummy14704) + (func $dummy14705) + (func $dummy14706) + (func $dummy14707) + (func $dummy14708) + (func $dummy14709) + (func $dummy14710) + (func $dummy14711) + (func $dummy14712) + (func $dummy14713) + (func $dummy14714) + (func $dummy14715) + (func $dummy14716) + (func $dummy14717) + (func $dummy14718) + (func $dummy14719) + (func $dummy14720) + (func $dummy14721) + (func $dummy14722) + (func $dummy14723) + (func $dummy14724) + (func $dummy14725) + (func $dummy14726) + (func $dummy14727) + (func $dummy14728) + (func $dummy14729) + (func $dummy14730) + (func $dummy14731) + (func $dummy14732) + (func $dummy14733) + (func $dummy14734) + (func $dummy14735) + (func $dummy14736) + (func $dummy14737) + (func $dummy14738) + (func $dummy14739) + (func $dummy14740) + (func $dummy14741) + (func $dummy14742) + (func $dummy14743) + (func $dummy14744) + (func $dummy14745) + (func $dummy14746) + (func $dummy14747) + (func $dummy14748) + (func $dummy14749) + (func $dummy14750) + (func $dummy14751) + (func $dummy14752) + (func $dummy14753) + (func $dummy14754) + (func $dummy14755) + (func $dummy14756) + (func $dummy14757) + (func $dummy14758) + (func $dummy14759) + (func $dummy14760) + (func $dummy14761) + (func $dummy14762) + (func $dummy14763) + (func $dummy14764) + (func $dummy14765) + (func $dummy14766) + (func $dummy14767) + (func $dummy14768) + (func $dummy14769) + (func $dummy14770) + (func $dummy14771) + (func $dummy14772) + (func $dummy14773) + (func $dummy14774) + (func $dummy14775) + (func $dummy14776) + (func $dummy14777) + (func $dummy14778) + (func $dummy14779) + (func $dummy14780) + (func $dummy14781) + (func $dummy14782) + (func $dummy14783) + (func $dummy14784) + (func $dummy14785) + (func $dummy14786) + (func $dummy14787) + (func $dummy14788) + (func $dummy14789) + (func $dummy14790) + (func $dummy14791) + (func $dummy14792) + (func $dummy14793) + (func $dummy14794) + (func $dummy14795) + (func $dummy14796) + (func $dummy14797) + (func $dummy14798) + (func $dummy14799) + (func $dummy14800) + (func $dummy14801) + (func $dummy14802) + (func $dummy14803) + (func $dummy14804) + (func $dummy14805) + (func $dummy14806) + (func $dummy14807) + (func $dummy14808) + (func $dummy14809) + (func $dummy14810) + (func $dummy14811) + (func $dummy14812) + (func $dummy14813) + (func $dummy14814) + (func $dummy14815) + (func $dummy14816) + (func $dummy14817) + (func $dummy14818) + (func $dummy14819) + (func $dummy14820) + (func $dummy14821) + (func $dummy14822) + (func $dummy14823) + (func $dummy14824) + (func $dummy14825) + (func $dummy14826) + (func $dummy14827) + (func $dummy14828) + (func $dummy14829) + (func $dummy14830) + (func $dummy14831) + (func $dummy14832) + (func $dummy14833) + (func $dummy14834) + (func $dummy14835) + (func $dummy14836) + (func $dummy14837) + (func $dummy14838) + (func $dummy14839) + (func $dummy14840) + (func $dummy14841) + (func $dummy14842) + (func $dummy14843) + (func $dummy14844) + (func $dummy14845) + (func $dummy14846) + (func $dummy14847) + (func $dummy14848) + (func $dummy14849) + (func $dummy14850) + (func $dummy14851) + (func $dummy14852) + (func $dummy14853) + (func $dummy14854) + (func $dummy14855) + (func $dummy14856) + (func $dummy14857) + (func $dummy14858) + (func $dummy14859) + (func $dummy14860) + (func $dummy14861) + (func $dummy14862) + (func $dummy14863) + (func $dummy14864) + (func $dummy14865) + (func $dummy14866) + (func $dummy14867) + (func $dummy14868) + (func $dummy14869) + (func $dummy14870) + (func $dummy14871) + (func $dummy14872) + (func $dummy14873) + (func $dummy14874) + (func $dummy14875) + (func $dummy14876) + (func $dummy14877) + (func $dummy14878) + (func $dummy14879) + (func $dummy14880) + (func $dummy14881) + (func $dummy14882) + (func $dummy14883) + (func $dummy14884) + (func $dummy14885) + (func $dummy14886) + (func $dummy14887) + (func $dummy14888) + (func $dummy14889) + (func $dummy14890) + (func $dummy14891) + (func $dummy14892) + (func $dummy14893) + (func $dummy14894) + (func $dummy14895) + (func $dummy14896) + (func $dummy14897) + (func $dummy14898) + (func $dummy14899) + (func $dummy14900) + (func $dummy14901) + (func $dummy14902) + (func $dummy14903) + (func $dummy14904) + (func $dummy14905) + (func $dummy14906) + (func $dummy14907) + (func $dummy14908) + (func $dummy14909) + (func $dummy14910) + (func $dummy14911) + (func $dummy14912) + (func $dummy14913) + (func $dummy14914) + (func $dummy14915) + (func $dummy14916) + (func $dummy14917) + (func $dummy14918) + (func $dummy14919) + (func $dummy14920) + (func $dummy14921) + (func $dummy14922) + (func $dummy14923) + (func $dummy14924) + (func $dummy14925) + (func $dummy14926) + (func $dummy14927) + (func $dummy14928) + (func $dummy14929) + (func $dummy14930) + (func $dummy14931) + (func $dummy14932) + (func $dummy14933) + (func $dummy14934) + (func $dummy14935) + (func $dummy14936) + (func $dummy14937) + (func $dummy14938) + (func $dummy14939) + (func $dummy14940) + (func $dummy14941) + (func $dummy14942) + (func $dummy14943) + (func $dummy14944) + (func $dummy14945) + (func $dummy14946) + (func $dummy14947) + (func $dummy14948) + (func $dummy14949) + (func $dummy14950) + (func $dummy14951) + (func $dummy14952) + (func $dummy14953) + (func $dummy14954) + (func $dummy14955) + (func $dummy14956) + (func $dummy14957) + (func $dummy14958) + (func $dummy14959) + (func $dummy14960) + (func $dummy14961) + (func $dummy14962) + (func $dummy14963) + (func $dummy14964) + (func $dummy14965) + (func $dummy14966) + (func $dummy14967) + (func $dummy14968) + (func $dummy14969) + (func $dummy14970) + (func $dummy14971) + (func $dummy14972) + (func $dummy14973) + (func $dummy14974) + (func $dummy14975) + (func $dummy14976) + (func $dummy14977) + (func $dummy14978) + (func $dummy14979) + (func $dummy14980) + (func $dummy14981) + (func $dummy14982) + (func $dummy14983) + (func $dummy14984) + (func $dummy14985) + (func $dummy14986) + (func $dummy14987) + (func $dummy14988) + (func $dummy14989) + (func $dummy14990) + (func $dummy14991) + (func $dummy14992) + (func $dummy14993) + (func $dummy14994) + (func $dummy14995) + (func $dummy14996) + (func $dummy14997) + (func $dummy14998) + (func $dummy14999) + (func $dummy15000) + (func $dummy15001) + (func $dummy15002) + (func $dummy15003) + (func $dummy15004) + (func $dummy15005) + (func $dummy15006) + (func $dummy15007) + (func $dummy15008) + (func $dummy15009) + (func $dummy15010) + (func $dummy15011) + (func $dummy15012) + (func $dummy15013) + (func $dummy15014) + (func $dummy15015) + (func $dummy15016) + (func $dummy15017) + (func $dummy15018) + (func $dummy15019) + (func $dummy15020) + (func $dummy15021) + (func $dummy15022) + (func $dummy15023) + (func $dummy15024) + (func $dummy15025) + (func $dummy15026) + (func $dummy15027) + (func $dummy15028) + (func $dummy15029) + (func $dummy15030) + (func $dummy15031) + (func $dummy15032) + (func $dummy15033) + (func $dummy15034) + (func $dummy15035) + (func $dummy15036) + (func $dummy15037) + (func $dummy15038) + (func $dummy15039) + (func $dummy15040) + (func $dummy15041) + (func $dummy15042) + (func $dummy15043) + (func $dummy15044) + (func $dummy15045) + (func $dummy15046) + (func $dummy15047) + (func $dummy15048) + (func $dummy15049) + (func $dummy15050) + (func $dummy15051) + (func $dummy15052) + (func $dummy15053) + (func $dummy15054) + (func $dummy15055) + (func $dummy15056) + (func $dummy15057) + (func $dummy15058) + (func $dummy15059) + (func $dummy15060) + (func $dummy15061) + (func $dummy15062) + (func $dummy15063) + (func $dummy15064) + (func $dummy15065) + (func $dummy15066) + (func $dummy15067) + (func $dummy15068) + (func $dummy15069) + (func $dummy15070) + (func $dummy15071) + (func $dummy15072) + (func $dummy15073) + (func $dummy15074) + (func $dummy15075) + (func $dummy15076) + (func $dummy15077) + (func $dummy15078) + (func $dummy15079) + (func $dummy15080) + (func $dummy15081) + (func $dummy15082) + (func $dummy15083) + (func $dummy15084) + (func $dummy15085) + (func $dummy15086) + (func $dummy15087) + (func $dummy15088) + (func $dummy15089) + (func $dummy15090) + (func $dummy15091) + (func $dummy15092) + (func $dummy15093) + (func $dummy15094) + (func $dummy15095) + (func $dummy15096) + (func $dummy15097) + (func $dummy15098) + (func $dummy15099) + (func $dummy15100) + (func $dummy15101) + (func $dummy15102) + (func $dummy15103) + (func $dummy15104) + (func $dummy15105) + (func $dummy15106) + (func $dummy15107) + (func $dummy15108) + (func $dummy15109) + (func $dummy15110) + (func $dummy15111) + (func $dummy15112) + (func $dummy15113) + (func $dummy15114) + (func $dummy15115) + (func $dummy15116) + (func $dummy15117) + (func $dummy15118) + (func $dummy15119) + (func $dummy15120) + (func $dummy15121) + (func $dummy15122) + (func $dummy15123) + (func $dummy15124) + (func $dummy15125) + (func $dummy15126) + (func $dummy15127) + (func $dummy15128) + (func $dummy15129) + (func $dummy15130) + (func $dummy15131) + (func $dummy15132) + (func $dummy15133) + (func $dummy15134) + (func $dummy15135) + (func $dummy15136) + (func $dummy15137) + (func $dummy15138) + (func $dummy15139) + (func $dummy15140) + (func $dummy15141) + (func $dummy15142) + (func $dummy15143) + (func $dummy15144) + (func $dummy15145) + (func $dummy15146) + (func $dummy15147) + (func $dummy15148) + (func $dummy15149) + (func $dummy15150) + (func $dummy15151) + (func $dummy15152) + (func $dummy15153) + (func $dummy15154) + (func $dummy15155) + (func $dummy15156) + (func $dummy15157) + (func $dummy15158) + (func $dummy15159) + (func $dummy15160) + (func $dummy15161) + (func $dummy15162) + (func $dummy15163) + (func $dummy15164) + (func $dummy15165) + (func $dummy15166) + (func $dummy15167) + (func $dummy15168) + (func $dummy15169) + (func $dummy15170) + (func $dummy15171) + (func $dummy15172) + (func $dummy15173) + (func $dummy15174) + (func $dummy15175) + (func $dummy15176) + (func $dummy15177) + (func $dummy15178) + (func $dummy15179) + (func $dummy15180) + (func $dummy15181) + (func $dummy15182) + (func $dummy15183) + (func $dummy15184) + (func $dummy15185) + (func $dummy15186) + (func $dummy15187) + (func $dummy15188) + (func $dummy15189) + (func $dummy15190) + (func $dummy15191) + (func $dummy15192) + (func $dummy15193) + (func $dummy15194) + (func $dummy15195) + (func $dummy15196) + (func $dummy15197) + (func $dummy15198) + (func $dummy15199) + (func $dummy15200) + (func $dummy15201) + (func $dummy15202) + (func $dummy15203) + (func $dummy15204) + (func $dummy15205) + (func $dummy15206) + (func $dummy15207) + (func $dummy15208) + (func $dummy15209) + (func $dummy15210) + (func $dummy15211) + (func $dummy15212) + (func $dummy15213) + (func $dummy15214) + (func $dummy15215) + (func $dummy15216) + (func $dummy15217) + (func $dummy15218) + (func $dummy15219) + (func $dummy15220) + (func $dummy15221) + (func $dummy15222) + (func $dummy15223) + (func $dummy15224) + (func $dummy15225) + (func $dummy15226) + (func $dummy15227) + (func $dummy15228) + (func $dummy15229) + (func $dummy15230) + (func $dummy15231) + (func $dummy15232) + (func $dummy15233) + (func $dummy15234) + (func $dummy15235) + (func $dummy15236) + (func $dummy15237) + (func $dummy15238) + (func $dummy15239) + (func $dummy15240) + (func $dummy15241) + (func $dummy15242) + (func $dummy15243) + (func $dummy15244) + (func $dummy15245) + (func $dummy15246) + (func $dummy15247) + (func $dummy15248) + (func $dummy15249) + (func $dummy15250) + (func $dummy15251) + (func $dummy15252) + (func $dummy15253) + (func $dummy15254) + (func $dummy15255) + (func $dummy15256) + (func $dummy15257) + (func $dummy15258) + (func $dummy15259) + (func $dummy15260) + (func $dummy15261) + (func $dummy15262) + (func $dummy15263) + (func $dummy15264) + (func $dummy15265) + (func $dummy15266) + (func $dummy15267) + (func $dummy15268) + (func $dummy15269) + (func $dummy15270) + (func $dummy15271) + (func $dummy15272) + (func $dummy15273) + (func $dummy15274) + (func $dummy15275) + (func $dummy15276) + (func $dummy15277) + (func $dummy15278) + (func $dummy15279) + (func $dummy15280) + (func $dummy15281) + (func $dummy15282) + (func $dummy15283) + (func $dummy15284) + (func $dummy15285) + (func $dummy15286) + (func $dummy15287) + (func $dummy15288) + (func $dummy15289) + (func $dummy15290) + (func $dummy15291) + (func $dummy15292) + (func $dummy15293) + (func $dummy15294) + (func $dummy15295) + (func $dummy15296) + (func $dummy15297) + (func $dummy15298) + (func $dummy15299) + (func $dummy15300) + (func $dummy15301) + (func $dummy15302) + (func $dummy15303) + (func $dummy15304) + (func $dummy15305) + (func $dummy15306) + (func $dummy15307) + (func $dummy15308) + (func $dummy15309) + (func $dummy15310) + (func $dummy15311) + (func $dummy15312) + (func $dummy15313) + (func $dummy15314) + (func $dummy15315) + (func $dummy15316) + (func $dummy15317) + (func $dummy15318) + (func $dummy15319) + (func $dummy15320) + (func $dummy15321) + (func $dummy15322) + (func $dummy15323) + (func $dummy15324) + (func $dummy15325) + (func $dummy15326) + (func $dummy15327) + (func $dummy15328) + (func $dummy15329) + (func $dummy15330) + (func $dummy15331) + (func $dummy15332) + (func $dummy15333) + (func $dummy15334) + (func $dummy15335) + (func $dummy15336) + (func $dummy15337) + (func $dummy15338) + (func $dummy15339) + (func $dummy15340) + (func $dummy15341) + (func $dummy15342) + (func $dummy15343) + (func $dummy15344) + (func $dummy15345) + (func $dummy15346) + (func $dummy15347) + (func $dummy15348) + (func $dummy15349) + (func $dummy15350) + (func $dummy15351) + (func $dummy15352) + (func $dummy15353) + (func $dummy15354) + (func $dummy15355) + (func $dummy15356) + (func $dummy15357) + (func $dummy15358) + (func $dummy15359) + (func $dummy15360) + (func $dummy15361) + (func $dummy15362) + (func $dummy15363) + (func $dummy15364) + (func $dummy15365) + (func $dummy15366) + (func $dummy15367) + (func $dummy15368) + (func $dummy15369) + (func $dummy15370) + (func $dummy15371) + (func $dummy15372) + (func $dummy15373) + (func $dummy15374) + (func $dummy15375) + (func $dummy15376) + (func $dummy15377) + (func $dummy15378) + (func $dummy15379) + (func $dummy15380) + (func $dummy15381) + (func $dummy15382) + (func $dummy15383) + (func $dummy15384) + (func $dummy15385) + (func $dummy15386) + (func $dummy15387) + (func $dummy15388) + (func $dummy15389) + (func $dummy15390) + (func $dummy15391) + (func $dummy15392) + (func $dummy15393) + (func $dummy15394) + (func $dummy15395) + (func $dummy15396) + (func $dummy15397) + (func $dummy15398) + (func $dummy15399) + (func $dummy15400) + (func $dummy15401) + (func $dummy15402) + (func $dummy15403) + (func $dummy15404) + (func $dummy15405) + (func $dummy15406) + (func $dummy15407) + (func $dummy15408) + (func $dummy15409) + (func $dummy15410) + (func $dummy15411) + (func $dummy15412) + (func $dummy15413) + (func $dummy15414) + (func $dummy15415) + (func $dummy15416) + (func $dummy15417) + (func $dummy15418) + (func $dummy15419) + (func $dummy15420) + (func $dummy15421) + (func $dummy15422) + (func $dummy15423) + (func $dummy15424) + (func $dummy15425) + (func $dummy15426) + (func $dummy15427) + (func $dummy15428) + (func $dummy15429) + (func $dummy15430) + (func $dummy15431) + (func $dummy15432) + (func $dummy15433) + (func $dummy15434) + (func $dummy15435) + (func $dummy15436) + (func $dummy15437) + (func $dummy15438) + (func $dummy15439) + (func $dummy15440) + (func $dummy15441) + (func $dummy15442) + (func $dummy15443) + (func $dummy15444) + (func $dummy15445) + (func $dummy15446) + (func $dummy15447) + (func $dummy15448) + (func $dummy15449) + (func $dummy15450) + (func $dummy15451) + (func $dummy15452) + (func $dummy15453) + (func $dummy15454) + (func $dummy15455) + (func $dummy15456) + (func $dummy15457) + (func $dummy15458) + (func $dummy15459) + (func $dummy15460) + (func $dummy15461) + (func $dummy15462) + (func $dummy15463) + (func $dummy15464) + (func $dummy15465) + (func $dummy15466) + (func $dummy15467) + (func $dummy15468) + (func $dummy15469) + (func $dummy15470) + (func $dummy15471) + (func $dummy15472) + (func $dummy15473) + (func $dummy15474) + (func $dummy15475) + (func $dummy15476) + (func $dummy15477) + (func $dummy15478) + (func $dummy15479) + (func $dummy15480) + (func $dummy15481) + (func $dummy15482) + (func $dummy15483) + (func $dummy15484) + (func $dummy15485) + (func $dummy15486) + (func $dummy15487) + (func $dummy15488) + (func $dummy15489) + (func $dummy15490) + (func $dummy15491) + (func $dummy15492) + (func $dummy15493) + (func $dummy15494) + (func $dummy15495) + (func $dummy15496) + (func $dummy15497) + (func $dummy15498) + (func $dummy15499) + (func $dummy15500) + (func $dummy15501) + (func $dummy15502) + (func $dummy15503) + (func $dummy15504) + (func $dummy15505) + (func $dummy15506) + (func $dummy15507) + (func $dummy15508) + (func $dummy15509) + (func $dummy15510) + (func $dummy15511) + (func $dummy15512) + (func $dummy15513) + (func $dummy15514) + (func $dummy15515) + (func $dummy15516) + (func $dummy15517) + (func $dummy15518) + (func $dummy15519) + (func $dummy15520) + (func $dummy15521) + (func $dummy15522) + (func $dummy15523) + (func $dummy15524) + (func $dummy15525) + (func $dummy15526) + (func $dummy15527) + (func $dummy15528) + (func $dummy15529) + (func $dummy15530) + (func $dummy15531) + (func $dummy15532) + (func $dummy15533) + (func $dummy15534) + (func $dummy15535) + (func $dummy15536) + (func $dummy15537) + (func $dummy15538) + (func $dummy15539) + (func $dummy15540) + (func $dummy15541) + (func $dummy15542) + (func $dummy15543) + (func $dummy15544) + (func $dummy15545) + (func $dummy15546) + (func $dummy15547) + (func $dummy15548) + (func $dummy15549) + (func $dummy15550) + (func $dummy15551) + (func $dummy15552) + (func $dummy15553) + (func $dummy15554) + (func $dummy15555) + (func $dummy15556) + (func $dummy15557) + (func $dummy15558) + (func $dummy15559) + (func $dummy15560) + (func $dummy15561) + (func $dummy15562) + (func $dummy15563) + (func $dummy15564) + (func $dummy15565) + (func $dummy15566) + (func $dummy15567) + (func $dummy15568) + (func $dummy15569) + (func $dummy15570) + (func $dummy15571) + (func $dummy15572) + (func $dummy15573) + (func $dummy15574) + (func $dummy15575) + (func $dummy15576) + (func $dummy15577) + (func $dummy15578) + (func $dummy15579) + (func $dummy15580) + (func $dummy15581) + (func $dummy15582) + (func $dummy15583) + (func $dummy15584) + (func $dummy15585) + (func $dummy15586) + (func $dummy15587) + (func $dummy15588) + (func $dummy15589) + (func $dummy15590) + (func $dummy15591) + (func $dummy15592) + (func $dummy15593) + (func $dummy15594) + (func $dummy15595) + (func $dummy15596) + (func $dummy15597) + (func $dummy15598) + (func $dummy15599) + (func $dummy15600) + (func $dummy15601) + (func $dummy15602) + (func $dummy15603) + (func $dummy15604) + (func $dummy15605) + (func $dummy15606) + (func $dummy15607) + (func $dummy15608) + (func $dummy15609) + (func $dummy15610) + (func $dummy15611) + (func $dummy15612) + (func $dummy15613) + (func $dummy15614) + (func $dummy15615) + (func $dummy15616) + (func $dummy15617) + (func $dummy15618) + (func $dummy15619) + (func $dummy15620) + (func $dummy15621) + (func $dummy15622) + (func $dummy15623) + (func $dummy15624) + (func $dummy15625) + (func $dummy15626) + (func $dummy15627) + (func $dummy15628) + (func $dummy15629) + (func $dummy15630) + (func $dummy15631) + (func $dummy15632) + (func $dummy15633) + (func $dummy15634) + (func $dummy15635) + (func $dummy15636) + (func $dummy15637) + (func $dummy15638) + (func $dummy15639) + (func $dummy15640) + (func $dummy15641) + (func $dummy15642) + (func $dummy15643) + (func $dummy15644) + (func $dummy15645) + (func $dummy15646) + (func $dummy15647) + (func $dummy15648) + (func $dummy15649) + (func $dummy15650) + (func $dummy15651) + (func $dummy15652) + (func $dummy15653) + (func $dummy15654) + (func $dummy15655) + (func $dummy15656) + (func $dummy15657) + (func $dummy15658) + (func $dummy15659) + (func $dummy15660) + (func $dummy15661) + (func $dummy15662) + (func $dummy15663) + (func $dummy15664) + (func $dummy15665) + (func $dummy15666) + (func $dummy15667) + (func $dummy15668) + (func $dummy15669) + (func $dummy15670) + (func $dummy15671) + (func $dummy15672) + (func $dummy15673) + (func $dummy15674) + (func $dummy15675) + (func $dummy15676) + (func $dummy15677) + (func $dummy15678) + (func $dummy15679) + (func $dummy15680) + (func $dummy15681) + (func $dummy15682) + (func $dummy15683) + (func $dummy15684) + (func $dummy15685) + (func $dummy15686) + (func $dummy15687) + (func $dummy15688) + (func $dummy15689) + (func $dummy15690) + (func $dummy15691) + (func $dummy15692) + (func $dummy15693) + (func $dummy15694) + (func $dummy15695) + (func $dummy15696) + (func $dummy15697) + (func $dummy15698) + (func $dummy15699) + (func $dummy15700) + (func $dummy15701) + (func $dummy15702) + (func $dummy15703) + (func $dummy15704) + (func $dummy15705) + (func $dummy15706) + (func $dummy15707) + (func $dummy15708) + (func $dummy15709) + (func $dummy15710) + (func $dummy15711) + (func $dummy15712) + (func $dummy15713) + (func $dummy15714) + (func $dummy15715) + (func $dummy15716) + (func $dummy15717) + (func $dummy15718) + (func $dummy15719) + (func $dummy15720) + (func $dummy15721) + (func $dummy15722) + (func $dummy15723) + (func $dummy15724) + (func $dummy15725) + (func $dummy15726) + (func $dummy15727) + (func $dummy15728) + (func $dummy15729) + (func $dummy15730) + (func $dummy15731) + (func $dummy15732) + (func $dummy15733) + (func $dummy15734) + (func $dummy15735) + (func $dummy15736) + (func $dummy15737) + (func $dummy15738) + (func $dummy15739) + (func $dummy15740) + (func $dummy15741) + (func $dummy15742) + (func $dummy15743) + (func $dummy15744) + (func $dummy15745) + (func $dummy15746) + (func $dummy15747) + (func $dummy15748) + (func $dummy15749) + (func $dummy15750) + (func $dummy15751) + (func $dummy15752) + (func $dummy15753) + (func $dummy15754) + (func $dummy15755) + (func $dummy15756) + (func $dummy15757) + (func $dummy15758) + (func $dummy15759) + (func $dummy15760) + (func $dummy15761) + (func $dummy15762) + (func $dummy15763) + (func $dummy15764) + (func $dummy15765) + (func $dummy15766) + (func $dummy15767) + (func $dummy15768) + (func $dummy15769) + (func $dummy15770) + (func $dummy15771) + (func $dummy15772) + (func $dummy15773) + (func $dummy15774) + (func $dummy15775) + (func $dummy15776) + (func $dummy15777) + (func $dummy15778) + (func $dummy15779) + (func $dummy15780) + (func $dummy15781) + (func $dummy15782) + (func $dummy15783) + (func $dummy15784) + (func $dummy15785) + (func $dummy15786) + (func $dummy15787) + (func $dummy15788) + (func $dummy15789) + (func $dummy15790) + (func $dummy15791) + (func $dummy15792) + (func $dummy15793) + (func $dummy15794) + (func $dummy15795) + (func $dummy15796) + (func $dummy15797) + (func $dummy15798) + (func $dummy15799) + (func $dummy15800) + (func $dummy15801) + (func $dummy15802) + (func $dummy15803) + (func $dummy15804) + (func $dummy15805) + (func $dummy15806) + (func $dummy15807) + (func $dummy15808) + (func $dummy15809) + (func $dummy15810) + (func $dummy15811) + (func $dummy15812) + (func $dummy15813) + (func $dummy15814) + (func $dummy15815) + (func $dummy15816) + (func $dummy15817) + (func $dummy15818) + (func $dummy15819) + (func $dummy15820) + (func $dummy15821) + (func $dummy15822) + (func $dummy15823) + (func $dummy15824) + (func $dummy15825) + (func $dummy15826) + (func $dummy15827) + (func $dummy15828) + (func $dummy15829) + (func $dummy15830) + (func $dummy15831) + (func $dummy15832) + (func $dummy15833) + (func $dummy15834) + (func $dummy15835) + (func $dummy15836) + (func $dummy15837) + (func $dummy15838) + (func $dummy15839) + (func $dummy15840) + (func $dummy15841) + (func $dummy15842) + (func $dummy15843) + (func $dummy15844) + (func $dummy15845) + (func $dummy15846) + (func $dummy15847) + (func $dummy15848) + (func $dummy15849) + (func $dummy15850) + (func $dummy15851) + (func $dummy15852) + (func $dummy15853) + (func $dummy15854) + (func $dummy15855) + (func $dummy15856) + (func $dummy15857) + (func $dummy15858) + (func $dummy15859) + (func $dummy15860) + (func $dummy15861) + (func $dummy15862) + (func $dummy15863) + (func $dummy15864) + (func $dummy15865) + (func $dummy15866) + (func $dummy15867) + (func $dummy15868) + (func $dummy15869) + (func $dummy15870) + (func $dummy15871) + (func $dummy15872) + (func $dummy15873) + (func $dummy15874) + (func $dummy15875) + (func $dummy15876) + (func $dummy15877) + (func $dummy15878) + (func $dummy15879) + (func $dummy15880) + (func $dummy15881) + (func $dummy15882) + (func $dummy15883) + (func $dummy15884) + (func $dummy15885) + (func $dummy15886) + (func $dummy15887) + (func $dummy15888) + (func $dummy15889) + (func $dummy15890) + (func $dummy15891) + (func $dummy15892) + (func $dummy15893) + (func $dummy15894) + (func $dummy15895) + (func $dummy15896) + (func $dummy15897) + (func $dummy15898) + (func $dummy15899) + (func $dummy15900) + (func $dummy15901) + (func $dummy15902) + (func $dummy15903) + (func $dummy15904) + (func $dummy15905) + (func $dummy15906) + (func $dummy15907) + (func $dummy15908) + (func $dummy15909) + (func $dummy15910) + (func $dummy15911) + (func $dummy15912) + (func $dummy15913) + (func $dummy15914) + (func $dummy15915) + (func $dummy15916) + (func $dummy15917) + (func $dummy15918) + (func $dummy15919) + (func $dummy15920) + (func $dummy15921) + (func $dummy15922) + (func $dummy15923) + (func $dummy15924) + (func $dummy15925) + (func $dummy15926) + (func $dummy15927) + (func $dummy15928) + (func $dummy15929) + (func $dummy15930) + (func $dummy15931) + (func $dummy15932) + (func $dummy15933) + (func $dummy15934) + (func $dummy15935) + (func $dummy15936) + (func $dummy15937) + (func $dummy15938) + (func $dummy15939) + (func $dummy15940) + (func $dummy15941) + (func $dummy15942) + (func $dummy15943) + (func $dummy15944) + (func $dummy15945) + (func $dummy15946) + (func $dummy15947) + (func $dummy15948) + (func $dummy15949) + (func $dummy15950) + (func $dummy15951) + (func $dummy15952) + (func $dummy15953) + (func $dummy15954) + (func $dummy15955) + (func $dummy15956) + (func $dummy15957) + (func $dummy15958) + (func $dummy15959) + (func $dummy15960) + (func $dummy15961) + (func $dummy15962) + (func $dummy15963) + (func $dummy15964) + (func $dummy15965) + (func $dummy15966) + (func $dummy15967) + (func $dummy15968) + (func $dummy15969) + (func $dummy15970) + (func $dummy15971) + (func $dummy15972) + (func $dummy15973) + (func $dummy15974) + (func $dummy15975) + (func $dummy15976) + (func $dummy15977) + (func $dummy15978) + (func $dummy15979) + (func $dummy15980) + (func $dummy15981) + (func $dummy15982) + (func $dummy15983) + (func $dummy15984) + (func $dummy15985) + (func $dummy15986) + (func $dummy15987) + (func $dummy15988) + (func $dummy15989) + (func $dummy15990) + (func $dummy15991) + (func $dummy15992) + (func $dummy15993) + (func $dummy15994) + (func $dummy15995) + (func $dummy15996) + (func $dummy15997) + (func $dummy15998) + (func $dummy15999) + (func $dummy16000) + (func $dummy16001) + (func $dummy16002) + (func $dummy16003) + (func $dummy16004) + (func $dummy16005) + (func $dummy16006) + (func $dummy16007) + (func $dummy16008) + (func $dummy16009) + (func $dummy16010) + (func $dummy16011) + (func $dummy16012) + (func $dummy16013) + (func $dummy16014) + (func $dummy16015) + (func $dummy16016) + (func $dummy16017) + (func $dummy16018) + (func $dummy16019) + (func $dummy16020) + (func $dummy16021) + (func $dummy16022) + (func $dummy16023) + (func $dummy16024) + (func $dummy16025) + (func $dummy16026) + (func $dummy16027) + (func $dummy16028) + (func $dummy16029) + (func $dummy16030) + (func $dummy16031) + (func $dummy16032) + (func $dummy16033) + (func $dummy16034) + (func $dummy16035) + (func $dummy16036) + (func $dummy16037) + (func $dummy16038) + (func $dummy16039) + (func $dummy16040) + (func $dummy16041) + (func $dummy16042) + (func $dummy16043) + (func $dummy16044) + (func $dummy16045) + (func $dummy16046) + (func $dummy16047) + (func $dummy16048) + (func $dummy16049) + (func $dummy16050) + (func $dummy16051) + (func $dummy16052) + (func $dummy16053) + (func $dummy16054) + (func $dummy16055) + (func $dummy16056) + (func $dummy16057) + (func $dummy16058) + (func $dummy16059) + (func $dummy16060) + (func $dummy16061) + (func $dummy16062) + (func $dummy16063) + (func $dummy16064) + (func $dummy16065) + (func $dummy16066) + (func $dummy16067) + (func $dummy16068) + (func $dummy16069) + (func $dummy16070) + (func $dummy16071) + (func $dummy16072) + (func $dummy16073) + (func $dummy16074) + (func $dummy16075) + (func $dummy16076) + (func $dummy16077) + (func $dummy16078) + (func $dummy16079) + (func $dummy16080) + (func $dummy16081) + (func $dummy16082) + (func $dummy16083) + (func $dummy16084) + (func $dummy16085) + (func $dummy16086) + (func $dummy16087) + (func $dummy16088) + (func $dummy16089) + (func $dummy16090) + (func $dummy16091) + (func $dummy16092) + (func $dummy16093) + (func $dummy16094) + (func $dummy16095) + (func $dummy16096) + (func $dummy16097) + (func $dummy16098) + (func $dummy16099) + (func $dummy16100) + (func $dummy16101) + (func $dummy16102) + (func $dummy16103) + (func $dummy16104) + (func $dummy16105) + (func $dummy16106) + (func $dummy16107) + (func $dummy16108) + (func $dummy16109) + (func $dummy16110) + (func $dummy16111) + (func $dummy16112) + (func $dummy16113) + (func $dummy16114) + (func $dummy16115) + (func $dummy16116) + (func $dummy16117) + (func $dummy16118) + (func $dummy16119) + (func $dummy16120) + (func $dummy16121) + (func $dummy16122) + (func $dummy16123) + (func $dummy16124) + (func $dummy16125) + (func $dummy16126) + (func $dummy16127) + (func $dummy16128) + (func $dummy16129) + (func $dummy16130) + (func $dummy16131) + (func $dummy16132) + (func $dummy16133) + (func $dummy16134) + (func $dummy16135) + (func $dummy16136) + (func $dummy16137) + (func $dummy16138) + (func $dummy16139) + (func $dummy16140) + (func $dummy16141) + (func $dummy16142) + (func $dummy16143) + (func $dummy16144) + (func $dummy16145) + (func $dummy16146) + (func $dummy16147) + (func $dummy16148) + (func $dummy16149) + (func $dummy16150) + (func $dummy16151) + (func $dummy16152) + (func $dummy16153) + (func $dummy16154) + (func $dummy16155) + (func $dummy16156) + (func $dummy16157) + (func $dummy16158) + (func $dummy16159) + (func $dummy16160) + (func $dummy16161) + (func $dummy16162) + (func $dummy16163) + (func $dummy16164) + (func $dummy16165) + (func $dummy16166) + (func $dummy16167) + (func $dummy16168) + (func $dummy16169) + (func $dummy16170) + (func $dummy16171) + (func $dummy16172) + (func $dummy16173) + (func $dummy16174) + (func $dummy16175) + (func $dummy16176) + (func $dummy16177) + (func $dummy16178) + (func $dummy16179) + (func $dummy16180) + (func $dummy16181) + (func $dummy16182) + (func $dummy16183) + (func $dummy16184) + (func $dummy16185) + (func $dummy16186) + (func $dummy16187) + (func $dummy16188) + (func $dummy16189) + (func $dummy16190) + (func $dummy16191) + (func $dummy16192) + (func $dummy16193) + (func $dummy16194) + (func $dummy16195) + (func $dummy16196) + (func $dummy16197) + (func $dummy16198) + (func $dummy16199) + (func $dummy16200) + (func $dummy16201) + (func $dummy16202) + (func $dummy16203) + (func $dummy16204) + (func $dummy16205) + (func $dummy16206) + (func $dummy16207) + (func $dummy16208) + (func $dummy16209) + (func $dummy16210) + (func $dummy16211) + (func $dummy16212) + (func $dummy16213) + (func $dummy16214) + (func $dummy16215) + (func $dummy16216) + (func $dummy16217) + (func $dummy16218) + (func $dummy16219) + (func $dummy16220) + (func $dummy16221) + (func $dummy16222) + (func $dummy16223) + (func $dummy16224) + (func $dummy16225) + (func $dummy16226) + (func $dummy16227) + (func $dummy16228) + (func $dummy16229) + (func $dummy16230) + (func $dummy16231) + (func $dummy16232) + (func $dummy16233) + (func $dummy16234) + (func $dummy16235) + (func $dummy16236) + (func $dummy16237) + (func $dummy16238) + (func $dummy16239) + (func $dummy16240) + (func $dummy16241) + (func $dummy16242) + (func $dummy16243) + (func $dummy16244) + (func $dummy16245) + (func $dummy16246) + (func $dummy16247) + (func $dummy16248) + (func $dummy16249) + (func $dummy16250) + (func $dummy16251) + (func $dummy16252) + (func $dummy16253) + (func $dummy16254) + (func $dummy16255) + (func $dummy16256) + (func $dummy16257) + (func $dummy16258) + (func $dummy16259) + (func $dummy16260) + (func $dummy16261) + (func $dummy16262) + (func $dummy16263) + (func $dummy16264) + (func $dummy16265) + (func $dummy16266) + (func $dummy16267) + (func $dummy16268) + (func $dummy16269) + (func $dummy16270) + (func $dummy16271) + (func $dummy16272) + (func $dummy16273) + (func $dummy16274) + (func $dummy16275) + (func $dummy16276) + (func $dummy16277) + (func $dummy16278) + (func $dummy16279) + (func $dummy16280) + (func $dummy16281) + (func $dummy16282) + (func $dummy16283) + (func $dummy16284) + (func $dummy16285) + (func $dummy16286) + (func $dummy16287) + (func $dummy16288) + (func $dummy16289) + (func $dummy16290) + (func $dummy16291) + (func $dummy16292) + (func $dummy16293) + (func $dummy16294) + (func $dummy16295) + (func $dummy16296) + (func $dummy16297) + (func $dummy16298) + (func $dummy16299) + (func $dummy16300) + (func $dummy16301) + (func $dummy16302) + (func $dummy16303) + (func $dummy16304) + (func $dummy16305) + (func $dummy16306) + (func $dummy16307) + (func $dummy16308) + (func $dummy16309) + (func $dummy16310) + (func $dummy16311) + (func $dummy16312) + (func $dummy16313) + (func $dummy16314) + (func $dummy16315) + (func $dummy16316) + (func $dummy16317) + (func $dummy16318) + (func $dummy16319) + (func $dummy16320) + (func $dummy16321) + (func $dummy16322) + (func $dummy16323) + (func $dummy16324) + (func $dummy16325) + (func $dummy16326) + (func $dummy16327) + (func $dummy16328) + (func $dummy16329) + (func $dummy16330) + (func $dummy16331) + (func $dummy16332) + (func $dummy16333) + (func $dummy16334) + (func $dummy16335) + (func $dummy16336) + (func $dummy16337) + (func $dummy16338) + (func $dummy16339) + (func $dummy16340) + (func $dummy16341) + (func $dummy16342) + (func $dummy16343) + (func $dummy16344) + (func $dummy16345) + (func $dummy16346) + (func $dummy16347) + (func $dummy16348) + (func $dummy16349) + (func $dummy16350) + (func $dummy16351) + (func $dummy16352) + (func $dummy16353) + (func $dummy16354) + (func $dummy16355) + (func $dummy16356) + (func $dummy16357) + (func $dummy16358) + (func $dummy16359) + (func $dummy16360) + (func $dummy16361) + (func $dummy16362) + (func $dummy16363) + (func $dummy16364) + (func $dummy16365) + (func $dummy16366) + (func $dummy16367) + (func $dummy16368) + (func $dummy16369) + (func $dummy16370) + (func $dummy16371) + (func $dummy16372) + (func $dummy16373) + (func $dummy16374) + (func $dummy16375) + (func $dummy16376) + (func $dummy16377) + (func $dummy16378) + (func $dummy16379) + (func $dummy16380) + (func $dummy16381) + (func $dummy16382) + (func $dummy16383) + (func $f (export "fast:f") (param i32) (result i32) + local.get 0 i32.const 1 i32.add) + (func (export "main") (result i32) + i32.const 41 + call $f + i32.const 42 + i32.ne) +) diff --git a/test/fastcall/test51_mixed_calls_flat.wasm b/test/fastcall/test51_mixed_calls_flat.wasm new file mode 100644 index 0000000000000000000000000000000000000000..f7c70bfec934edf1c42132e77051cd7361670775 GIT binary patch literal 358 zcmYk0K~BRk5JmsY*h#=t$`NdpGq7OgS(OFi3N)exwM`Zv58ew@V8h)@#wOF aIm~3%Zz^auioH don't trap + if unreachable end + + ;; loop with alternating fast/slow calls and a conditional inside + i32.const 0 local.set $i + i32.const 0 local.set $acc + block $break loop $cont + local.get $i i32.const 8 i32.ge_s br_if $break + ;; fast call + local.get $acc local.get $i call $fast_add local.set $acc + ;; regular call + local.get $acc call $slow_double local.set $acc + ;; conditional: on even iterations subtract b, on odd add 1 + local.get $i i32.const 1 i32.and + if + local.get $acc call $fast_inc local.set $acc + else + local.get $acc local.get $b call $slow_sub local.set $acc + end + local.get $i i32.const 1 i32.add local.set $i + br $cont + end end + + ;; write acc to memory, read it back via fast call + i32.const 0 local.get $acc i32.store + local.get $acc local.get $b call $fast_mul local.set $c ;; c = acc*7 + + ;; update global, branch on it + local.get $c global.set $g + global.get $g + i32.const 0 i32.le_s + if + i32.const 0 local.set $c + end + + ;; another loop: fast_inc until we hit a threshold, with slow_add mixing in + block $break2 loop $cont2 + local.get $c i32.const 200 i32.ge_s br_if $break2 + local.get $c call $fast_inc local.set $c + local.get $c i32.const 5 call $slow_add local.set $c + br $cont2 + end end + + ;; fast_neg to flip, slow_sub to bring back, check zero + local.get $c call $fast_neg ;; -c + local.get $c call $slow_add ;; -c + c = 0 + i32.const 0 i32.ne) ;; expect 0 +) diff --git a/test/fastcall/test52_mixed_calls_nested.wasm b/test/fastcall/test52_mixed_calls_nested.wasm new file mode 100644 index 0000000000000000000000000000000000000000..03aec53a9c1799d2fcac985cc29b883108d46041 GIT binary patch literal 319 zcmYk1L23gr3`M_W%Pw^TK7vfU=m|>cYJ7oSp&2?95|V*1pNj8Ga(?UOW1J@7*3T2@#_#4&us@Ew z8R7nyVuV6zpH@9xwEp|UHUGZql75I{t5Q&1vFpX#6CT{4QssR^>J@p7!zB*Yt+9Qm zu!@F#rIR0&GZz+Ro2SA_L*=vb3&U3Q{+W@bSZ{OT0V%1klznl=T|c4z2`WaV(?=Mk F^apyiEK2|Y literal 0 HcmV?d00001 diff --git a/test/fastcall/test52_mixed_calls_nested.wasm.exit b/test/fastcall/test52_mixed_calls_nested.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test52_mixed_calls_nested.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test52_mixed_calls_nested.wasm.flags b/test/fastcall/test52_mixed_calls_nested.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test52_mixed_calls_nested.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test52_mixed_calls_nested.wat b/test/fastcall/test52_mixed_calls_nested.wat new file mode 100644 index 000000000..f8bb507f1 --- /dev/null +++ b/test/fastcall/test52_mixed_calls_nested.wat @@ -0,0 +1,74 @@ +;; Stress test: large main with fast/regular calls inside deeply nested control flow. +;; Multiple levels of block/loop nesting with fast and slow calls at each level, +;; maximally stressing r_stp across many sidetable entries at varying nesting depth. +(module + (memory 1) + (global $g (mut i32) (i32.const 0)) + + (func $fast_add (export "fast:fast_add") (param i32 i32) (result i32) local.get 0 local.get 1 i32.add) + (func $fast_and (export "fast:fast_and") (param i32 i32) (result i32) local.get 0 local.get 1 i32.and) + (func $fast_inc (export "fast:fast_inc") (param i32) (result i32) local.get 0 i32.const 1 i32.add) + + (func $slow_mul (param i32 i32) (result i32) local.get 0 local.get 1 i32.mul) + (func $slow_shr (param i32 i32) (result i32) local.get 0 local.get 1 i32.shr_u) + (func $slow_xor (param i32 i32) (result i32) local.get 0 local.get 1 i32.xor) + + (func (export "main") (result i32) + (local $a i32) (local $b i32) (local $c i32) (local $d i32) + (local $acc i32) (local $i i32) (local $j i32) + + i32.const 5 local.set $a + i32.const 3 local.set $b + i32.const 0 local.set $acc + + ;; outer loop: i from 0..4 + i32.const 0 local.set $i + block $outer_break loop $outer + local.get $i i32.const 5 i32.ge_s br_if $outer_break + + ;; fast call at outer level + local.get $acc local.get $a call $fast_add local.set $acc + + ;; inner loop: j from 0..2, with nested block + i32.const 0 local.set $j + block $inner_break loop $inner + local.get $j i32.const 3 i32.ge_s br_if $inner_break + + ;; slow call inside inner loop + local.get $acc local.get $b call $slow_mul local.set $c + + ;; nested if with fast call on each branch + local.get $i local.get $j i32.add i32.const 1 i32.and + if + local.get $c call $fast_inc local.set $c + else + local.get $c local.get $a call $fast_and local.set $c + end + + ;; store c to memory slot j, read back and xor into acc + local.get $j i32.const 2 i32.shl ;; j*4 + local.get $c i32.store + local.get $acc + local.get $j i32.const 2 i32.shl i32.load + call $slow_xor local.set $acc + + local.get $j call $fast_inc local.set $j + br $inner + end end + + ;; between inner and outer: slow_shr, then fast_add, then branch + local.get $acc i32.const 1 call $slow_shr local.set $d + local.get $acc local.get $d call $fast_add local.set $acc + + ;; update global at end of each outer iteration + local.get $acc global.set $g + + local.get $i call $fast_inc local.set $i + br $outer + end end + + ;; final: read global, fast_and with mask, check low bit is 0 + global.get $g + i32.const 1 + call $fast_and) ;; expect 0 (result is even after all the shifts/xors) +) From 73251ee56956d1ae61a6c6dab201a0c3f26fe426 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 21 Apr 2026 16:42:06 -0400 Subject: [PATCH 63/91] Always reconstruct frames across runtime calls in fast handler --- src/engine/compiler/SinglePassCompiler.v3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index ebf6b3cd3..af164f210 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -2050,7 +2050,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_call_runtime_op(op); }; // Reconstruct stack frames across runtime calls that might (Wasm-level) trap. - if (canTrap) withReconstructedInlinedFrames(emit); else emit(); + if (canTrap || fast) withReconstructedInlinedFrames(emit); else emit(); masm.emit_get_curstack(regs.scratch); masm.emit_pop_X86_64Stack_rsp_r_r(regs.scratch); dropN(args); @@ -2074,7 +2074,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_call_runtime_op(op); }; // Reconstruct stack frames across runtime calls that might (Wasm-level) trap. - if (canTrap) withReconstructedInlinedFrames(emit); else emit(); + if (canTrap || fast) withReconstructedInlinedFrames(emit); else emit(); masm.emit_get_curstack(regs.scratch); masm.emit_pop_X86_64Stack_rsp_r_r(regs.scratch); dropN(args); From eac78cecc8fb110df29e911c53af52fc151b6763 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 22 Apr 2026 01:23:45 -0400 Subject: [PATCH 64/91] Streamline SPC register saving (should just be sent to MacroAssembler though) --- src/engine/compiler/SinglePassCompiler.v3 | 14 +-- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 105 +++++------------- 2 files changed, 34 insertions(+), 85 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index af164f210..43735205e 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -399,8 +399,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Advance IP past the fast-call opcode and spill it def r_ip = X86_64MasmRegs.INT_EXEC_ENV.ip; masm.emit_addw_r_i(r_ip, fast_operand_size); // increment ip - computePc(-(fast_operand_size + 1)); // compute r_curpc - saveCallerIVars(); // save r_ip and r_curpc + computeIntPc(-(fast_operand_size + 1)); // compute r_curpc + saveFastIVars(); // save r_ip and r_curpc // Why do we have to compute and save? // 1. r_ip = rax (clobbered by HW `div`) |\ can validation catch this? // 2. m_curpc = HW trap reads this |/ or hidden by arbitrary outcalls? @@ -2207,10 +2207,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl return label; } def getSpcInlinedFrameIp() -> long; - def saveCallerIVars(); - def restoreDispatchTableReg(); - def restoreCallerIVars(); - def computePc(delta: int); + def saveFastIVars(); + def restoreFastIVars(); + def computeIntPc(delta: int); // Emit code to materialize stack frames for each inlined function. def emitReconstructStackFrames(frames: Array) -> int { Metrics.spc_static_reconst.val++; @@ -2338,8 +2337,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot.plus(space - frame.frameSize - 8)); masm.emit_addw_r_i(regs.sp, space); - restoreCallerIVars(); - restoreDispatchTableReg(); + restoreFastIVars(); } else { masm.emit_addw_r_i(regs.sp, space); masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 96f96b4ae..63df2d14c 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -23,54 +23,7 @@ def KIND_F64 = SpcConsts.KIND_F64; def KIND_V128 = SpcConsts.KIND_V128; def KIND_REF = SpcConsts.KIND_REF; -def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; - -def r_mem0_base = G(xenv.mem0_base); -def r_vfp = G(xenv.vfp); -def r_vsp = G(xenv.vsp); -def r_stp = G(xenv.stp); -def r_ip = G(xenv.ip); -def r_eip = G(xenv.eip); -def r_func_decl = G(xenv.func_decl); -def r_instance = G(xenv.instance); -def r_curpc = G(xenv.curpc); -def ip_ptr = r_ip.plus(0); -def r_dispatch = G(xenv.dispatch); -def r_tmp0 = G(xenv.tmp0); // RCX -def r_tmp1 = G(xenv.tmp1); // RDX - -def m_mem0_base = R.RSP.plus(X86_64InterpreterFrame.mem0_base.offset); -def m_vfp = R.RSP.plus(X86_64InterpreterFrame.vfp.offset); -def m_vsp = R.RSP.plus(X86_64InterpreterFrame.vsp.offset); -def m_stp = R.RSP.plus(X86_64InterpreterFrame.stp.offset); -def m_ip = R.RSP.plus(X86_64InterpreterFrame.ip.offset); -def m_eip = R.RSP.plus(X86_64InterpreterFrame.eip.offset); -def m_func_decl = R.RSP.plus(X86_64InterpreterFrame.func_decl.offset); -def m_instance = R.RSP.plus(X86_64InterpreterFrame.instance.offset); -def m_curpc = R.RSP.plus(X86_64InterpreterFrame.curpc.offset); -def m_code = R.RSP.plus(X86_64InterpreterFrame.code.offset); - -def ivar_MEM0_BASE = (r_mem0_base, m_mem0_base); -def ivar_VFP = (r_vfp, m_vfp); -def ivar_VSP = (r_vsp, m_vsp); -def ivar_STP = (r_stp, m_stp); -def ivar_IP = (r_ip, m_ip); -def ivar_EIP = (r_eip, m_eip); -def ivar_FUNC_DECL = (r_func_decl, m_func_decl); -def ivar_INSTANCE = (r_instance, m_instance); -def ivar_CURPC = (r_curpc, m_curpc); - -def all_ivars = [ - ivar_MEM0_BASE, - ivar_VFP, - ivar_VSP, - ivar_STP, - ivar_IP, - ivar_EIP, - ivar_FUNC_DECL, - ivar_INSTANCE, - ivar_CURPC -]; +def int_xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; // Implements the target-specific parts of the single-pass compiler for X86-64. class X86_64SinglePassCompiler extends SinglePassCompiler { @@ -86,42 +39,40 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.trap_stubs = TRAPS_STUB; } def emitFastDispatch() { + def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; + def r_ip = G(xenv.ip); + def ip_ptr = r_ip.plus(0); + def r_dispatch = G(xenv.dispatch); + def r_tmp0 = G(xenv.tmp0); // RCX + def r_tmp1 = G(xenv.tmp1); // RDX + + def m_ip = R.RSP.plus(X86_64InterpreterFrame.ip.offset); asm.movq_r_m(r_ip, m_ip); mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } - private def saveIVar(r: X86_64Gpr) { - for (t in all_ivars) { - if (t.0 == r) asm.movq_m_r(t.1, r); - } - } - def saveCallerIVars() { - saveIVar(r_ip); - if (!FeatureDisable.stacktraces) saveIVar(r_curpc); - } - def restoreDispatchTableReg() { - if (!FeatureDisable.globalProbes) { - // restore dispatch table from Interpreter.dispatchTable - def offsets = masm.getOffsets(); - asm.movq_r_m(r_dispatch, mmasm.absPointer(offsets.Interpreter_dispatchTable)); - } - } - private def restoreReg(r: X86_64Gpr) { - for (t in all_ivars) { - if (t.0 == r) asm.movq_r_m(r, t.1); - } + def saveFastIVars() { + mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.ip_slot, int_xenv.ip); + mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.pc_slot, int_xenv.curpc); } def restoreCallerIVars() { - restoreReg(r_stp); - restoreReg(r_ip); - restoreReg(r_eip); - restoreReg(r_func_decl); - restoreReg(r_instance); - restoreReg(r_mem0_base); - restoreReg(r_curpc); - } - def computePc(delta: int) { + mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.stp_slot, int_xenv.stp); + mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.ip_slot, int_xenv.ip); + mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.eip_slot, int_xenv.eip); + mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.func_decl_slot, int_xenv.func_decl); + mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.instance_slot, int_xenv.instance); + mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.mem0_base_slot, int_xenv.mem0_base); + mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.curpc_slot, int_xenv.curpc); + // restore dispatch table from Interpreter.dispatchTable + def offsets = masm.getOffsets(); + def r_dispatch = G(int_xenv.dispatch); + asm.movq_r_m(r_dispatch, mmasm.absPointer(offsets.Interpreter_dispatchTable)); + } + def computeIntPc(delta: int) { def offsets = masm.getOffsets(); + def r_curpc = G(int_xenv.curpc); + def r_ip = G(int_xenv.ip); + def m_code = R.RSP.plus(X86_64InterpreterFrame.code.offset); asm.q.lea(r_curpc, X86_64Addr.new(r_ip, null, 1, delta - offsets.Array_contents)); asm.q.sub_r_m(r_curpc, m_code); } From 004c04e13e240c61bc45cdbaf56ada8c86907328 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 22 Apr 2026 11:05:07 -0400 Subject: [PATCH 65/91] Revert "Streamline SPC register saving (should just be sent to MacroAssembler though)" This reverts commit 7d3da8be7016fb0c90f607b1d8105cd37d725e76. --- src/engine/compiler/SinglePassCompiler.v3 | 14 ++- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 105 +++++++++++++----- 2 files changed, 85 insertions(+), 34 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 43735205e..af164f210 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -399,8 +399,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Advance IP past the fast-call opcode and spill it def r_ip = X86_64MasmRegs.INT_EXEC_ENV.ip; masm.emit_addw_r_i(r_ip, fast_operand_size); // increment ip - computeIntPc(-(fast_operand_size + 1)); // compute r_curpc - saveFastIVars(); // save r_ip and r_curpc + computePc(-(fast_operand_size + 1)); // compute r_curpc + saveCallerIVars(); // save r_ip and r_curpc // Why do we have to compute and save? // 1. r_ip = rax (clobbered by HW `div`) |\ can validation catch this? // 2. m_curpc = HW trap reads this |/ or hidden by arbitrary outcalls? @@ -2207,9 +2207,10 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl return label; } def getSpcInlinedFrameIp() -> long; - def saveFastIVars(); - def restoreFastIVars(); - def computeIntPc(delta: int); + def saveCallerIVars(); + def restoreDispatchTableReg(); + def restoreCallerIVars(); + def computePc(delta: int); // Emit code to materialize stack frames for each inlined function. def emitReconstructStackFrames(frames: Array) -> int { Metrics.spc_static_reconst.val++; @@ -2337,7 +2338,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot.plus(space - frame.frameSize - 8)); masm.emit_addw_r_i(regs.sp, space); - restoreFastIVars(); + restoreCallerIVars(); + restoreDispatchTableReg(); } else { masm.emit_addw_r_i(regs.sp, space); masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 63df2d14c..96f96b4ae 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -23,7 +23,54 @@ def KIND_F64 = SpcConsts.KIND_F64; def KIND_V128 = SpcConsts.KIND_V128; def KIND_REF = SpcConsts.KIND_REF; -def int_xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; +def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; + +def r_mem0_base = G(xenv.mem0_base); +def r_vfp = G(xenv.vfp); +def r_vsp = G(xenv.vsp); +def r_stp = G(xenv.stp); +def r_ip = G(xenv.ip); +def r_eip = G(xenv.eip); +def r_func_decl = G(xenv.func_decl); +def r_instance = G(xenv.instance); +def r_curpc = G(xenv.curpc); +def ip_ptr = r_ip.plus(0); +def r_dispatch = G(xenv.dispatch); +def r_tmp0 = G(xenv.tmp0); // RCX +def r_tmp1 = G(xenv.tmp1); // RDX + +def m_mem0_base = R.RSP.plus(X86_64InterpreterFrame.mem0_base.offset); +def m_vfp = R.RSP.plus(X86_64InterpreterFrame.vfp.offset); +def m_vsp = R.RSP.plus(X86_64InterpreterFrame.vsp.offset); +def m_stp = R.RSP.plus(X86_64InterpreterFrame.stp.offset); +def m_ip = R.RSP.plus(X86_64InterpreterFrame.ip.offset); +def m_eip = R.RSP.plus(X86_64InterpreterFrame.eip.offset); +def m_func_decl = R.RSP.plus(X86_64InterpreterFrame.func_decl.offset); +def m_instance = R.RSP.plus(X86_64InterpreterFrame.instance.offset); +def m_curpc = R.RSP.plus(X86_64InterpreterFrame.curpc.offset); +def m_code = R.RSP.plus(X86_64InterpreterFrame.code.offset); + +def ivar_MEM0_BASE = (r_mem0_base, m_mem0_base); +def ivar_VFP = (r_vfp, m_vfp); +def ivar_VSP = (r_vsp, m_vsp); +def ivar_STP = (r_stp, m_stp); +def ivar_IP = (r_ip, m_ip); +def ivar_EIP = (r_eip, m_eip); +def ivar_FUNC_DECL = (r_func_decl, m_func_decl); +def ivar_INSTANCE = (r_instance, m_instance); +def ivar_CURPC = (r_curpc, m_curpc); + +def all_ivars = [ + ivar_MEM0_BASE, + ivar_VFP, + ivar_VSP, + ivar_STP, + ivar_IP, + ivar_EIP, + ivar_FUNC_DECL, + ivar_INSTANCE, + ivar_CURPC +]; // Implements the target-specific parts of the single-pass compiler for X86-64. class X86_64SinglePassCompiler extends SinglePassCompiler { @@ -39,40 +86,42 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.trap_stubs = TRAPS_STUB; } def emitFastDispatch() { - def xenv: IntExecEnv = X86_64MasmRegs.INT_EXEC_ENV; - def r_ip = G(xenv.ip); - def ip_ptr = r_ip.plus(0); - def r_dispatch = G(xenv.dispatch); - def r_tmp0 = G(xenv.tmp0); // RCX - def r_tmp1 = G(xenv.tmp1); // RDX - - def m_ip = R.RSP.plus(X86_64InterpreterFrame.ip.offset); asm.movq_r_m(r_ip, m_ip); mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } - def saveFastIVars() { - mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.ip_slot, int_xenv.ip); - mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.pc_slot, int_xenv.curpc); + private def saveIVar(r: X86_64Gpr) { + for (t in all_ivars) { + if (t.0 == r) asm.movq_m_r(t.1, r); + } } - def restoreCallerIVars() { - mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.stp_slot, int_xenv.stp); - mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.ip_slot, int_xenv.ip); - mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.eip_slot, int_xenv.eip); - mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.func_decl_slot, int_xenv.func_decl); - mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.instance_slot, int_xenv.instance); - mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.mem0_base_slot, int_xenv.mem0_base); - mmasm.emit_mov_m_r(ValueKind.REF, int_xenv.curpc_slot, int_xenv.curpc); - // restore dispatch table from Interpreter.dispatchTable - def offsets = masm.getOffsets(); - def r_dispatch = G(int_xenv.dispatch); - asm.movq_r_m(r_dispatch, mmasm.absPointer(offsets.Interpreter_dispatchTable)); + def saveCallerIVars() { + saveIVar(r_ip); + if (!FeatureDisable.stacktraces) saveIVar(r_curpc); + } + def restoreDispatchTableReg() { + if (!FeatureDisable.globalProbes) { + // restore dispatch table from Interpreter.dispatchTable + def offsets = masm.getOffsets(); + asm.movq_r_m(r_dispatch, mmasm.absPointer(offsets.Interpreter_dispatchTable)); + } + } + private def restoreReg(r: X86_64Gpr) { + for (t in all_ivars) { + if (t.0 == r) asm.movq_r_m(r, t.1); + } } - def computeIntPc(delta: int) { + def restoreCallerIVars() { + restoreReg(r_stp); + restoreReg(r_ip); + restoreReg(r_eip); + restoreReg(r_func_decl); + restoreReg(r_instance); + restoreReg(r_mem0_base); + restoreReg(r_curpc); + } + def computePc(delta: int) { def offsets = masm.getOffsets(); - def r_curpc = G(int_xenv.curpc); - def r_ip = G(int_xenv.ip); - def m_code = R.RSP.plus(X86_64InterpreterFrame.code.offset); asm.q.lea(r_curpc, X86_64Addr.new(r_ip, null, 1, delta - offsets.Array_contents)); asm.q.sub_r_m(r_curpc, m_code); } From 9fa678158c2abf3e8d666fdc39df30e14bacc09b Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 22 Apr 2026 12:54:44 -0400 Subject: [PATCH 66/91] Add wave.new_func tests to fastcall --- test/fastcall/test53_dynamic_calls_fast.wasm | Bin 0 -> 147 bytes .../test53_dynamic_calls_fast.wasm.exit | 1 + .../test53_dynamic_calls_fast.wasm.flags | 1 + test/fastcall/test53_dynamic_calls_fast.wat | 33 ++++++++++ test/fastcall/test54_dynamic_chains_fast.wasm | Bin 0 -> 177 bytes .../test54_dynamic_chains_fast.wasm.exit | 1 + .../test54_dynamic_chains_fast.wasm.flags | 1 + test/fastcall/test54_dynamic_chains_fast.wat | 37 ++++++++++++ test/fastcall/test55_two_dynamic_funcs.wasm | Bin 0 -> 211 bytes .../test55_two_dynamic_funcs.wasm.exit | 1 + .../test55_two_dynamic_funcs.wasm.flags | 1 + test/fastcall/test55_two_dynamic_funcs.wat | 57 ++++++++++++++++++ 12 files changed, 133 insertions(+) create mode 100644 test/fastcall/test53_dynamic_calls_fast.wasm create mode 100644 test/fastcall/test53_dynamic_calls_fast.wasm.exit create mode 100644 test/fastcall/test53_dynamic_calls_fast.wasm.flags create mode 100644 test/fastcall/test53_dynamic_calls_fast.wat create mode 100644 test/fastcall/test54_dynamic_chains_fast.wasm create mode 100644 test/fastcall/test54_dynamic_chains_fast.wasm.exit create mode 100644 test/fastcall/test54_dynamic_chains_fast.wasm.flags create mode 100644 test/fastcall/test54_dynamic_chains_fast.wat create mode 100644 test/fastcall/test55_two_dynamic_funcs.wasm create mode 100644 test/fastcall/test55_two_dynamic_funcs.wasm.exit create mode 100644 test/fastcall/test55_two_dynamic_funcs.wasm.flags create mode 100644 test/fastcall/test55_two_dynamic_funcs.wat diff --git a/test/fastcall/test53_dynamic_calls_fast.wasm b/test/fastcall/test53_dynamic_calls_fast.wasm new file mode 100644 index 0000000000000000000000000000000000000000..bbc8a594fb09380cad36c45bb0537d2c63d405e8 GIT binary patch literal 147 zcmWlOu@1r@00rLz3Py}+ogLi#2R9}^!=lo}MyRo^jT65v=7vk|;KxV+Y-G#K+{&E) z0<&nS7XJyW6qZXjryD4xfKZArpppd5QQ6Lq)9F6U*Jl8A3~_jW1**xHK&a>+31Yn$ a28Tj#cW}m`pldXM+n%l6umr2iuW5gyq8bDw;MZ%r40i~rBq){Q3(%5acG9MG(|m5m<@WSoo|0=Ch)wVN@% fast:double(result) +;; Bytecode (func index layout: 0=new_func, 1=fast:double, 2=fast:add, 3=main): +;; \00 = 0 locals +;; \20\00 = local.get 0 +;; \20\00 = local.get 0 +;; \10\02 = call 2 (fast:add) +;; \10\01 = call 1 (fast:double) +;; \0B = end +;; For x=5: add(5,5)=10, double(10)=20. +(module + (type $t_i_i (func (param i32) (result i32))) + (type $t_ii_i (func (param i32 i32) (result i32))) + + (import "wave" "new_func" (func $new_func (param i32 i32 i32) (result i32))) + + (func $double (export "fast:double") (param i32) (result i32) + local.get 0 + local.get 0 + i32.add) + (func $add (export "fast:add") (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.add) + + (memory (export "memory") 1) + (data (i32.const 0) "\00\20\00\20\00\10\02\10\01\0B") + + (table (export "table") 0 funcref) + + (func (export "main") (result i32) + i32.const 5 + (call $new_func (i32.const 0) (i32.const 0) (i32.const 10)) + (call_indirect (type $t_i_i)) + i32.const 20 + i32.ne) +) diff --git a/test/fastcall/test55_two_dynamic_funcs.wasm b/test/fastcall/test55_two_dynamic_funcs.wasm new file mode 100644 index 0000000000000000000000000000000000000000..5d3b8f4fef0a23fb1b5840c54b9f7d904141f979 GIT binary patch literal 211 zcmW-Z%?iRW5QJy4=??~^MZs(P2IA3My!aRzZ3`CLidu`Oyt=Ur%s0a>1NZ6(fE#_L zr#~zIckweouX5_ied@HYr&BZbS18c}iq?Dpkq}IFk!jrPy|0Gxa<9R3Zmz1J;;!z7 z=T{+myKp0P=Wab@agYQ>P-|wgHCu|e2#Pb5u(YvFLkcXA16Hgqm=kTO3T0PEW7Z7s NW*Js8n*SOzWq!9fBhvr? literal 0 HcmV?d00001 diff --git a/test/fastcall/test55_two_dynamic_funcs.wasm.exit b/test/fastcall/test55_two_dynamic_funcs.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test55_two_dynamic_funcs.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test55_two_dynamic_funcs.wasm.flags b/test/fastcall/test55_two_dynamic_funcs.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test55_two_dynamic_funcs.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test55_two_dynamic_funcs.wat b/test/fastcall/test55_two_dynamic_funcs.wat new file mode 100644 index 000000000..65efb85e6 --- /dev/null +++ b/test/fastcall/test55_two_dynamic_funcs.wat @@ -0,0 +1,57 @@ +;; Two functions created via wave.new_func, each wrapping a different fast handler. +;; Dynamic func A (type 0, i32->i32): wraps fast:double. +;; \00 \20\00 \10\01 \0B +;; Dynamic func B (type 1, i32 i32->i32): wraps fast:add. +;; \00 \20\00 \20\01 \10\02 \0B +;; Func index layout: 0=new_func, 1=fast:double, 2=fast:add, 3=main. +;; main creates both, then calls A(6)=12 and B(3,4)=7, checks sum=19. +(module + (type $t_i_i (func (param i32) (result i32))) + (type $t_ii_i (func (param i32 i32) (result i32))) + + (import "wave" "new_func" (func $new_func (param i32 i32 i32) (result i32))) + + (func $double (export "fast:double") (param i32) (result i32) + local.get 0 + local.get 0 + i32.add) + (func $add (export "fast:add") (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.add) + + ;; Body A at offset 0, len 6: \00 \20\00 \10\01 \0B + ;; Body B at offset 6, len 8: \00 \20\00 \20\01 \10\02 \0B + (memory (export "memory") 1) + (data (i32.const 0) "\00\20\00\10\01\0B\00\20\00\20\01\10\02\0B") + + (table (export "table") 0 funcref) + + (func (export "main") (result i32) + (local $slot_a i32) (local $slot_b i32) (local $sum i32) + + ;; create dynamic func A (type 0), store slot + (call $new_func (i32.const 0) (i32.const 0) (i32.const 6)) + local.set $slot_a + + ;; create dynamic func B (type 1), store slot + (call $new_func (i32.const 1) (i32.const 6) (i32.const 8)) + local.set $slot_b + + ;; call A(6) = double(6) = 12 + i32.const 6 + local.get $slot_a + (call_indirect (type $t_i_i)) + + ;; call B(3,4) = add(3,4) = 7 + i32.const 3 + i32.const 4 + local.get $slot_b + (call_indirect (type $t_ii_i)) + + i32.add ;; 12 + 7 = 19 + local.set $sum + local.get $sum + i32.const 19 + i32.ne) +) From 9e3df1def1090db73c97e5a3e254e2adefd47cb3 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 22 Apr 2026 15:03:31 -0400 Subject: [PATCH 67/91] Optimize replaceCall --- src/engine/Module.v3 | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/engine/Module.v3 b/src/engine/Module.v3 index 063aea151..8dd6436f7 100644 --- a/src/engine/Module.v3 +++ b/src/engine/Module.v3 @@ -173,14 +173,9 @@ class FuncDecl(sig_index: int) extends Decl { cur_bytecode[pc] = orig_bytecode[pc]; } def replaceCall(pc: int, idx: int) { - // "orig" will become a copy of the original code, to allow in-place modification of old code + // copy bytecode for modification if (cur_bytecode == orig_bytecode) orig_bytecode = Arrays.dup(orig_bytecode); - if (cur_bytecode[pc] != Opcode.CALL.code) { // sanity check - def realOp = Opcodes.find(0, cur_bytecode[pc]); - System.error("replace bytecode", Strings.format1("not replacing call (got %s)", realOp.mnemonic)); - } cur_bytecode[pc] = byte.!(Opcodes.indexToFastCall(idx).code); - // do not replace the operands, beeded for BytecodeIterator } def reset() -> this { if (cur_bytecode == orig_bytecode) return; From fb42f99daacbf48428e2143f1f7ea906fb609e7b Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 22 Apr 2026 15:04:04 -0400 Subject: [PATCH 68/91] Print out patches to dispatch table --- src/engine/x86-64/X86_64Target.v3 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 9a1396c4d..82cb4eaff 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -342,6 +342,24 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { RiRuntime.registerUserCode(code); module.target_module.spc_code.keepAlive(); Debug.afterCompileModule(module); + // print out patched dispatch table + if (Trace.compiler) { + Trace.OUT.puts("Patched fast handlers:\n"); + for (i < module.fast_funcs.length) { + def func: FuncDecl = module.fast_funcs[i]; + var name: string; + for (j < module.exports.length) { + def exp = module.exports[j]; + if (exp.1 == func) { + name = exp.0; + break; + } + } + Trace.OUT.put2(" FAST_CALL%d: %s (", i, name); + func.render(module.names, Trace.OUT); + Trace.OUT.puts(")\n"); + } + } } } From bf07a5df43987218ee0456d6451b80fd8892965c Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 22 Apr 2026 15:25:29 -0400 Subject: [PATCH 69/91] Eagely allocate fast handler slots --- src/engine/CodeValidator.v3 | 39 +++---------------------------- src/engine/x86-64/X86_64Target.v3 | 19 +++++++++++---- 2 files changed, 17 insertions(+), 41 deletions(-) diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index e7b0a4933..44468bc09 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -422,42 +422,9 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e checkSignature(func.sig); // fast call: if function is exported with fast name, replace the bytecode with FAST_CALL - if (FastIntTuning.useFastFunctions) { - for (i < module.exports.length) { - def ex = module.exports[i]; - if (ex.1 == func && Strings.startsWith(ex.0, "fast:")) { - if (Trace.validation) Trace.OUT.puts(" function declared as fast: "); - - var fast_idx = -1; - def fast_funcs = module.fast_funcs; - // look for existing FAST_CALL instruction allocated for this function - for (i < fast_funcs.length) { - if (func == fast_funcs[i]) { - fast_idx = i; - if (Trace.validation) Trace.OUT.put1("allocated as FAST_CALL%d, ", fast_idx); - break; - } - } - // not found? allocate FAST_CALL instruction, if there's space - if (fast_idx < 0) { - if (fast_funcs.length < Opcodes.FAST_CALL_OPCODES) { - fast_idx = fast_funcs.length; - func.fast_call_idx = fast_idx; - if (Trace.validation) Trace.OUT.put1("not found, allocating FAST_CALL%d, ", fast_idx); - fast_funcs.put(func); - } else { - if (Trace.validation) Trace.OUT.puts("not found, FAST_CALL table is full, "); - } - } - // replace the bytecode, if it's found or allocated - if (fast_idx >= 0) { - if (Trace.validation) Trace.OUT.puts("replacing call\n"); - this.func.replaceCall(opcode_pos, fast_idx); - } else { - if (Trace.validation) Trace.OUT.puts("not replacing\n"); - } - } - } + if (FastIntTuning.useFastFunctions && func.fast_call_idx >= 0) { + if (Trace.validation) Trace.OUT.put1(" replacing with FAST_CALL%d\n", func.fast_call_idx); + this.func.replaceCall(opcode_pos, func.fast_call_idx); } } FAST_CALL0 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 82cb4eaff..95e11729d 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -299,10 +299,18 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { for (j < module.exports.length) { def ex = module.exports[j]; if (ex.1 == f && Strings.startsWith(ex.0, "fast:")) { - var start = w.atEnd().pos; - var compiled = compiler.gen(module, f, suberr); - if (compiled) bounds[i] = (start, w.end()); - else bounds[i] = (-1, -1); + def fast_funcs = module.fast_funcs; + if (fast_funcs.length < Opcodes.FAST_CALL_OPCODES) { + // allocate FAST_CALL opcode + def idx = fast_funcs.length; + f.fast_call_idx = idx; + fast_funcs.put(f); + + var start = w.atEnd().pos; + var compiled = compiler.gen(module, f, suberr); + if (compiled) bounds[i] = (start, w.end()); + else bounds[i] = (-1, -1); + } } } } @@ -357,7 +365,8 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { } Trace.OUT.put2(" FAST_CALL%d: %s (", i, name); func.render(module.names, Trace.OUT); - Trace.OUT.puts(")\n"); + Trace.OUT.puts(")"); + Trace.OUT.ln(); } } } From 09021c6cce4ff6ef84d2c652c423eb6305b17afc Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 23 Apr 2026 13:01:36 -0400 Subject: [PATCH 70/91] Save r_stp during reconstruction --- src/engine/compiler/SinglePassCompiler.v3 | 5 ++++- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index af164f210..098738849 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -408,7 +408,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Compute VFP = VSP - sig.params.length * SLOT_SIZE masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); // XXX: use 3-addr adjustment of VFP masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); - } def visitLocalDecl(count: u32, vtc: ValueTypeCode) { var vt = vtc.toAbstractValueType(module); @@ -2208,6 +2207,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } def getSpcInlinedFrameIp() -> long; def saveCallerIVars(); + def saveReconstructCallerIVars(); def restoreDispatchTableReg(); def restoreCallerIVars(); def computePc(delta: int); @@ -2327,6 +2327,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl emit(); return; } + if (fast) { + saveReconstructCallerIVars(); + } unrefRegs(); frames_reconstructed = true; def space = emitReconstructStackFrames(snapshotFrames()); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 96f96b4ae..bc27eedc9 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -99,6 +99,9 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { saveIVar(r_ip); if (!FeatureDisable.stacktraces) saveIVar(r_curpc); } + def saveReconstructCallerIVars() { + saveIVar(r_stp); + } def restoreDispatchTableReg() { if (!FeatureDisable.globalProbes) { // restore dispatch table from Interpreter.dispatchTable From 33b9ebc1f7114e9b0e454a6d572051b8f67a70b0 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 27 Apr 2026 23:25:20 -0400 Subject: [PATCH 71/91] Add even more tests --- test/fastcall/test56_caller_if_else_stp.wasm | Bin 0 -> 117 bytes .../test56_caller_if_else_stp.wasm.exit | 1 + .../test56_caller_if_else_stp.wasm.flags | 1 + test/fastcall/test56_caller_if_else_stp.wat | 46 ++++++ test/fastcall/test57_caller_br_table_stp.wasm | Bin 0 -> 135 bytes .../test57_caller_br_table_stp.wasm.exit | 1 + .../test57_caller_br_table_stp.wasm.flags | 1 + test/fastcall/test57_caller_br_table_stp.wat | 42 ++++++ test/fastcall/test58_deep_block_stp.wasm | Bin 0 -> 156 bytes test/fastcall/test58_deep_block_stp.wasm.exit | 1 + .../fastcall/test58_deep_block_stp.wasm.flags | 1 + test/fastcall/test58_deep_block_stp.wat | 47 ++++++ test/fastcall/test59_dynfunc_br_if_fast.wasm | Bin 0 -> 183 bytes .../test59_dynfunc_br_if_fast.wasm.exit | 1 + .../test59_dynfunc_br_if_fast.wasm.flags | 1 + test/fastcall/test59_dynfunc_br_if_fast.wat | 63 ++++++++ test/fastcall/test60_dynfunc_loop_fast.wasm | Bin 0 -> 175 bytes .../test60_dynfunc_loop_fast.wasm.exit | 1 + .../test60_dynfunc_loop_fast.wasm.flags | 1 + test/fastcall/test60_dynfunc_loop_fast.wat | 56 +++++++ .../fastcall/test61_dynfunc_if_else_fast.wasm | Bin 0 -> 208 bytes .../test61_dynfunc_if_else_fast.wasm.exit | 1 + .../test61_dynfunc_if_else_fast.wasm.flags | 1 + test/fastcall/test61_dynfunc_if_else_fast.wat | 69 +++++++++ .../test62_dynfunc_fast_outcall_if.wasm | Bin 0 -> 200 bytes .../test62_dynfunc_fast_outcall_if.wat | 61 ++++++++ .../test63_dynfunc_fast_outcall_loop.wasm | Bin 0 -> 192 bytes .../test63_dynfunc_fast_outcall_loop.wat | 50 +++++++ .../test64_dynfunc_fast_outcall_complex.wasm | Bin 0 -> 220 bytes .../test64_dynfunc_fast_outcall_complex.wat | 65 ++++++++ .../test65_dynfunc_fast_deep_outcall.wasm | Bin 0 -> 249 bytes .../test65_dynfunc_fast_deep_outcall.wat | 73 +++++++++ .../test66_fast_handler_indirect_call.wasm | Bin 0 -> 102 bytes ...est66_fast_handler_indirect_call.wasm.exit | 1 + ...st66_fast_handler_indirect_call.wasm.flags | 1 + .../test66_fast_handler_indirect_call.wat | 33 +++++ .../test67_fast_handler_indirect_if_else.wasm | Bin 0 -> 138 bytes ...67_fast_handler_indirect_if_else.wasm.exit | 1 + ...7_fast_handler_indirect_if_else.wasm.flags | 1 + .../test67_fast_handler_indirect_if_else.wat | 54 +++++++ .../test68_fast_handler_indirect_loop.wasm | Bin 0 -> 132 bytes ...est68_fast_handler_indirect_loop.wasm.exit | 1 + ...st68_fast_handler_indirect_loop.wasm.flags | 1 + .../test68_fast_handler_indirect_loop.wat | 45 ++++++ ...est69_fast_handler_two_indirect_calls.wasm | Bin 0 -> 128 bytes ..._fast_handler_two_indirect_calls.wasm.exit | 1 + ...fast_handler_two_indirect_calls.wasm.flags | 1 + ...test69_fast_handler_two_indirect_calls.wat | 47 ++++++ .../test70_fast_handler_dynamic_dispatch.wasm | Bin 0 -> 158 bytes ...70_fast_handler_dynamic_dispatch.wasm.exit | 1 + ...0_fast_handler_dynamic_dispatch.wasm.flags | 1 + .../test70_fast_handler_dynamic_dispatch.wat | 70 +++++++++ .../test71_fast_handler_indirect_heavy.wasm | Bin 0 -> 248 bytes ...st71_fast_handler_indirect_heavy.wasm.exit | 1 + ...t71_fast_handler_indirect_heavy.wasm.flags | 1 + .../test71_fast_handler_indirect_heavy.wat | 139 ++++++++++++++++++ 56 files changed, 984 insertions(+) create mode 100644 test/fastcall/test56_caller_if_else_stp.wasm create mode 100644 test/fastcall/test56_caller_if_else_stp.wasm.exit create mode 100644 test/fastcall/test56_caller_if_else_stp.wasm.flags create mode 100644 test/fastcall/test56_caller_if_else_stp.wat create mode 100644 test/fastcall/test57_caller_br_table_stp.wasm create mode 100644 test/fastcall/test57_caller_br_table_stp.wasm.exit create mode 100644 test/fastcall/test57_caller_br_table_stp.wasm.flags create mode 100644 test/fastcall/test57_caller_br_table_stp.wat create mode 100644 test/fastcall/test58_deep_block_stp.wasm create mode 100644 test/fastcall/test58_deep_block_stp.wasm.exit create mode 100644 test/fastcall/test58_deep_block_stp.wasm.flags create mode 100644 test/fastcall/test58_deep_block_stp.wat create mode 100644 test/fastcall/test59_dynfunc_br_if_fast.wasm create mode 100644 test/fastcall/test59_dynfunc_br_if_fast.wasm.exit create mode 100644 test/fastcall/test59_dynfunc_br_if_fast.wasm.flags create mode 100644 test/fastcall/test59_dynfunc_br_if_fast.wat create mode 100644 test/fastcall/test60_dynfunc_loop_fast.wasm create mode 100644 test/fastcall/test60_dynfunc_loop_fast.wasm.exit create mode 100644 test/fastcall/test60_dynfunc_loop_fast.wasm.flags create mode 100644 test/fastcall/test60_dynfunc_loop_fast.wat create mode 100644 test/fastcall/test61_dynfunc_if_else_fast.wasm create mode 100644 test/fastcall/test61_dynfunc_if_else_fast.wasm.exit create mode 100644 test/fastcall/test61_dynfunc_if_else_fast.wasm.flags create mode 100644 test/fastcall/test61_dynfunc_if_else_fast.wat create mode 100644 test/fastcall/test62_dynfunc_fast_outcall_if.wasm create mode 100644 test/fastcall/test62_dynfunc_fast_outcall_if.wat create mode 100644 test/fastcall/test63_dynfunc_fast_outcall_loop.wasm create mode 100644 test/fastcall/test63_dynfunc_fast_outcall_loop.wat create mode 100644 test/fastcall/test64_dynfunc_fast_outcall_complex.wasm create mode 100644 test/fastcall/test64_dynfunc_fast_outcall_complex.wat create mode 100644 test/fastcall/test65_dynfunc_fast_deep_outcall.wasm create mode 100644 test/fastcall/test65_dynfunc_fast_deep_outcall.wat create mode 100644 test/fastcall/test66_fast_handler_indirect_call.wasm create mode 100644 test/fastcall/test66_fast_handler_indirect_call.wasm.exit create mode 100644 test/fastcall/test66_fast_handler_indirect_call.wasm.flags create mode 100644 test/fastcall/test66_fast_handler_indirect_call.wat create mode 100644 test/fastcall/test67_fast_handler_indirect_if_else.wasm create mode 100644 test/fastcall/test67_fast_handler_indirect_if_else.wasm.exit create mode 100644 test/fastcall/test67_fast_handler_indirect_if_else.wasm.flags create mode 100644 test/fastcall/test67_fast_handler_indirect_if_else.wat create mode 100644 test/fastcall/test68_fast_handler_indirect_loop.wasm create mode 100644 test/fastcall/test68_fast_handler_indirect_loop.wasm.exit create mode 100644 test/fastcall/test68_fast_handler_indirect_loop.wasm.flags create mode 100644 test/fastcall/test68_fast_handler_indirect_loop.wat create mode 100644 test/fastcall/test69_fast_handler_two_indirect_calls.wasm create mode 100644 test/fastcall/test69_fast_handler_two_indirect_calls.wasm.exit create mode 100644 test/fastcall/test69_fast_handler_two_indirect_calls.wasm.flags create mode 100644 test/fastcall/test69_fast_handler_two_indirect_calls.wat create mode 100644 test/fastcall/test70_fast_handler_dynamic_dispatch.wasm create mode 100644 test/fastcall/test70_fast_handler_dynamic_dispatch.wasm.exit create mode 100644 test/fastcall/test70_fast_handler_dynamic_dispatch.wasm.flags create mode 100644 test/fastcall/test70_fast_handler_dynamic_dispatch.wat create mode 100644 test/fastcall/test71_fast_handler_indirect_heavy.wasm create mode 100644 test/fastcall/test71_fast_handler_indirect_heavy.wasm.exit create mode 100644 test/fastcall/test71_fast_handler_indirect_heavy.wasm.flags create mode 100644 test/fastcall/test71_fast_handler_indirect_heavy.wat diff --git a/test/fastcall/test56_caller_if_else_stp.wasm b/test/fastcall/test56_caller_if_else_stp.wasm new file mode 100644 index 0000000000000000000000000000000000000000..8a5e8a08d11cf0f3d3dd175b2050a294d98e92d5 GIT binary patch literal 117 zcmWN{I|>3p5QO2Xp7nvFAbNow@Bqd}+kq&aV#h#OWlhFxgTA^Q)lc!Ewuu0^k%3Mh zKu<}))lt^3+J2Y%Y(O{F@f+wW2Ph2p&Mo4zP~?23xXmT*Lg`bl*hBd)3>g#7mX95` JL6vs8 2 sidetable entries (IF entry + ELSE entry). +;; After abs returns via emitFastDispatch, r_stp has been advanced past those entries. +;; The caller then has its own br_if; if stp is stale the branch goes to the wrong place. +(module + ;; fast handler WITH its own if/else -- advances stp internally + (func $abs (export "fast:abs") (param i32) (result i32) + local.get 0 + i32.const 0 + i32.lt_s + if (result i32) + i32.const 0 + local.get 0 + i32.sub + else + local.get 0 + end) + + ;; caller: loop that calls abs, then br_if to exit based on accumulator. + ;; The br_if's sidetable entry must be read correctly every iteration. + ;; If stp drifts by 2 entries (one IF + one ELSE entry from abs) per iteration, + ;; it will read garbage after the first iteration. + (func (export "main") (result i32) + (local $i i32) + (local $acc i32) + i32.const -5 local.set $i + i32.const 0 local.set $acc + + block $exit loop $top + ;; call fast:abs -- handler has if/else, so stp moves during the call + local.get $i call $abs + local.get $acc i32.add local.set $acc + + local.get $i i32.const 1 i32.add local.set $i + + ;; this br_if reads from caller's sidetable -- if stp is wrong, wrong exit + local.get $i i32.const 6 i32.gt_s br_if $exit + br $top + end end + + ;; abs(-5)+abs(-4)+...+abs(6) = 5+4+3+2+1+0+1+2+3+4+5+6 = 36 + local.get $acc i32.const 36 i32.ne) +) diff --git a/test/fastcall/test57_caller_br_table_stp.wasm b/test/fastcall/test57_caller_br_table_stp.wasm new file mode 100644 index 0000000000000000000000000000000000000000..0a05a79cda1655dc577c8b154fd4ede6e43b70b0 GIT binary patch literal 135 zcmWlPu?oUK5JYG8L?LU`!a@+_@()&4*~-qsFUX+;BSZq1{(jrimErNGcu09909Mkm zuykMvLBQ2P>OST9@*MJ%=En10, 1->20, 2->30, else->0 + ;; br_table produces N+1 sidetable entries (one per arm + default) + (func $dispatch (export "fast:dispatch") (param $n i32) (result i32) + (block $b2 + (block $b1 + (block $b0 + local.get $n + br_table $b0 $b1 $b2 $b2) + i32.const 10 return) + i32.const 20 return) + i32.const 30) + + ;; caller: call dispatch repeatedly; after each call use br_if. + ;; The br_if's stp must survive the br_table inside dispatch intact. + (func (export "main") (result i32) + (local $i i32) + (local $acc i32) + i32.const 0 local.set $i + i32.const 0 local.set $acc + + block $exit loop $top + local.get $i i32.const 3 i32.rem_u ;; cycle: 0,1,2,0,1,2,... + call $dispatch + local.get $acc i32.add local.set $acc + + local.get $i i32.const 1 i32.add local.set $i + + ;; caller br_if: stp must point at THIS entry, not inside dispatch's br_table + local.get $i i32.const 6 i32.ge_s br_if $exit + br $top + end end + + ;; 6 iterations: dispatch(0)=10, dispatch(1)=20, dispatch(2)=30, + ;; dispatch(0)=10, dispatch(1)=20, dispatch(2)=30 + ;; sum = 10+20+30+10+20+30 = 120 + local.get $acc i32.const 120 i32.ne) +) diff --git a/test/fastcall/test58_deep_block_stp.wasm b/test/fastcall/test58_deep_block_stp.wasm new file mode 100644 index 0000000000000000000000000000000000000000..0da6cdbbf47c51de9c9a73da904a792a3bc2d305 GIT binary patch literal 156 zcmXAg!3x4K5JYD-MZsA0>TUA}f;UgeN$9~}ut6v&v=vg%`E?UL48!cchnPkJ;6{38 z<{r$(2)I7VZis2QJm$}|+~0EonlV17f(~+~pp+oh44i3=zS5yq8R$cq28TMEE1qn44+5i9m literal 0 HcmV?d00001 diff --git a/test/fastcall/test58_deep_block_stp.wasm.exit b/test/fastcall/test58_deep_block_stp.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test58_deep_block_stp.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test58_deep_block_stp.wasm.flags b/test/fastcall/test58_deep_block_stp.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test58_deep_block_stp.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test58_deep_block_stp.wat b/test/fastcall/test58_deep_block_stp.wat new file mode 100644 index 000000000..c54045ce4 --- /dev/null +++ b/test/fastcall/test58_deep_block_stp.wat @@ -0,0 +1,47 @@ +;; Stress test: fast handler has nested if/else within a loop (many stp advances), +;; called from a caller that has its own loop with br_if. +;; The handler's internal control flow moves stp by multiple entries per call; +;; if not restored, the caller's br_if drifts further each iteration. +(module + ;; fast handler: loop + br_if + if/else -> multiple stp entries per call + (func $count_pos (export "fast:count_pos") (param $n i32) (result i32) + (local $i i32) + (local $c i32) + i32.const 0 local.set $i + i32.const 0 local.set $c + block $exit loop $top + local.get $i local.get $n i32.ge_s br_if $exit + local.get $i i32.const 0 i32.gt_s + if + local.get $c i32.const 1 i32.add local.set $c + end + local.get $i i32.const 1 i32.add local.set $i + br $top + end end + local.get $c) + + ;; caller: call count_pos in a loop, accumulate, exit via br_if. + ;; Each call to count_pos advances stp by many entries inside the handler. + ;; If stp is not restored, the caller's exit br_if reads a wrong sidetable entry. + (func (export "main") (result i32) + (local $n i32) + (local $acc i32) + i32.const 1 local.set $n + i32.const 0 local.set $acc + + block $exit loop $top + local.get $n call $count_pos ;; count_pos(n) = number of i in [0,n) where i>0 = n-1 + local.get $acc i32.add local.set $acc + + local.get $n i32.const 1 i32.add local.set $n + + ;; caller br_if: must read the right sidetable entry despite handler's stp movement + local.get $n i32.const 6 i32.gt_s br_if $exit + br $top + end end + + ;; n goes 1->6: count_pos(1)=0, count_pos(2)=1, count_pos(3)=2, + ;; count_pos(4)=3, count_pos(5)=4, count_pos(6)=5 + ;; acc = 0+1+2+3+4+5 = 15 + local.get $acc i32.const 15 i32.ne) +) diff --git a/test/fastcall/test59_dynfunc_br_if_fast.wasm b/test/fastcall/test59_dynfunc_br_if_fast.wasm new file mode 100644 index 0000000000000000000000000000000000000000..641f14f2c9195c92d98dc67378e6f4466a2bc71a GIT binary patch literal 183 zcmW-Xu?~VT07UQFBE}{J5);=l>Fns%$?zrO;>=wcw0 wcaIKYa}+5|q}2zCU=hi3l&~usYXOwBiRGe(tu4-4Zy9eogP{rri9t@Se_FpEh5!Hn literal 0 HcmV?d00001 diff --git a/test/fastcall/test59_dynfunc_br_if_fast.wasm.exit b/test/fastcall/test59_dynfunc_br_if_fast.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test59_dynfunc_br_if_fast.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test59_dynfunc_br_if_fast.wasm.flags b/test/fastcall/test59_dynfunc_br_if_fast.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test59_dynfunc_br_if_fast.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test59_dynfunc_br_if_fast.wat b/test/fastcall/test59_dynfunc_br_if_fast.wat new file mode 100644 index 000000000..2b7fc3858 --- /dev/null +++ b/test/fastcall/test59_dynfunc_br_if_fast.wat @@ -0,0 +1,63 @@ +;; Dynamic function (interpreted) with if/else surrounding a FAST_CALL. +;; Stresses stp: the if/else creates sidetable entries; after the FAST_CALL +;; on one arm, the interpreter must have the correct stp going forward. +;; +;; Func index layout: 0=new_func, 1=fast:double, 2=main +;; Dynamic function type 0: (i32 i32) -> i32 +;; param 0 = value, param 1 = flag +;; +;; Body bytecode (0 locals): +;; \00 = 0 locals +;; \20\01 = local.get 1 (flag) +;; \04\7F = if (i32) +;; \20\00 = local.get 0 (flag!=0: return value as-is) +;; \05 = else +;; \20\00 = local.get 0 +;; \10\01 = call 1 (fast:double) +;; \0B = end if +;; \0B = end +;; +;; dynfunc(6, 0) -> double(6) = 12 +;; dynfunc(5, 1) -> 5 +;; sum = 17 +(module + (type $t_ii_i (func (param i32 i32) (result i32))) + + (import "wave" "new_func" (func $new_func (param i32 i32 i32) (result i32))) + + (func $double (export "fast:double") (param i32) (result i32) + local.get 0 + local.get 0 + i32.add) + + (memory (export "memory") 1) + ;; 12 bytes: \00 \20\01 \04\7F \20\00 \05 \20\00 \10\01 \0B \0B + (data (i32.const 0) "\00\20\01\04\7F\20\00\05\20\00\10\01\0B\0B") + + (table (export "table") 0 funcref) + + (func (export "main") (result i32) + (local $slot i32) + (local $acc i32) + + ;; create: type=0 (ii->i), ptr=0, len=14 + (call $new_func (i32.const 0) (i32.const 0) (i32.const 14)) + local.set $slot + + ;; dynfunc(6, 0) -> double(6) = 12 + i32.const 6 + i32.const 0 + local.get $slot + (call_indirect (type $t_ii_i)) + local.set $acc + + ;; dynfunc(5, 1) -> 5 + i32.const 5 + i32.const 1 + local.get $slot + (call_indirect (type $t_ii_i)) + local.get $acc + i32.add + i32.const 17 + i32.ne) +) diff --git a/test/fastcall/test60_dynfunc_loop_fast.wasm b/test/fastcall/test60_dynfunc_loop_fast.wasm new file mode 100644 index 0000000000000000000000000000000000000000..0c887e2da7992d3e532a676cfab549a798054f4c GIT binary patch literal 175 zcmWlOu?~VT00rM`ix8>_Y;F{zKjB0tH-AB@fdpgG2uhs#>q2h0pPG=%c5>mkye uh+$xP*IP1J%oG_)*w`QkY i32 +;; +;; Body bytecode (1 local of type i32): +;; \01\7F = 1 local, type i32 +;; \20\00 = local.get 0 (copy param to local $v) +;; \21\01 = local.set 1 +;; \02\40 = block +;; \03\40 = loop +;; \20\01 = local.get 1 +;; \41\0A = i32.const 10 +;; \4E = i32.ge_s +;; \0D\01 = br_if 1 (exit block if v >= 10) +;; \20\01 = local.get 1 +;; \10\01 = call 1 (fast:inc) +;; \21\01 = local.set 1 +;; \0C\00 = br 0 (back to loop) +;; \0B = end loop +;; \0B = end block +;; \20\01 = local.get 1 +;; \0B = end +;; +;; dynfunc(7) -> increments 7->8->9->10 (3 fast:inc calls), returns 10 +(module + (type $t_i_i (func (param i32) (result i32))) + + (import "wave" "new_func" (func $new_func (param i32 i32 i32) (result i32))) + + (func $inc (export "fast:inc") (param i32) (result i32) + local.get 0 + i32.const 1 + i32.add) + + (memory (export "memory") 1) + ;; 31 bytes: locals section is \01\01\7F (1 entry, count=1, type=i32) + (data (i32.const 0) "\01\01\7F\20\00\21\01\02\40\03\40\20\01\41\0A\4E\0D\01\20\01\10\01\21\01\0C\00\0B\0B\20\01\0B") + + (table (export "table") 0 funcref) + + (func (export "main") (result i32) + (local $slot i32) + + ;; create: type=0 (i32->i32), ptr=0, len=31 + (call $new_func (i32.const 0) (i32.const 0) (i32.const 31)) + local.set $slot + + ;; dynfunc(7) -> 10 + i32.const 7 + local.get $slot + (call_indirect (type $t_i_i)) + i32.const 10 + i32.ne) +) diff --git a/test/fastcall/test61_dynfunc_if_else_fast.wasm b/test/fastcall/test61_dynfunc_if_else_fast.wasm new file mode 100644 index 0000000000000000000000000000000000000000..3cb72ecc29d91b5195c383784c7ceea06926bbab GIT binary patch literal 208 zcmX9#I}XAy6tnZ8h%9A+wQO8~rCTPBK?4NDr!Ar_6;rOx17yh`*+%GU0^rhAOiYzZ zU)Jd-U{Z6MF}&imiR11xGzTbcG@y;)1F)K4wz2LMy1qQN!~Pz@e`?}6^bu-O$GUyK z6>J}*CQKbJ4fL$k84AJGW$>amx28&-9zM^pg14Rp=ERC(WgxcT)!VIe3(Cdil1(a* I(+Vl)KDIX`^#A|> literal 0 HcmV?d00001 diff --git a/test/fastcall/test61_dynfunc_if_else_fast.wasm.exit b/test/fastcall/test61_dynfunc_if_else_fast.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test61_dynfunc_if_else_fast.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test61_dynfunc_if_else_fast.wasm.flags b/test/fastcall/test61_dynfunc_if_else_fast.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test61_dynfunc_if_else_fast.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test61_dynfunc_if_else_fast.wat b/test/fastcall/test61_dynfunc_if_else_fast.wat new file mode 100644 index 000000000..44d52defd --- /dev/null +++ b/test/fastcall/test61_dynfunc_if_else_fast.wat @@ -0,0 +1,69 @@ +;; Dynamic function (interpreted) with two FAST_CALLs: one on each arm of if/else. +;; Two different fast handlers on each branch stress the sidetable through both arms. +;; +;; Func index layout: 0=new_func, 1=fast:double, 2=fast:negate, 3=main +;; Dynamic function type 1: (i32 i32) -> i32 (types: 0=i32->i32, 1=ii->i) +;; param 0=value, param 1=flag +;; +;; Body (0 locals): +;; \00 = 0 locals +;; \20\01 = local.get 1 (flag) +;; \04\7F = if (i32) +;; \20\00 = local.get 0 +;; \10\01 = call 1 (fast:double) +;; \05 = else +;; \20\00 = local.get 0 +;; \10\02 = call 2 (fast:negate) +;; \0B = end +;; \0B = end +;; +;; dynfunc(5, 1) -> double(5) = 10 +;; dynfunc(5, 0) -> negate(5) = -5 +;; 10 + (-5) = 5 +(module + (type $t_i_i (func (param i32) (result i32))) + (type $t_ii_i (func (param i32 i32) (result i32))) + + (import "wave" "new_func" (func $new_func (param i32 i32 i32) (result i32))) + + (func $double (export "fast:double") (param i32) (result i32) + local.get 0 + local.get 0 + i32.add) + + (func $negate (export "fast:negate") (param i32) (result i32) + i32.const 0 + local.get 0 + i32.sub) + + (memory (export "memory") 1) + ;; 14 bytes: \00 \20\01 \04\7F \20\00 \10\01 \05 \20\00 \10\02 \0B \0B + (data (i32.const 0) "\00\20\01\04\7F\20\00\10\01\05\20\00\10\02\0B\0B") + + (table (export "table") 0 funcref) + + (func (export "main") (result i32) + (local $slot i32) + (local $acc i32) + + ;; create: type=1 (ii->i), ptr=0, len=16 + (call $new_func (i32.const 1) (i32.const 0) (i32.const 16)) + local.set $slot + + ;; dynfunc(5, 1) -> double(5) = 10 + i32.const 5 + i32.const 1 + local.get $slot + (call_indirect (type $t_ii_i)) + local.set $acc + + ;; dynfunc(5, 0) -> negate(5) = -5 + i32.const 5 + i32.const 0 + local.get $slot + (call_indirect (type $t_ii_i)) + local.get $acc + i32.add + i32.const 5 + i32.ne) +) diff --git a/test/fastcall/test62_dynfunc_fast_outcall_if.wasm b/test/fastcall/test62_dynfunc_fast_outcall_if.wasm new file mode 100644 index 0000000000000000000000000000000000000000..8da7e5320359eaecb112da0e4f3d9892651d3987 GIT binary patch literal 200 zcmW-YO$)*>7=x3xn_^*XAb8zw9=+=AJ^3@XIyacCoA`;R{&lMao`i(J-8}(tV;TmA zMui`B_!}5hLGyO6ZaH=Dx_?eBlr|dB#_$Rxn&4t**1fww4(IuK8oT;6xVm-Y2$lNI z&$o|4@^En>jCaEXz1r&q%BYJ?BXim i32 +;; if flag: return value; else: return fast:double_via_call(value) +;; +;; Body (0 locals): +;; \00 \20\01 \04\7F \20\00 \05 \20\00 \10\01 \0B \0B +(module + (type $t_i_i (func (param i32) (result i32))) + (type $t_ii_i (func (param i32 i32) (result i32))) + + (import "wave" "new_func" (func $new_func (param i32 i32 i32) (result i32))) + + ;; slow_double: a regular (non-fast) function called by the fast handler + (func $slow_double (param i32) (result i32) + local.get 0 + local.get 0 + i32.add) + + ;; fast handler that makes an out-call to slow_double + (func $double_via_call (export "fast:double_via_call") (param i32) (result i32) + local.get 0 + call $slow_double) + + (memory (export "memory") 1) + ;; body: \00 \20\01 \04\7F \20\00 \05 \20\00 \10\02 \0B \0B + ;; (fast:double_via_call is func index 2) + (data (i32.const 0) "\00\20\01\04\7F\20\00\05\20\00\10\02\0B\0B") + + (table (export "table") 0 funcref) + + (func (export "main") (result i32) + (local $slot i32) + (local $acc i32) + + ;; create: type=0 (ii->i), ptr=0, len=14 + (call $new_func (i32.const 1) (i32.const 0) (i32.const 14)) + local.set $slot + + ;; dynfunc(6, 0) -> double_via_call(6) = 12 + i32.const 6 + i32.const 0 + local.get $slot + (call_indirect (type $t_ii_i)) + local.set $acc + + ;; dynfunc(5, 1) -> 5 (if-arm: no fast call) + i32.const 5 + i32.const 1 + local.get $slot + (call_indirect (type $t_ii_i)) + local.get $acc + i32.add + i32.const 17 + i32.ne) +) diff --git a/test/fastcall/test63_dynfunc_fast_outcall_loop.wasm b/test/fastcall/test63_dynfunc_fast_outcall_loop.wasm new file mode 100644 index 0000000000000000000000000000000000000000..07848be2afc4e2bab50912b37cd378daf80354b6 GIT binary patch literal 192 zcmWlOu?~VT00rM`ix{d2Y;Kgn!NDJJqLZ7y0F^+30W^XTr~bN_8!own8+!s^B1?Mu zQhNUv=tV-cxVhdA^-?sSp#r6nfKZArAdm#Zvq~B_PM3D5in(<~<+=`H)7Sm;{S^o% zckgOK^{yQtqmv9_VENFS)iL#f^cE{=j0`q3NB|pMwLWsqI$gg(Mv=?h&_=gC4P%jU I2dxeD4`qlTc>n+a literal 0 HcmV?d00001 diff --git a/test/fastcall/test63_dynfunc_fast_outcall_loop.wat b/test/fastcall/test63_dynfunc_fast_outcall_loop.wat new file mode 100644 index 000000000..2b4521920 --- /dev/null +++ b/test/fastcall/test63_dynfunc_fast_outcall_loop.wat @@ -0,0 +1,50 @@ +;; Dynamic function (interpreted) with a loop that calls a fast handler which +;; makes an out-call to a non-fast function with its own control flow. +;; br_if and br inside the loop must have correct stp after every fast call. +;; +;; Func index layout: 0=new_func, 1=fast:inc_via_call, 2=slow_inc, 3=main +;; +;; Dynamic function body (1 local): +;; \01\01\7F = 1 local of type i32 +;; \20\00 \21\01 = local.get 0, local.set 1 (copy param to $v) +;; \02\40 = block +;; \03\40 = loop +;; \20\01 \41\0A \4E = local.get 1, i32.const 10, i32.ge_s +;; \0D\01 = br_if 1 (exit if v >= 10) +;; \20\01 \10\01 \21\01 = local.get 1, call 1 (fast:inc_via_call), local.set 1 +;; \0C\00 = br 0 (loop back) +;; \0B \0B = end loop, end block +;; \20\01 \0B = local.get 1, end +(module + (type $t_i_i (func (param i32) (result i32))) + + (import "wave" "new_func" (func $new_func (param i32 i32 i32) (result i32))) + + (func $slow_inc (param i32) (result i32) + local.get 0 + i32.const 1 + i32.add) + + (func $inc_via_call (export "fast:inc_via_call") (param i32) (result i32) + local.get 0 + call $slow_inc) + + (memory (export "memory") 1) + (data (i32.const 0) "\01\01\7F\20\00\21\01\02\40\03\40\20\01\41\0A\4E\0D\01\20\01\10\02\21\01\0C\00\0B\0B\20\01\0B") + + (table (export "table") 0 funcref) + + (func (export "main") (result i32) + (local $slot i32) + + ;; body length: 31 bytes + (call $new_func (i32.const 0) (i32.const 0) (i32.const 31)) + local.set $slot + + ;; dynfunc(7) -> increments to 10, returns 10 + i32.const 7 + local.get $slot + (call_indirect (type $t_i_i)) + i32.const 10 + i32.ne) +) diff --git a/test/fastcall/test64_dynfunc_fast_outcall_complex.wasm b/test/fastcall/test64_dynfunc_fast_outcall_complex.wasm new file mode 100644 index 0000000000000000000000000000000000000000..8fe66a12becd729a1a86eff358648cc0e7be01f8 GIT binary patch literal 220 zcmW-Yy>7xV6ot>ZcA%Bl-a-{TiSd4Ne^whA1+gSh8SxAV=a52G6a`9ySl_-d^>l!pT-1PJkp&UtYQcx>o)dJPN+^#%<>6?EPb Y4K*sQQQ5G5ckY=8aJ6<@JgS*?e{M%3i~s-t literal 0 HcmV?d00001 diff --git a/test/fastcall/test64_dynfunc_fast_outcall_complex.wat b/test/fastcall/test64_dynfunc_fast_outcall_complex.wat new file mode 100644 index 000000000..cdd9cf1cc --- /dev/null +++ b/test/fastcall/test64_dynfunc_fast_outcall_complex.wat @@ -0,0 +1,65 @@ +;; Dynamic function (interpreted, created via wave.new_func) calls a fast handler +;; which makes an out-call to a non-fast function with its own loops and branches. +;; The out-callee is large/complex to maximize stp movement during the out-call. +;; After the fast call, the dynamic function branches (if/else) -- stp must be correct. +;; +;; Func index layout: 0=new_func, 1=fast:compute, 2=slow_sum, 3=main +;; slow_sum(n): sums 0..n-1, has a loop+br_if (lots of stp movement) +;; fast:compute calls slow_sum +;; +;; Dynamic function body (0 locals): if flag, return value; else call fast:compute(value) +;; \00 \20\01 \04\7F \20\00 \05 \20\00 \10\01 \0B \0B +;; (fast:compute is func index 1) +(module + (type $t_i_i (func (param i32) (result i32))) + (type $t_ii_i (func (param i32 i32) (result i32))) + + (import "wave" "new_func" (func $new_func (param i32 i32 i32) (result i32))) + + ;; slow_sum: sum 0+1+...+(n-1). Has a loop with br_if = multiple stp entries. + (func $slow_sum (param $n i32) (result i32) + (local $i i32) (local $acc i32) + block $exit loop $top + local.get $i local.get $n i32.ge_s br_if $exit + local.get $acc local.get $i i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $top + end end + local.get $acc) + + ;; fast handler: calls slow_sum (the out-call) + (func $compute (export "fast:compute") (param i32) (result i32) + local.get 0 + call $slow_sum) + + (memory (export "memory") 1) + ;; body bytes: \00 \20\01 \04\7F \20\00 \05 \20\00 \10\01 \0B \0B (14 bytes) + ;; fast:compute is func index 1 + (data (i32.const 0) "\00\20\01\04\7F\20\00\05\20\00\10\01\0B\0B") + + (table (export "table") 0 funcref) + + (func (export "main") (result i32) + (local $slot i32) + (local $acc i32) + + (call $new_func (i32.const 1) (i32.const 0) (i32.const 14)) + local.set $slot + + ;; dynfunc(5, 0) -> compute(5) = slow_sum(5) = 0+1+2+3+4 = 10 + i32.const 5 + i32.const 0 + local.get $slot + (call_indirect (type $t_ii_i)) + local.set $acc + + ;; dynfunc(5, 1) -> 5 (if-arm, no fast call, stp must be correct for this branch) + i32.const 5 + i32.const 1 + local.get $slot + (call_indirect (type $t_ii_i)) + local.get $acc + i32.add ;; 10 + 5 = 15 + i32.const 15 + i32.ne) +) diff --git a/test/fastcall/test65_dynfunc_fast_deep_outcall.wasm b/test/fastcall/test65_dynfunc_fast_deep_outcall.wasm new file mode 100644 index 0000000000000000000000000000000000000000..c183601a287c2d856420c782915ea0cb64229f33 GIT binary patch literal 249 zcmW-ZK}*9x6ohBqzO<#QC51xq_5y-O@1DA+f`7uUl0wDAk~S7k``3N(GBXS_AM&Lm z0B-fb!g7!@X(;~&7Fkno`KMjoM;bwlcf70It&SM1*1B&a!82r4+EVgtN;K2 literal 0 HcmV?d00001 diff --git a/test/fastcall/test65_dynfunc_fast_deep_outcall.wat b/test/fastcall/test65_dynfunc_fast_deep_outcall.wat new file mode 100644 index 000000000..50cd64268 --- /dev/null +++ b/test/fastcall/test65_dynfunc_fast_deep_outcall.wat @@ -0,0 +1,73 @@ +;; Dynamic function (wave.new_func) has if/else; the fast handler it calls makes +;; a deep chain of out-calls (non-fast), each with their own loops and branches. +;; This maximizes the chance that m_ip or m_stp in the dynamic function's frame +;; gets clobbered by the deep call chain before the fast handler returns. +;; +;; Func layout: 0=new_func, 1=fast:run, 2=depth2, 3=depth1, 4=main +;; fast:run -> depth1(n) -> depth2(n) -> loop summing +;; +;; Dynamic body (type 1 = ii->i, 0 locals): +;; if flag: return value; else: call fast:run(value) +;; \00 \20\01 \04\7F \20\00 \05 \20\00 \10\01 \0B \0B +(module + (type $t_i_i (func (param i32) (result i32))) + (type $t_ii_i (func (param i32 i32) (result i32))) + + (import "wave" "new_func" (func $new_func (param i32 i32 i32) (result i32))) + + ;; depth2: sum 1..n (loop with br_if) + (func $depth2 (param $n i32) (result i32) + (local $i i32) (local $acc i32) + i32.const 1 local.set $i + block $exit loop $top + local.get $i local.get $n i32.gt_s br_if $exit + local.get $acc local.get $i i32.add local.set $acc + local.get $i i32.const 1 i32.add local.set $i + br $top + end end + local.get $acc) + + ;; depth1: calls depth2 twice with different args, adds results + (func $depth1 (param $n i32) (result i32) + (local $a i32) + local.get $n call $depth2 local.set $a + local.get $n i32.const 1 i32.add call $depth2 + local.get $a i32.add) + + ;; fast handler: calls depth1 (out-call from SPC into interpreter) + (func $run (export "fast:run") (param i32) (result i32) + local.get 0 + call $depth1) + + (memory (export "memory") 1) + ;; fast:run is func index 3 + (data (i32.const 0) "\00\20\01\04\7F\20\00\05\20\00\10\03\0B\0B") + + (table (export "table") 0 funcref) + + (func (export "main") (result i32) + (local $slot i32) + (local $r0 i32) (local $r1 i32) + + (call $new_func (i32.const 1) (i32.const 0) (i32.const 14)) + local.set $slot + + ;; dynfunc(4, 0) -> run(4) = depth1(4) = depth2(4)+depth2(5) + ;; depth2(4) = 1+2+3+4 = 10, depth2(5) = 1+2+3+4+5 = 15 -> 25 + i32.const 4 + i32.const 0 + local.get $slot + (call_indirect (type $t_ii_i)) + local.set $r0 + + ;; dynfunc(4, 1) -> 4 (if-arm: no fast call, stp must be correct here) + i32.const 4 + i32.const 1 + local.get $slot + (call_indirect (type $t_ii_i)) + local.set $r1 + + local.get $r0 i32.const 25 i32.ne + local.get $r1 i32.const 4 i32.ne + i32.or) +) diff --git a/test/fastcall/test66_fast_handler_indirect_call.wasm b/test/fastcall/test66_fast_handler_indirect_call.wasm new file mode 100644 index 0000000000000000000000000000000000000000..259867f9f184217eb52bf78b1f8a86a6fcd25239 GIT binary patch literal 102 zcmWNF(F#C76hvq2YFk_4o$?*t_Q`L!iXtSG$NhD;snaI&mc|&0^~%9q`$9YG}1IPDC}mg#w$O0A&V%2@A&oy%)MxA%k~5Qnqz$c=YM$h4Z_a!Uya S;Yg}DVPp^42_oAk=^B2^3Kksz literal 0 HcmV?d00001 diff --git a/test/fastcall/test67_fast_handler_indirect_if_else.wasm.exit b/test/fastcall/test67_fast_handler_indirect_if_else.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test67_fast_handler_indirect_if_else.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test67_fast_handler_indirect_if_else.wasm.flags b/test/fastcall/test67_fast_handler_indirect_if_else.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test67_fast_handler_indirect_if_else.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test67_fast_handler_indirect_if_else.wat b/test/fastcall/test67_fast_handler_indirect_if_else.wat new file mode 100644 index 000000000..90c908048 --- /dev/null +++ b/test/fastcall/test67_fast_handler_indirect_if_else.wat @@ -0,0 +1,54 @@ +;; Fast handler contains call_indirect inside an if/else. +;; One arm performs the indirect out-call, the other is pure. +;; stp must be correct on both arms after compilation. +;; +;; Func index layout: 0=double (non-fast), 1=fast:branch_call (fast), 2=main +;; table[0] = $double +;; +;; fast:branch_call(value, flag): +;; if flag != 0: return value +;; else: return call_indirect[table[0]](value) ;; = double(value) +;; +;; main: branch_call(5, 1) = 5 +;; branch_call(6, 0) = double(6) = 12 +;; sum = 17 +(module + (type $t_i_i (func (param i32) (result i32))) + (type $t_ii_i (func (param i32 i32) (result i32))) + + (func $double (param i32) (result i32) + local.get 0 + local.get 0 + i32.add) + + (func $branch_call (export "fast:branch_call") (param $v i32) (param $flag i32) (result i32) + local.get $flag + if (result i32) + local.get $v + else + local.get $v + i32.const 0 + call_indirect (type $t_i_i) + end) + + (table (export "table") 1 funcref) + (elem (i32.const 0) $double) + + (func (export "main") (result i32) + (local $acc i32) + + ;; if-arm: no indirect call, returns value as-is + i32.const 5 + i32.const 1 + call $branch_call + local.set $acc + + ;; else-arm: indirect call to double + i32.const 6 + i32.const 0 + call $branch_call + local.get $acc + i32.add ;; 5 + 12 = 17 + i32.const 17 + i32.ne) +) diff --git a/test/fastcall/test68_fast_handler_indirect_loop.wasm b/test/fastcall/test68_fast_handler_indirect_loop.wasm new file mode 100644 index 0000000000000000000000000000000000000000..13e9bb58f4052055192647fe205b3855ef701ba1 GIT binary patch literal 132 zcmWN`K@Ng26h+bZ+M0%bHM)c1A{;oPBW7+vzD5&G5fYep>vVLJbD_&f01ReeVHv<; zovq*;XVACy_|av( literal 0 HcmV?d00001 diff --git a/test/fastcall/test68_fast_handler_indirect_loop.wasm.exit b/test/fastcall/test68_fast_handler_indirect_loop.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test68_fast_handler_indirect_loop.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test68_fast_handler_indirect_loop.wasm.flags b/test/fastcall/test68_fast_handler_indirect_loop.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test68_fast_handler_indirect_loop.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test68_fast_handler_indirect_loop.wat b/test/fastcall/test68_fast_handler_indirect_loop.wat new file mode 100644 index 000000000..8ebcb5600 --- /dev/null +++ b/test/fastcall/test68_fast_handler_indirect_loop.wat @@ -0,0 +1,45 @@ +;; Fast handler contains call_indirect inside a loop. +;; br_if (loop exit) and br (loop back) must have correct stp after each +;; indirect out-call. Mirrors test60 but stressor is inside the fast handler. +;; +;; Func index layout: 0=inc (non-fast), 1=fast:loop_call (fast), 2=main +;; table[0] = $inc +;; +;; fast:loop_call(x): loop calling table[0](v) until v >= 10, return v +;; starting from x=7: 7->8->9->10, returns 10 +(module + (type $t_i_i (func (param i32) (result i32))) + + (func $inc (param i32) (result i32) + local.get 0 + i32.const 1 + i32.add) + + (func $loop_call (export "fast:loop_call") (param $x i32) (result i32) + (local $v i32) + local.get $x + local.set $v + block $exit + loop $top + local.get $v + i32.const 10 + i32.ge_s + br_if $exit + local.get $v + i32.const 0 ;; table index + call_indirect (type $t_i_i) + local.set $v + br $top + end + end + local.get $v) + + (table (export "table") 1 funcref) + (elem (i32.const 0) $inc) + + (func (export "main") (result i32) + i32.const 7 + call $loop_call + i32.const 10 + i32.ne) +) diff --git a/test/fastcall/test69_fast_handler_two_indirect_calls.wasm b/test/fastcall/test69_fast_handler_two_indirect_calls.wasm new file mode 100644 index 0000000000000000000000000000000000000000..fb2e25b91cbf29fbc3a6b60998e9df0709c83a6a GIT binary patch literal 128 zcmWlRF$w}P6b0W)eu!&86g)uo2G(||Jcb)ZLCva=pk=P^muZG62D#1zz@?ek*(b1D zC;uYCH;fY8iYx9{tC&ZSfs*Yc@c2$}Qk2|Fx^gkW^C6OX9egVz-C2wSp8^$jpG OGEpTANN#P?=Ma8a6%z;m literal 0 HcmV?d00001 diff --git a/test/fastcall/test69_fast_handler_two_indirect_calls.wasm.exit b/test/fastcall/test69_fast_handler_two_indirect_calls.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test69_fast_handler_two_indirect_calls.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test69_fast_handler_two_indirect_calls.wasm.flags b/test/fastcall/test69_fast_handler_two_indirect_calls.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test69_fast_handler_two_indirect_calls.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test69_fast_handler_two_indirect_calls.wat b/test/fastcall/test69_fast_handler_two_indirect_calls.wat new file mode 100644 index 000000000..06f913d40 --- /dev/null +++ b/test/fastcall/test69_fast_handler_two_indirect_calls.wat @@ -0,0 +1,47 @@ +;; Fast handler makes two sequential call_indirect calls to different table slots. +;; Tests that ip/stp state is correct between consecutive indirect out-calls. +;; +;; Func index layout: 0=double (non-fast), 1=negate (non-fast), +;; 2=fast:two_calls (fast), 3=main +;; table[0] = $double, table[1] = $negate +;; +;; fast:two_calls(x): +;; a = call_indirect[0](x) ;; double(x) = 2x +;; b = call_indirect[1](a) ;; negate(2x) = -2x +;; return b +;; +;; main: two_calls(5) = negate(double(5)) = negate(10) = -10 +;; check result == -10 +(module + (type $t_i_i (func (param i32) (result i32))) + + (func $double (param i32) (result i32) + local.get 0 + local.get 0 + i32.add) + + (func $negate (param i32) (result i32) + i32.const 0 + local.get 0 + i32.sub) + + (func $two_calls (export "fast:two_calls") (param $x i32) (result i32) + (local $a i32) + local.get $x + i32.const 0 + call_indirect (type $t_i_i) ;; double(x) + local.set $a + local.get $a + i32.const 1 + call_indirect (type $t_i_i) ;; negate(a) + ) + + (table (export "table") 2 funcref) + (elem (i32.const 0) $double $negate) + + (func (export "main") (result i32) + i32.const 5 + call $two_calls + i32.const -10 + i32.ne) +) diff --git a/test/fastcall/test70_fast_handler_dynamic_dispatch.wasm b/test/fastcall/test70_fast_handler_dynamic_dispatch.wasm new file mode 100644 index 0000000000000000000000000000000000000000..c7f57170cb2fcceb7df1ce2b4e6efcbc8a6bbbbf GIT binary patch literal 158 zcmW-b-3r1m424gc);fzY-=N}Kc$cfa#_At#b24b}`|73=IQjTU;2`Cd08q~(RjQ+@ zEkTucu6biEZD1ey_)584A5-2^xxc}#q}%67uxpyWuw6$G1lE_s;5?$v9K5=SMR$bI d9J=P|1cVDw6)WiZ4B3ko(0fG|^GC5m_yHmC7c2k( literal 0 HcmV?d00001 diff --git a/test/fastcall/test70_fast_handler_dynamic_dispatch.wasm.exit b/test/fastcall/test70_fast_handler_dynamic_dispatch.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test70_fast_handler_dynamic_dispatch.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test70_fast_handler_dynamic_dispatch.wasm.flags b/test/fastcall/test70_fast_handler_dynamic_dispatch.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test70_fast_handler_dynamic_dispatch.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test70_fast_handler_dynamic_dispatch.wat b/test/fastcall/test70_fast_handler_dynamic_dispatch.wat new file mode 100644 index 000000000..a1d72bd4a --- /dev/null +++ b/test/fastcall/test70_fast_handler_dynamic_dispatch.wat @@ -0,0 +1,70 @@ +;; Fast handler dispatches to one of N table slots based on a runtime parameter. +;; The table index is computed from the argument, so the callee is not statically +;; known — tests truly dynamic indirect dispatch inside SPC. +;; +;; Func index layout: 0=double (non-fast), 1=negate (non-fast), +;; 2=inc (non-fast), 3=fast:dispatch (fast), 4=main +;; table[0] = $double, table[1] = $negate, table[2] = $inc +;; +;; fast:dispatch(value, selector): +;; call_indirect[selector](value) +;; selector=0 -> double(value), selector=1 -> negate(value), selector=2 -> inc(value) +;; +;; main: +;; dispatch(4, 0) = double(4) = 8 +;; dispatch(8, 1) = negate(8) = -8 +;; dispatch(3, 2) = inc(3) = 4 +;; sum = 8 + (-8) + 4 = 4, check == 4 +(module + (type $t_i_i (func (param i32) (result i32))) + (type $t_ii_i (func (param i32 i32) (result i32))) + + (func $double (param i32) (result i32) + local.get 0 + local.get 0 + i32.add) + + (func $negate (param i32) (result i32) + i32.const 0 + local.get 0 + i32.sub) + + (func $inc (param i32) (result i32) + local.get 0 + i32.const 1 + i32.add) + + (func $dispatch (export "fast:dispatch") (param $value i32) (param $sel i32) (result i32) + local.get $value + local.get $sel + call_indirect (type $t_i_i)) + + (table (export "table") 3 funcref) + (elem (i32.const 0) $double $negate $inc) + + (func (export "main") (result i32) + (local $acc i32) + + ;; dispatch(4, 0) = double(4) = 8 + i32.const 4 + i32.const 0 + call $dispatch + local.set $acc + + ;; dispatch(8, 1) = negate(8) = -8 + i32.const 8 + i32.const 1 + call $dispatch + local.get $acc + i32.add + local.set $acc + + ;; dispatch(3, 2) = inc(3) = 4 + i32.const 3 + i32.const 2 + call $dispatch + local.get $acc + i32.add ;; 8 + (-8) + 4 = 4 + i32.const 4 + i32.ne) +) diff --git a/test/fastcall/test71_fast_handler_indirect_heavy.wasm b/test/fastcall/test71_fast_handler_indirect_heavy.wasm new file mode 100644 index 0000000000000000000000000000000000000000..afc8bc5cf4bafbaefe01b56c435be8e0e38e3c7f GIT binary patch literal 248 zcmZ9GK?=e^3`PH+q>3GddI6bPx$p*VbXJ0=u!4fMRY7q(;Bh>qp}KODgz$b|P~STO zVCiIhfzYl#U7({Ok>KgdH;Xx4PK0Rna2=?F<@FkK~l3v{S4--xw(EtDd literal 0 HcmV?d00001 diff --git a/test/fastcall/test71_fast_handler_indirect_heavy.wasm.exit b/test/fastcall/test71_fast_handler_indirect_heavy.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test71_fast_handler_indirect_heavy.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test71_fast_handler_indirect_heavy.wasm.flags b/test/fastcall/test71_fast_handler_indirect_heavy.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test71_fast_handler_indirect_heavy.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test71_fast_handler_indirect_heavy.wat b/test/fastcall/test71_fast_handler_indirect_heavy.wat new file mode 100644 index 000000000..a69a6bc62 --- /dev/null +++ b/test/fastcall/test71_fast_handler_indirect_heavy.wat @@ -0,0 +1,139 @@ +;; Fast handler calls an indirect function that does a lot: +;; - calls two helper functions (fib-like recursion depth via iterative sum + product) +;; - has its own locals, loop, and branch +;; +;; Func index layout: +;; 0 = $sum_to_n : (i32) -> i32 sum 1..n +;; 1 = $product_to_n : (i32) -> i32 product 1..n (n!) +;; 2 = $heavy : (i32) -> i32 calls sum_to_n + product_to_n, loops, branches +;; 3 = fast:invoke : (i32) -> i32 fast handler, calls table[0] = $heavy +;; 4 = $main : () -> i32 +;; +;; table[0] = $heavy +;; +;; $sum_to_n(n): returns 1+2+...+n (loop with br_if) +;; $product_to_n(n): returns 1*2*...*n (loop with br_if) +;; +;; $heavy(n): +;; s = sum_to_n(n) ;; e.g. n=4 -> 10 +;; p = product_to_n(n) ;; e.g. n=4 -> 24 +;; acc = 0 +;; loop i from 1..n: ;; accumulate s*i XOR p%i +;; acc += (s * i) + (p / (i+1)) +;; return acc +;; +;; For n=4: +;; s = 10, p = 24 +;; i=1: (10*1) + (24/2) = 10+12 = 22 +;; i=2: (10*2) + (24/3) = 20+8 = 28 +;; i=3: (10*3) + (24/4) = 30+6 = 36 +;; i=4: (10*4) + (24/5) = 40+4 = 44 +;; acc = 22+28+36+44 = 130 +;; +;; fast:invoke(4) -> heavy(4) = 130 +;; main: checks result == 130 +(module + (type $t_i_i (func (param i32) (result i32))) + + (func $sum_to_n (param $n i32) (result i32) + (local $i i32) (local $acc i32) + i32.const 1 + local.set $i + block $exit + loop $top + local.get $i + local.get $n + i32.gt_s + br_if $exit + local.get $acc + local.get $i + i32.add + local.set $acc + local.get $i + i32.const 1 + i32.add + local.set $i + br $top + end + end + local.get $acc) + + (func $product_to_n (param $n i32) (result i32) + (local $i i32) (local $acc i32) + i32.const 1 + local.set $i + i32.const 1 + local.set $acc + block $exit + loop $top + local.get $i + local.get $n + i32.gt_s + br_if $exit + local.get $acc + local.get $i + i32.mul + local.set $acc + local.get $i + i32.const 1 + i32.add + local.set $i + br $top + end + end + local.get $acc) + + ;; heavy(n): s=sum_to_n(n), p=product_to_n(n), loop i=1..n accumulating (s*i)+(p/(i+1)) + (func $heavy (param $n i32) (result i32) + (local $s i32) (local $p i32) (local $i i32) (local $acc i32) + local.get $n + call $sum_to_n + local.set $s + local.get $n + call $product_to_n + local.set $p + i32.const 1 + local.set $i + block $exit + loop $top + local.get $i + local.get $n + i32.gt_s + br_if $exit + ;; acc += (s * i) + (p / (i + 1)) + local.get $acc + local.get $s + local.get $i + i32.mul + local.get $p + local.get $i + i32.const 1 + i32.add + i32.div_s + i32.add + i32.add + local.set $acc + local.get $i + i32.const 1 + i32.add + local.set $i + br $top + end + end + local.get $acc) + + ;; fast handler: calls table[0] (= $heavy) via call_indirect + (func $invoke (export "fast:invoke") (param $n i32) (result i32) + local.get $n + i32.const 0 + call_indirect (type $t_i_i)) + + (table (export "table") 1 funcref) + (elem (i32.const 0) $heavy) + + (func (export "main") (result i32) + i32.const 4 + call $invoke + i32.const 130 + i32.ne) +) From bdbc235adb5c99c9d57288ca6afdfa7557acf8ae Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 27 Apr 2026 23:30:30 -0400 Subject: [PATCH 72/91] Assign fast_call_idx during parsing --- src/engine/BinParser.v3 | 9 +++++++++ src/engine/x86-64/X86_64Target.v3 | 25 ++++++------------------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/engine/BinParser.v3 b/src/engine/BinParser.v3 index 873fbf18e..672698898 100644 --- a/src/engine/BinParser.v3 +++ b/src/engine/BinParser.v3 @@ -541,6 +541,15 @@ class BinParser(extensions: Extension.set, limits: Limits, err: ErrorGen, filena } var decl = readExportWithoutName(); module.exports.put(name, decl); + // assign fast functions + if (FastIntTuning.useFastFunctions && Strings.startsWith(name, "fast:") && FuncDecl.?(decl)) { + def fdecl = FuncDecl.!(decl); + def fast_funcs = module.fast_funcs; + if (fast_funcs.length < Opcodes.FAST_CALL_OPCODES) { + fdecl.fast_call_idx = fast_funcs.length; + fast_funcs.put(fdecl); + } + } } def readExportWithoutName() -> Decl { var pt = decoder.pos; diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 95e11729d..180187101 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -290,29 +290,16 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { var compiler = newCompiler(module.filename, true, null); var w = compiler.w; - // generate code for all functions + // generate code for all fast functions var bounds = Array<(int, int)>.new(module.functions.length); var suberr = if(!interpreter_fallback, err); for (i = 0; err.ok() && i < module.functions.length; i++) { var f = module.functions[i]; - if (f.imported()) continue; - for (j < module.exports.length) { - def ex = module.exports[j]; - if (ex.1 == f && Strings.startsWith(ex.0, "fast:")) { - def fast_funcs = module.fast_funcs; - if (fast_funcs.length < Opcodes.FAST_CALL_OPCODES) { - // allocate FAST_CALL opcode - def idx = fast_funcs.length; - f.fast_call_idx = idx; - fast_funcs.put(f); - - var start = w.atEnd().pos; - var compiled = compiler.gen(module, f, suberr); - if (compiled) bounds[i] = (start, w.end()); - else bounds[i] = (-1, -1); - } - } - } + if (f.fast_call_idx < 0) continue; + var start = w.atEnd().pos; + var compiled = compiler.gen(module, f, suberr); + if (compiled) bounds[i] = (start, w.end()); + else bounds[i] = (-1, -1); } // copy and map code (reserve32 ensures address fits in 32 bits for dispatch table patching) From 2ccc1a47983de76d82d0d37537b004ec1aa508bf Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 28 Apr 2026 01:34:42 -0400 Subject: [PATCH 73/91] Add fixes PR to master --- src/engine/compiler/SinglePassCompiler.v3 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 098738849..ff2f71034 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -2213,6 +2213,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def computePc(delta: int); // Emit code to materialize stack frames for each inlined function. def emitReconstructStackFrames(frames: Array) -> int { + unrefRegs(); Metrics.spc_static_reconst.val++; masm.emit_inc_metric(Metrics.spc_dynamic_reconst); @@ -2265,6 +2266,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl prev_base_sp = cur_base_sp; } + unrefRegs(); return total_space; } def emitReconstructStackFrame(spcFrame: SpcFrame, offset: int, vfp_delta: int, @@ -2330,7 +2332,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (fast) { saveReconstructCallerIVars(); } - unrefRegs(); frames_reconstructed = true; def space = emitReconstructStackFrames(snapshotFrames()); emit(); From 098aaa76d588e1ba8a09589720e66c45b7b15651 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 28 Apr 2026 02:32:07 -0400 Subject: [PATCH 74/91] Spill registers in visitCallIndirect in fast mode (Why?) --- src/engine/compiler/SinglePassCompiler.v3 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index ff2f71034..c4eb8a3f9 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -1014,6 +1014,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, tailCall: bool) { var sig = SigDecl.!(module.heaptypes[sig_index]); + if (fast) state.emitSaveAll(resolver, SpillMode.SAVE_AND_FREE_REGS); withReconstructedInlinedFrames(fun { var vsp_reg = allocTmpFixed(ValueKind.REF, regs.vsp); var sv = popFixedReg(regs.func_arg); @@ -1044,7 +1045,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Non-final signatures do a fast-path check and then fallback to a runtime call. var sigokpt = masm.newLabel(it.pc); masm.emit_breq_r_i(tmp_reg, sig.canon_id, sigokpt); - state.emitSaveAll(resolver, SpillMode.SAVE_AND_REMEMBER_STORED); // XXX: no need to save all regs? + if (!fast) state.emitSaveAll(resolver, SpillMode.SAVE_AND_REMEMBER_STORED); // XXX: no need to save all regs? var arg2 = regs.runtime_arg2; // load from table into runtime arg0 masm.emit_v3_Table_funcs_r_r(arg2, table_reg); From a842fdd7d9db933b34ecc7f0457a9af7a51f36d3 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 28 Apr 2026 16:53:28 -0400 Subject: [PATCH 75/91] Streamline save/restore of interpreter registers --- src/engine/compiler/SinglePassCompiler.v3 | 19 ++++++++----------- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 18 +++++++++++------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index c4eb8a3f9..6c1892ef2 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -400,7 +400,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def r_ip = X86_64MasmRegs.INT_EXEC_ENV.ip; masm.emit_addw_r_i(r_ip, fast_operand_size); // increment ip computePc(-(fast_operand_size + 1)); // compute r_curpc - saveCallerIVars(); // save r_ip and r_curpc + saveFastIVars(); // Why do we have to compute and save? // 1. r_ip = rax (clobbered by HW `div`) |\ can validation catch this? // 2. m_curpc = HW trap reads this |/ or hidden by arbitrary outcalls? @@ -2172,8 +2172,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_addw_r_i(regs.sp, frame.frameSize); masm.emit_ret(); } else { - // Restore VFP from interpreter frame - masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); + restoreFastIVars(); emitFastDispatch(); } } @@ -2207,10 +2206,11 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl return label; } def getSpcInlinedFrameIp() -> long; - def saveCallerIVars(); - def saveReconstructCallerIVars(); + def saveFastIVars(); + def saveReconstructIVars(); def restoreDispatchTableReg(); - def restoreCallerIVars(); + def restoreReconstructIVars(); + def restoreFastIVars(); def computePc(delta: int); // Emit code to materialize stack frames for each inlined function. def emitReconstructStackFrames(frames: Array) -> int { @@ -2330,9 +2330,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl emit(); return; } - if (fast) { - saveReconstructCallerIVars(); - } + if (fast) saveReconstructIVars(); frames_reconstructed = true; def space = emitReconstructStackFrames(snapshotFrames()); emit(); @@ -2343,8 +2341,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot.plus(space - frame.frameSize - 8)); masm.emit_addw_r_i(regs.sp, space); - restoreCallerIVars(); - restoreDispatchTableReg(); + restoreReconstructIVars(); } else { masm.emit_addw_r_i(regs.sp, space); masm.emit_mov_r_m(ValueKind.REF, regs.vfp, frame.vfp_slot); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index bc27eedc9..27e00201f 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -86,7 +86,6 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { mmasm.trap_stubs = TRAPS_STUB; } def emitFastDispatch() { - asm.movq_r_m(r_ip, m_ip); mmasm.emit_int_dispatch(r_tmp0, r_tmp1, r_ip, r_dispatch, ip_ptr, if(ic != null, IcCodeRef.new(ic.header.fastDispatchTableOffset)), true, ic); } @@ -95,13 +94,14 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { if (t.0 == r) asm.movq_m_r(t.1, r); } } - def saveCallerIVars() { + def saveFastIVars() { saveIVar(r_ip); if (!FeatureDisable.stacktraces) saveIVar(r_curpc); - } - def saveReconstructCallerIVars() { saveIVar(r_stp); } + def saveReconstructIVars() { + // nothing + } def restoreDispatchTableReg() { if (!FeatureDisable.globalProbes) { // restore dispatch table from Interpreter.dispatchTable @@ -114,14 +114,18 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { if (t.0 == r) asm.movq_r_m(r, t.1); } } - def restoreCallerIVars() { + def restoreReconstructIVars() { + restoreReg(r_instance); + restoreReg(r_mem0_base); + } + def restoreFastIVars() { + restoreReg(r_vfp); restoreReg(r_stp); restoreReg(r_ip); restoreReg(r_eip); restoreReg(r_func_decl); - restoreReg(r_instance); - restoreReg(r_mem0_base); restoreReg(r_curpc); + restoreDispatchTableReg(); } def computePc(delta: int) { def offsets = masm.getOffsets(); From 6648726d954a15b06c25b57f4de33be721abe7b5 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 29 Apr 2026 12:00:10 -0400 Subject: [PATCH 76/91] Fast compile modules on JIT compiler tiers --- src/engine/x86-64/X86_64Target.v3 | 56 +++++++++++++++++-------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 180187101..29447941d 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -258,30 +258,6 @@ class X86_64ExecutionStrategy extends ExecutionStrategy { } allocateCodeForModule(module, codeSize); } -} - -// One tier: fast-int, modules require no pre-processing. -class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { - def call(func: Function, args: Range) -> Result { - return X86_64StackManager.runOnFreshStack(func, args); - } - - def onModuleFinish(module: Module, size: u32, err: ErrorGen) { - disableLazyNameDecodingDuringGC(module); - if (FastIntTuning.useFastFunctions) fastCompileEntireModule(module, size, false, err, 1024); - } - def onFuncValidationFinish(module: Module, func: FuncDecl, err: ErrorGen) { - if (err != null && !err.ok()) return; - Target.setUnconditionalInterpreterEntryIfMultiTier(func); - } - def onNewFunction(wf: WasmFunction, err: ErrorGen) { - Target.setUnconditionalInterpreterEntryIfMultiTier(wf.decl); - } - - def onFuncProbeInsert1(module: Module, func: FuncDecl, offset: int, p: Probe) { - if (FastIntTuning.enableWhammProbeTrampoline && WhammProbe.?(p)) - X86_64WhammTrampoline.makeTrampoline(WhammProbe.!(p), X86_64PreGenStubs.getInterpreterCode()); - } def fastCompileEntireModule(module: Module, size: u32, interpreter_fallback: bool, err: ErrorGen, ballast: u32) { // ensure entrypoint and lazy compile stubs are generated @@ -359,6 +335,30 @@ class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { } } +// One tier: fast-int, modules require no pre-processing. +class X86_64InterpreterOnlyStrategy extends X86_64ExecutionStrategy { + def call(func: Function, args: Range) -> Result { + return X86_64StackManager.runOnFreshStack(func, args); + } + + def onModuleFinish(module: Module, size: u32, err: ErrorGen) { + disableLazyNameDecodingDuringGC(module); + if (FastIntTuning.useFastFunctions) fastCompileEntireModule(module, size, false, err, 1024); + } + def onFuncValidationFinish(module: Module, func: FuncDecl, err: ErrorGen) { + if (err != null && !err.ok()) return; + Target.setUnconditionalInterpreterEntryIfMultiTier(func); + } + def onNewFunction(wf: WasmFunction, err: ErrorGen) { + Target.setUnconditionalInterpreterEntryIfMultiTier(wf.decl); + } + + def onFuncProbeInsert1(module: Module, func: FuncDecl, offset: int, p: Probe) { + if (FastIntTuning.enableWhammProbeTrampoline && WhammProbe.?(p)) + X86_64WhammTrampoline.makeTrampoline(WhammProbe.!(p), X86_64PreGenStubs.getInterpreterCode()); + } +} + // Base class of all strategies that use SPC. class X86_64SpcStrategy extends X86_64ExecutionStrategy { def onFuncProbeInsert1(module: Module, func: FuncDecl, offset: int, p: Probe) { @@ -422,11 +422,15 @@ class X86_64SpcAotStrategy(interpreter_fallback: bool) extends X86_64SpcStrategy // Called after a module is parsed. def onModuleFinish(module: Module, size: u32, err: ErrorGen) { // defer compilation for AOT mode until after monitors have been installed - if (!hasMonitors) compileEntireModule(module, size, interpreter_fallback, err, 1024); + if (!hasMonitors) { + if (FastIntTuning.useFastFunctions) fastCompileEntireModule(module, size, true, err, 1024); + compileEntireModule(module, size, interpreter_fallback, err, 1024); + } disableLazyNameDecodingDuringGC(module); } // Called after monitors have processed a module. def onMonitorsFinish(module: Module, err: ErrorGen) { + if (FastIntTuning.useFastFunctions) fastCompileEntireModule(module, 0, true, err, 1024); compileEntireModule(module, 0, interpreter_fallback, err, 1024); } // Called before a test function is run. @@ -501,6 +505,7 @@ class X86_64SpcAotStrategy(interpreter_fallback: bool) extends X86_64SpcStrategy class X86_64SpcLazyStrategy extends X86_64SpcStrategy { // Called after a module is parsed. def onModuleFinish(module: Module, size: u32, err: ErrorGen) { + if (FastIntTuning.useFastFunctions) fastCompileEntireModule(module, size, true, err, 1024); installStubForModule(module, X86_64Spc.setLazyCompileFor); disableLazyNameDecodingDuringGC(module); } @@ -516,6 +521,7 @@ class X86_64SpcLazyStrategy extends X86_64SpcStrategy { class X86_64DynamicStrategy extends X86_64SpcStrategy { // Called after a module is parsed. def onModuleFinish(module: Module, size: u32, err: ErrorGen) { + if (FastIntTuning.useFastFunctions) fastCompileEntireModule(module, size, true, err, 1024); installStubForModule(module, X86_64Spc.setTierUpFor); disableLazyNameDecodingDuringGC(module); if (Debug.runtime) { From 21f268a50a91b0d6c977aa84ff25914c31924ba7 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 29 Apr 2026 12:03:01 -0400 Subject: [PATCH 77/91] Do not inline non-fast functions when fast handlers are in use --- src/engine/compiler/SinglePassCompiler.v3 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 6c1892ef2..707081051 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -2836,6 +2836,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def shouldInline(func: FuncDecl) -> bool { if (Trace.compiler) OUT.put1("deciding on inlining call to func #%d: ", func.func_index); + if (FastIntTuning.useFastFunctions && !fast) return no("fast functions enabled and this is not a fast function"); if (func.imp != null) return no("imported"); if (inlineDepth() >= SpcTuning.maxInlineDepth) return no("max inline depth exceeded"); if (func.orig_bytecode.length > SpcTuning.maxInlineBytecodeSize) return no("func too large"); From 1c54b7294a48ccfe08336cb7362f6c674fed1c6e Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 29 Apr 2026 15:33:55 -0400 Subject: [PATCH 78/91] Add (fast) to fast-compiled compiler traces --- src/engine/compiler/SinglePassCompiler.v3 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 707081051..a57bef5fb 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -144,7 +144,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl return if(ok, osr_entry_label); } private def gen0(module: Module, func: FuncDecl) -> bool { - if (Trace.compiler) OUT.put1("==== begin compile: %q ========================", func.render(module.names, _)).ln(); + if (Trace.compiler) + OUT.put2("==== begin compile: %q %s==================", func.render(module.names, _), if(fast, "(fast)", "======")).ln(); var before_code_bytes = masm.curCodeBytes(); var before_data_bytes = masm.curDataBytes(); From e7c9a79927ccc45327db154ec741cb72f1e0fbc5 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 3 Jun 2026 11:42:42 -0400 Subject: [PATCH 79/91] Add tests that use new_func --- .../test72_new_func_dispatch_clobber.wasm | Bin 0 -> 227 bytes ...test72_new_func_dispatch_clobber.wasm.exit | 1 + ...est72_new_func_dispatch_clobber.wasm.flags | 1 + .../test72_new_func_dispatch_clobber.wat | 55 ++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 test/fastcall/test72_new_func_dispatch_clobber.wasm create mode 100644 test/fastcall/test72_new_func_dispatch_clobber.wasm.exit create mode 100644 test/fastcall/test72_new_func_dispatch_clobber.wasm.flags create mode 100644 test/fastcall/test72_new_func_dispatch_clobber.wat diff --git a/test/fastcall/test72_new_func_dispatch_clobber.wasm b/test/fastcall/test72_new_func_dispatch_clobber.wasm new file mode 100644 index 0000000000000000000000000000000000000000..5a74b21a227c7e899dced3809f9d64f58e4c3e4c GIT binary patch literal 227 zcmX}lu@1s838C`nh$~l%PSEE8o P?yQ|Looy*?Oda+IFB>Vr literal 0 HcmV?d00001 diff --git a/test/fastcall/test72_new_func_dispatch_clobber.wasm.exit b/test/fastcall/test72_new_func_dispatch_clobber.wasm.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/fastcall/test72_new_func_dispatch_clobber.wasm.exit @@ -0,0 +1 @@ +0 diff --git a/test/fastcall/test72_new_func_dispatch_clobber.wasm.flags b/test/fastcall/test72_new_func_dispatch_clobber.wasm.flags new file mode 100644 index 000000000..da6241c2d --- /dev/null +++ b/test/fastcall/test72_new_func_dispatch_clobber.wasm.flags @@ -0,0 +1 @@ +--fast-functions=true diff --git a/test/fastcall/test72_new_func_dispatch_clobber.wat b/test/fastcall/test72_new_func_dispatch_clobber.wat new file mode 100644 index 000000000..7c2ef5454 --- /dev/null +++ b/test/fastcall/test72_new_func_dispatch_clobber.wat @@ -0,0 +1,55 @@ +;; Func layout: 0=new_func, 1=fast:worker, 2=heavy, 3=main +;; +;; Dynamic body (type $t_i_i = i32->i32): +;; \00 = 0 local decls +;; \20\00 = local.get 0 +;; \10\01 = call 1 (fast:worker) +;; \41\01 = i32.const 1 +;; \6A = i32.add +;; \0B = end +;; total = 9 bytes +(module + (type $t_i_i (func (param i32) (result i32))) + + (import "wave" "new_func" (func $new_func (param i32 i32 i32) (result i32))) + + (func $worker (export "fast:worker") (param $x i32) (result i32) + local.get $x + call $heavy) + + (func $heavy (param $x i32) (result i32) + local.get $x i32.const 0 i32.add + local.get $x i32.const 1 i32.add + local.get $x i32.const 2 i32.add + local.get $x i32.const 3 i32.add + local.get $x i32.const 4 i32.add + local.get $x i32.const 5 i32.add + local.get $x i32.const 6 i32.add + local.get $x i32.const 7 i32.add + local.get $x i32.const 8 i32.add + local.get $x i32.const 9 i32.add + i32.add i32.add i32.add i32.add i32.add + i32.add i32.add i32.add i32.add ;; sum = 10x+45 + i32.const 45 + i32.sub ;; 10x + i32.const 9 local.get $x i32.mul + i32.sub) ;; x + + (memory (export "memory") 1) + ;; body: \00 \20\00 \10\01 \41\01 \6A \0B = 9 bytes + (data (i32.const 0) "\00\20\00\10\01\41\01\6A\0B") + + (table (export "table") 0 funcref) + + (func (export "main") (result i32) + (local $slot i32) + ;; create dynamic func: sig=0, ptr=0, len=9 + (call $new_func (i32.const 0) (i32.const 0) (i32.const 9)) + local.set $slot + ;; dynfunc(5) -> fast:worker(5) -> heavy(5) = 5, then +1 = 6 + i32.const 5 + local.get $slot + (call_indirect (type $t_i_i)) + i32.const 6 + i32.ne) +) From 8f1403bf374e9d30d4e22272944f0a93d9d65cd7 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Thu, 4 Jun 2026 11:30:43 -0400 Subject: [PATCH 80/91] Don't restore instance and mem0base after stack reconstruction --- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 27e00201f..9c21196bf 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -115,8 +115,8 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { } } def restoreReconstructIVars() { - restoreReg(r_instance); - restoreReg(r_mem0_base); + //restoreReg(r_instance); + //restoreReg(r_mem0_base); } def restoreFastIVars() { restoreReg(r_vfp); From 3bf3afe4834f790a4874a3c0ac1eef87e2f3dd33 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 15 Jun 2026 11:42:43 -0400 Subject: [PATCH 81/91] Change registers to only be restored if there is an outcall --- src/engine/compiler/SinglePassCompiler.v3 | 6 ++++-- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index a57bef5fb..aa97ef069 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -119,6 +119,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl var whamm_config: WhammInlineConfig; var frames_reconstructed = false; var fast_operand_size: int; + var fast_has_outcall = false; // XXX: hack var handler_dest_info = Vector.new(); @@ -963,6 +964,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl popSpcFrame(); } def emitCallToReg(sig: SigDecl, func_reg: Reg, vsp_reg: Reg, tmp: Reg, checkHostCall: bool, tailCall: bool) { + if (fast) fast_has_outcall = true; var retpt = masm.newLabel(it.pc), wasmcall_label = masm.newLabel(it.pc); // Handle the current stack state. if (tailCall) emitMoveTailCallArgs(sig); // transfer tail call args @@ -2173,7 +2175,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl masm.emit_addw_r_i(regs.sp, frame.frameSize); masm.emit_ret(); } else { - restoreFastIVars(); + restoreFastIVars(fast_has_outcall); emitFastDispatch(); } } @@ -2211,7 +2213,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def saveReconstructIVars(); def restoreDispatchTableReg(); def restoreReconstructIVars(); - def restoreFastIVars(); + def restoreFastIVars(has_outcall: bool); def computePc(delta: int); // Emit code to materialize stack frames for each inlined function. def emitReconstructStackFrames(frames: Array) -> int { diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 9c21196bf..6e9bd5a09 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -118,14 +118,16 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { //restoreReg(r_instance); //restoreReg(r_mem0_base); } - def restoreFastIVars() { + def restoreFastIVars(has_outcall: bool) { restoreReg(r_vfp); restoreReg(r_stp); restoreReg(r_ip); - restoreReg(r_eip); - restoreReg(r_func_decl); + if (has_outcall) { + restoreReg(r_eip); + restoreReg(r_func_decl); + restoreDispatchTableReg(); + } restoreReg(r_curpc); - restoreDispatchTableReg(); } def computePc(delta: int) { def offsets = masm.getOffsets(); From 637d2c5c5aaa359d2a7609c02a2258e318356a5d Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 17 Jun 2026 12:58:21 -0400 Subject: [PATCH 82/91] Move restoreDispatchTableReg and computePc to MacroAssembler --- src/engine/compiler/MacroAssembler.v3 | 1 + src/engine/compiler/SinglePassCompiler.v3 | 4 +-- src/engine/x86-64/X86_64Interpreter.v3 | 36 +++++++------------ src/engine/x86-64/X86_64MacroAssembler.v3 | 12 +++++-- src/engine/x86-64/X86_64SinglePassCompiler.v3 | 15 +------- 5 files changed, 25 insertions(+), 43 deletions(-) diff --git a/src/engine/compiler/MacroAssembler.v3 b/src/engine/compiler/MacroAssembler.v3 index 326da728f..7e9ee6aac 100644 --- a/src/engine/compiler/MacroAssembler.v3 +++ b/src/engine/compiler/MacroAssembler.v3 @@ -315,6 +315,7 @@ class MacroAssembler(valuerep: Tagging, regConfig: RegConfig) { def emit_save_ivar(reg: Reg); def emit_spill_ivar(reg: Reg); def emit_restore_ivar(reg: Reg); + def emit_compute_pc(delta: int); def emit_pop_r(kind: ValueKind, reg: Reg); def emit_ret(); diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index aa97ef069..8a467bda1 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -401,7 +401,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl // Advance IP past the fast-call opcode and spill it def r_ip = X86_64MasmRegs.INT_EXEC_ENV.ip; masm.emit_addw_r_i(r_ip, fast_operand_size); // increment ip - computePc(-(fast_operand_size + 1)); // compute r_curpc + masm.emit_compute_pc(-(fast_operand_size + 1)); // compute r_curpc saveFastIVars(); // Why do we have to compute and save? // 1. r_ip = rax (clobbered by HW `div`) |\ can validation catch this? @@ -2211,10 +2211,8 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def getSpcInlinedFrameIp() -> long; def saveFastIVars(); def saveReconstructIVars(); - def restoreDispatchTableReg(); def restoreReconstructIVars(); def restoreFastIVars(has_outcall: bool); - def computePc(delta: int); // Emit code to materialize stack frames for each inlined function. def emitReconstructStackFrames(frames: Array) -> int { unrefRegs(); diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index 5f4a6205c..24adc85e4 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -530,7 +530,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { // Spill VSP (value stack pointer) asm.movq_m_r(m_vsp, r_v3_vsp); // load dispatch table into register - if (!FeatureDisable.globalProbes) masm.emit_load_dispatch_table_reg(xenv.dispatch); + masm.emit_load_dispatch_table_reg(); // move WasmFunction into tmp asm.movq_r_r(tmp, r_v3_wasm_func); masm.emit_restore_ivar(xenv.vsp); @@ -547,7 +547,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { // Spill VSP (value stack pointer) asm.movq_m_r(m_vsp, r_vsp); // load dispatch table into register - if (!FeatureDisable.globalProbes) masm.emit_load_dispatch_table_reg(xenv.dispatch); + masm.emit_load_dispatch_table_reg(); // move WasmFunction into tmp asm.movq_r_r(tmp, r_func_arg); asm.jmp_rel_near(shared_entry); @@ -561,7 +561,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { masm.emit_v3_X86_64Stack_rsp_r_r(xenv.sp, xenv.scratch); // Restore interpreter registers restoreCallerIVars(); - restoreDispatchTableReg(); + masm.emit_load_dispatch_table_reg(); // Continue to dispatch table endHandler(); } @@ -736,7 +736,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { ic.header.deoptReentryOffset = w.atEnd().pos; restoreCallerIVars(); masm.emit_restore_ivar(xenv.vsp); - restoreDispatchTableReg(); + masm.emit_load_dispatch_table_reg(); genJumpToDispatch(); genDeferred(); } @@ -1232,7 +1232,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { endHandler(); // TierUp triggered; call runtime asm.bind(tierup); - computePc(-1); + masm.emit_compute_pc(-1); masm.emit_get_curstack(xenv.tmp3); saveCallerIVars(); asm.movq_r_m(r_tmp1, m_wasm_func); @@ -1335,14 +1335,14 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { asm.call_rel_far(callReentryLabel); } restoreCallerIVars(); - if (!FeatureDisable.multiTier && !SpcTuning.disable) restoreDispatchTableReg(); + if (!FeatureDisable.multiTier && !SpcTuning.disable) masm.emit_load_dispatch_table_reg(); genDispatchOrJumpToDispatch(); // HostFunction: call into runtime asm.bind(call_host.label); asm.call_rel_far(hostCallStubLabel.label); restoreCallerIVars(); - restoreDispatchTableReg(); + masm.emit_load_dispatch_table_reg(); genJumpToDispatch(); } @@ -2612,7 +2612,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { restoreCallerIVars(); // skip pass {suspend} instruction after restoring pc genSkipLeb(); - restoreDispatchTableReg(); + masm.emit_load_dispatch_table_reg(); endHandler(); asm.bind(stub_suspend); { @@ -2646,7 +2646,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { restoreCallerIVars(); genSkipLeb(); genSkipLeb(); - restoreDispatchTableReg(); + masm.emit_load_dispatch_table_reg(); endHandler(); asm.bind(switchStub); { @@ -2654,7 +2654,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { masm.emit_v3_X86_64Stack_rsp_r_r(xenv.sp, xenv.scratch); masm.emit_v3_X86_64Stack_vsp_r_r(xenv.vsp, xenv.scratch); restoreCallerIVars(); - restoreDispatchTableReg(); + masm.emit_load_dispatch_table_reg(); masm.emit_pop_r(ValueKind.REF, xenv.scratch); masm.emit_jump_r(xenv.scratch); } @@ -2713,7 +2713,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { } restoreCallerIVars(); - restoreDispatchTableReg(); + masm.emit_load_dispatch_table_reg(); // Compute a pointer to the original code at this pc offset. var pc = r_tmp1; // = IP - CODE asm.movq_r_r(pc, r_ip); @@ -3682,12 +3682,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { masm.emit_restore_ivar(xenv.mem0_base); masm.emit_restore_ivar(xenv.vfp); } - def restoreDispatchTableReg() { - if (!FeatureDisable.globalProbes) { - // restore dispatch table from Interpreter.dispatchTable - asm.movq_r_m(r_dispatch, masm.absPointer(offsets.Interpreter_dispatchTable)); - } - } def callRuntime(abs: Pointer, args: Array, canTrap: bool) { masm.emit_save_ivar(xenv.vsp); // save a copy of VSP into valueStack.sp @@ -3706,7 +3700,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { for (i < dst.length) orderMoves(dst, stk, i); // emit actual call asm.callr(int.!((abs - (ic.start + w.pos + 5)))); // TODO: handle 64-bit {abs} with movq_r_l - restoreDispatchTableReg(); + masm.emit_load_dispatch_table_reg(); // restore VSP from valueStack.sp masm.emit_get_curstack(xenv.vsp); masm.emit_v3_X86_64Stack_vsp_r_r(xenv.vsp, xenv.vsp); @@ -4163,10 +4157,6 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { def computePcFromCurIp() { if (!FeatureDisable.stacktraces) asm.q.sub_r_m(r_curpc, m_code); } - def computePc(delta: int) { - asm.q.lea(r_curpc, X86_64Addr.new(r_ip, null, 1, delta - offsets.Array_contents)); - asm.q.sub_r_m(r_curpc, m_code); - } // All traps are generated out-of-line and call into the runtime. def genTraps() { w.atEnd(); @@ -4271,7 +4261,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { private def genOnResumeFinish(skip_tag: bool) { restoreCurPcFromFrame(); restoreCallerIVars(); - restoreDispatchTableReg(); + masm.emit_load_dispatch_table_reg(); var r_stack = r_tmp1; // load %stack masm.emit_get_curstack(xenv.tmp1); diff --git a/src/engine/x86-64/X86_64MacroAssembler.v3 b/src/engine/x86-64/X86_64MacroAssembler.v3 index 73629923d..9d5aaebb5 100644 --- a/src/engine/x86-64/X86_64MacroAssembler.v3 +++ b/src/engine/x86-64/X86_64MacroAssembler.v3 @@ -995,9 +995,9 @@ class X86_64MacroAssembler extends MacroAssembler { def emit_restore_ivar(reg: Reg) { for (t in INT_EXEC_ENV.all_ivars) if (t.0 == reg) { asm.movq_r_m(G(reg), R.RSP.plus(t.1)); return; } } - def emit_load_dispatch_table_reg(reg: Reg) { - var offsets = getOffsets(); - asm.movq_r_m(G(reg), absPointer(offsets.Interpreter_dispatchTable)); + def emit_load_dispatch_table_reg() { + if (FeatureDisable.globalProbes) return; + asm.movq_r_m(G(INT_EXEC_ENV.dispatch), absPointer(getOffsets().Interpreter_dispatchTable)); } def emit_i32_clz_r_r(r: X86_64Gpr, s: X86_64Gpr) { asm.movd_r_i(scratch, -1); @@ -1604,6 +1604,12 @@ class X86_64MacroAssembler extends MacroAssembler { asm.pextrq_r_s_i(G(to), X(from), 1); } + def emit_compute_pc(delta: int) { + def r_ip = G(INT_EXEC_ENV.ip), r_curpc = G(INT_EXEC_ENV.curpc); + def m_code = R.RSP.plus(X86_64InterpreterFrame.code.offset); + asm.q.lea(r_curpc, X86_64Addr.new(r_ip, null, 1, delta - getOffsets().Array_contents)); + asm.q.sub_r_m(r_curpc, m_code); + } def emit_int_dispatch(opcode: X86_64Gpr, base: X86_64Gpr, r_ip: X86_64Gpr, r_dispatch: X86_64Gpr, ptr: X86_64Addr, table: IcCodeRef, increment: bool, ic: X86_64InterpreterCode) { if (ptr != null) asm.movbzx_r_m(opcode, ptr); diff --git a/src/engine/x86-64/X86_64SinglePassCompiler.v3 b/src/engine/x86-64/X86_64SinglePassCompiler.v3 index 6e9bd5a09..c85b28a92 100644 --- a/src/engine/x86-64/X86_64SinglePassCompiler.v3 +++ b/src/engine/x86-64/X86_64SinglePassCompiler.v3 @@ -102,13 +102,6 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { def saveReconstructIVars() { // nothing } - def restoreDispatchTableReg() { - if (!FeatureDisable.globalProbes) { - // restore dispatch table from Interpreter.dispatchTable - def offsets = masm.getOffsets(); - asm.movq_r_m(r_dispatch, mmasm.absPointer(offsets.Interpreter_dispatchTable)); - } - } private def restoreReg(r: X86_64Gpr) { for (t in all_ivars) { if (t.0 == r) asm.movq_r_m(r, t.1); @@ -125,16 +118,10 @@ class X86_64SinglePassCompiler extends SinglePassCompiler { if (has_outcall) { restoreReg(r_eip); restoreReg(r_func_decl); - restoreDispatchTableReg(); + mmasm.emit_load_dispatch_table_reg(); } restoreReg(r_curpc); } - def computePc(delta: int) { - def offsets = masm.getOffsets(); - asm.q.lea(r_curpc, X86_64Addr.new(r_ip, null, 1, delta - offsets.Array_contents)); - asm.q.sub_r_m(r_curpc, m_code); - } - private def visitCompareI(asm: X86_64Assembler, cond: X86_64Cond) -> bool { var b = pop(), a = popReg(); if (b.isConst()) asm.cmp_r_i(G(a.reg), b.const); From 3171e2d52b6d7b2f893e5ee77287d401672f9e1e Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 22 Jun 2026 12:58:16 -0400 Subject: [PATCH 83/91] Update comments --- src/engine/compiler/SinglePassCompiler.v3 | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 8a467bda1..4c953656e 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -400,12 +400,12 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } // Advance IP past the fast-call opcode and spill it def r_ip = X86_64MasmRegs.INT_EXEC_ENV.ip; - masm.emit_addw_r_i(r_ip, fast_operand_size); // increment ip - masm.emit_compute_pc(-(fast_operand_size + 1)); // compute r_curpc + masm.emit_addw_r_i(r_ip, fast_operand_size); // increment ip + masm.emit_compute_pc(-(fast_operand_size + 1)); // compute r_curpc saveFastIVars(); // Why do we have to compute and save? - // 1. r_ip = rax (clobbered by HW `div`) |\ can validation catch this? - // 2. m_curpc = HW trap reads this |/ or hidden by arbitrary outcalls? + // 1. r_ip = rax (clobbered by HW `div`) + // 2. m_curpc = HW trap reads this // Compute VFP = VSP - sig.params.length * SLOT_SIZE masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); // XXX: use 3-addr adjustment of VFP @@ -1017,7 +1017,6 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, tailCall: bool) { var sig = SigDecl.!(module.heaptypes[sig_index]); - if (fast) state.emitSaveAll(resolver, SpillMode.SAVE_AND_FREE_REGS); withReconstructedInlinedFrames(fun { var vsp_reg = allocTmpFixed(ValueKind.REF, regs.vsp); var sv = popFixedReg(regs.func_arg); @@ -2788,7 +2787,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } state.frame_stack.push(frame); // Update cached copies from new top frame - if (frame.func != null) it.reset(frame.func).at(frame.pc, -1); // null = func in int + if (frame.func != null) it.reset(frame.func).at(frame.pc, -1); // null = fast: interpreted caller module = frame.module; func = frame.func; sig = if(func != null, func.sig); From 1f65ca514b19af0b2b5883498381a04af130682b Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 22 Jun 2026 12:59:25 -0400 Subject: [PATCH 84/91] Restore save of registers --- src/engine/compiler/SinglePassCompiler.v3 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 4c953656e..c3de3c09d 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -1017,6 +1017,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl } def visitCallIndirect(op: Opcode, sig_index: u31, table_index: u31, tailCall: bool) { var sig = SigDecl.!(module.heaptypes[sig_index]); + if (fast) state.emitSaveAll(resolver, SpillMode.SAVE_AND_FREE_REGS); withReconstructedInlinedFrames(fun { var vsp_reg = allocTmpFixed(ValueKind.REF, regs.vsp); var sv = popFixedReg(regs.func_arg); From 7b56a20212f8da2889682ec023729cc8e9213ab0 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 22 Jun 2026 13:03:10 -0400 Subject: [PATCH 85/91] Reset fast_has_outcall in gen0 --- src/engine/compiler/SinglePassCompiler.v3 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index c3de3c09d..69cbb01a8 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -154,6 +154,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl regAlloc.clear(); trap_labels.resize(0); success = true; + fast_has_outcall = false; osr_offset = -1; osr_state = null; handler_dest_info.clear(); From ab6ccbbba2b8eca369614ee9a42122ad959e2f4a Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 22 Jun 2026 13:03:32 -0400 Subject: [PATCH 86/91] Remove swp file --- src/monitors/.WhammMonitor.v3.swp | Bin 1024 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/monitors/.WhammMonitor.v3.swp diff --git a/src/monitors/.WhammMonitor.v3.swp b/src/monitors/.WhammMonitor.v3.swp deleted file mode 100644 index e88663d1be844a4a7ce71706a30dc406af157a18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1024 zcmYc?$V<%2S1{KzVn6|X2@DLmi6tc&spTl**f`~hrP-;)8Hw2Bkj26?5_5BX^Yb!G Y@{9D!jFF{A*`pya8UnNrflzcS0LqmRMF0Q* From ded4546c25dc14048e4ae1b4523c2caf64901105 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Fri, 3 Jul 2026 16:09:41 -0400 Subject: [PATCH 87/91] Clean up repo --- fast_call.wasm | Bin 68 -> 0 bytes fast_call.wat | 10 ---------- fast_call2.wasm | Bin 43 -> 0 bytes fast_call2.wat | 7 ------- fast_call_export.wasm | Bin 54 -> 0 bytes fast_call_export.wat | 10 ---------- fast_call_nop.wasm | Bin 53 -> 0 bytes fast_call_nop.wat | 10 ---------- fast_call_param.wasm | Bin 91 -> 0 bytes fast_call_param.wat | 18 ------------------ slow_call.wasm | Bin 68 -> 0 bytes slow_call_nop.wasm | Bin 46 -> 0 bytes slow_call_nop.wat | 7 ------- src/engine/compiler/MacroAssembler.v3 | 2 -- src/engine/compiler/SinglePassCompiler.v3 | 2 +- src/engine/x86-64/X86_64MacroAssembler.v3 | 2 +- src/engine/x86-64/X86_64PreGenStubs.v3 | 2 +- 17 files changed, 3 insertions(+), 67 deletions(-) delete mode 100644 fast_call.wasm delete mode 100644 fast_call.wat delete mode 100644 fast_call2.wasm delete mode 100644 fast_call2.wat delete mode 100644 fast_call_export.wasm delete mode 100644 fast_call_export.wat delete mode 100644 fast_call_nop.wasm delete mode 100644 fast_call_nop.wat delete mode 100644 fast_call_param.wasm delete mode 100644 fast_call_param.wat delete mode 100644 slow_call.wasm delete mode 100644 slow_call_nop.wasm delete mode 100644 slow_call_nop.wat diff --git a/fast_call.wasm b/fast_call.wasm deleted file mode 100644 index 36f858295824074b732c768e522caf4cc349e47b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmV~$F%Ezr5Cp*8CsVqjqBU}VWn%*L#;06G4wFH9z diff --git a/fast_call2.wat b/fast_call2.wat deleted file mode 100644 index 3dd58686b..000000000 --- a/fast_call2.wat +++ /dev/null @@ -1,7 +0,0 @@ -(module - (func $f (result i32) - i32.const 10) - (func (export "main") (result i32) - call $f - ) -) diff --git a/fast_call_export.wasm b/fast_call_export.wasm deleted file mode 100644 index de5abe4d8a74f8a24c8d888a332931be286cbba9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54 zcmZQbEY4+QU|?WmWlUgTtY>CsVqjnwX5vUoEH1H1%g<+EV98C)%wu5W;$~uDaAe|U JVGv;81_0r`2ebeH diff --git a/fast_call_export.wat b/fast_call_export.wat deleted file mode 100644 index 20c428045..000000000 --- a/fast_call_export.wat +++ /dev/null @@ -1,10 +0,0 @@ -;; export name holds fast information, we don't modify binary ahead of time - -(module - (func $fast (export "fast:foo") (result i32) - (i32.const 2) - ) - (func (export "main") (result i32) - (call $fast) - ) -) diff --git a/fast_call_nop.wasm b/fast_call_nop.wasm deleted file mode 100644 index 403dc7cf1dac9ad70c13cfaf0ac80a170e8d6a3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53 zcmZQbEY4+QU|?Y6U`k+MNMK;BXJ%mra@jc;S#lFI^B9=81euu_xPge1!HHW+oY9ei F8vvyN1z-RG diff --git a/fast_call_nop.wat b/fast_call_nop.wat deleted file mode 100644 index c406ac91a..000000000 --- a/fast_call_nop.wat +++ /dev/null @@ -1,10 +0,0 @@ -(module - (func $f) - (func $g) - (func (export "main") (result i32) - i64.const 11 - drop - call $g - i32.const 0 - ) -) diff --git a/fast_call_param.wasm b/fast_call_param.wasm deleted file mode 100644 index c70071c25eaade813ac8547a90cd3b2846efe266..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91 zcmZQbEY4+QU|?Y6V@_bKX8>Zx`UD2XdM18Gw(`uX)Vy?-g3^*q1_owkCPpT94n~&T n#LPSfCN4!LJ_ZE_mU_qM?5vI}>bSWD7#tbJ8G$4NgyaSQ2wV?q diff --git a/fast_call_param.wat b/fast_call_param.wat deleted file mode 100644 index b3f4ad728..000000000 --- a/fast_call_param.wat +++ /dev/null @@ -1,18 +0,0 @@ -(module - (import "wizeng" "puti" (func $puti (param i32))) - (func $f (param i32) (result i32) - local.get 0 - if (result i32) - i32.const 999 - else - i32.const -216 - end - ) - (func (export "main") (result i32) - (call $f (i32.const 1)) - call $puti - (call $f (i32.const 0)) - call $puti - i32.const 0 - ) -) diff --git a/slow_call.wasm b/slow_call.wasm deleted file mode 100644 index 8d09b720e6f90786cc1181c7b66a5a752a1782a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmV~$K?;B%5Czcx$DvFYdL?h7i-=h$K}FEUtM?w-)d_%`R8CZIO5*a`w~s^5=QhAO UAy-fB%?2bSQIrrpGBXO|50y3wFaQ7m diff --git a/slow_call_nop.wasm b/slow_call_nop.wasm deleted file mode 100644 index 2af221a3849d934689386000c1a05e6771d57181..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46 zcmV~$u@L|e5JkcFkHNS^OFAJGkSIXwcA0kzP_Y36y$}rLqPXWesJa=RXmtDog7yU0 diff --git a/slow_call_nop.wat b/slow_call_nop.wat deleted file mode 100644 index 0533b6638..000000000 --- a/slow_call_nop.wat +++ /dev/null @@ -1,7 +0,0 @@ -(module - (func $f) - (func (export "main") (result i32) - call $f - i32.const 0 - ) -) diff --git a/src/engine/compiler/MacroAssembler.v3 b/src/engine/compiler/MacroAssembler.v3 index 7e9ee6aac..2258ac7ba 100644 --- a/src/engine/compiler/MacroAssembler.v3 +++ b/src/engine/compiler/MacroAssembler.v3 @@ -373,8 +373,6 @@ class MacroAssembler(valuerep: Tagging, regConfig: RegConfig) { // Destructive on {parent}. def emit_cont_mv(from_vsp: Reg, contStack: Reg, n_vals: Reg, tmp1: Reg, tmp2: Reg, xmm0: Reg); - def emit_dispatchSequence(); - // Validates {cont} and: // - Mark {cont} as used // - Move {cont.stack} to {destContStack} diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 69cbb01a8..22ba607ce 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -78,7 +78,6 @@ def KIND_REF = SpcConsts.KIND_REF; def KIND_REF_U64 = SpcConsts.KIND_REF_U64; def KIND_CONT = SpcConsts.KIND_CONT; - // Compiles Wasm bytecode to machine code in a single pass via a MacroAssembler. class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAlloc, extensions: Extension.set, limits: Limits, fast: bool) extends BytecodeVisitor { def instrTracer = if(Trace.compiler, InstrTracer.new()); @@ -375,6 +374,7 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl if (SpcTuning.inlineWhammProbes && SpcTuning.intrinsifyWhammProbe) { masm.emit_mov_m_l(frame.inlined_instance_slot, 0); } + // Compute VFP = VSP - sig.params.length * SLOT_SIZE masm.emit_mov_r_r(ValueKind.REF, regs.vfp, regs.vsp); // XXX: use 3-addr adjustment of VFP masm.emit_subw_r_i(regs.vfp, sig.params.length * masm.valuerep.slot_size); diff --git a/src/engine/x86-64/X86_64MacroAssembler.v3 b/src/engine/x86-64/X86_64MacroAssembler.v3 index 89a06c37d..ab92efaec 100644 --- a/src/engine/x86-64/X86_64MacroAssembler.v3 +++ b/src/engine/x86-64/X86_64MacroAssembler.v3 @@ -56,7 +56,7 @@ class X86_64MacroAssembler extends MacroAssembler { if (Trace.compiler) Trace.OUT.put2(" bind label (+%d) -> @%d", l.create_pos, w.end()).ln(); var label = X86_64MasmLabel.!(l); asm.bind(label.label); - + label.offset = label.label.pos; } def bindLabelTo(l: MasmLabel, offset: int) { if (Trace.compiler) Trace.OUT.put2(" bind label (+%d) -> @%d", l.create_pos, offset).ln(); diff --git a/src/engine/x86-64/X86_64PreGenStubs.v3 b/src/engine/x86-64/X86_64PreGenStubs.v3 index 79b3a3dc3..cbc467a29 100644 --- a/src/engine/x86-64/X86_64PreGenStubs.v3 +++ b/src/engine/x86-64/X86_64PreGenStubs.v3 @@ -25,7 +25,7 @@ layout X86_64PreGenHeader { +24 intV3EntryOffset: i32; // entry into interpreter from V3 caller +28 intSpcEntryOffset: i32; // entry into interpreter from SPC caller +32 intIntEntryOffset: i32; // entry into interpreter from interpreter caller - +36 intSuspendEntryOffset: i32; // entry into interpreter from a suspended child stack + +36 intSuspendEntryOffset: i32; // entry into interpreter from a suspended child stack +40 deoptReentryOffset: i32; // re-enter interpreter from optimized code +44 oobMemoryHandlerOffset: i32; // handler for signals caused by OOB memory access +48 divZeroHandlerOffset: i32; // handler for signals caused by divide by zero From 87fba3d0ad7a27305ff20cacf098d1d79b50b707 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Wed, 22 Jul 2026 01:26:36 -0400 Subject: [PATCH 88/91] Fail upon validating FAST_CALL instructions --- src/engine/CodeValidator.v3 | 40 ------------------------------------- 1 file changed, 40 deletions(-) diff --git a/src/engine/CodeValidator.v3 b/src/engine/CodeValidator.v3 index 44468bc09..286aba592 100644 --- a/src/engine/CodeValidator.v3 +++ b/src/engine/CodeValidator.v3 @@ -427,46 +427,6 @@ class CodeValidator(extensions: Extension.set, limits: Limits, module: Module, e this.func.replaceCall(opcode_pos, func.fast_call_idx); } } - FAST_CALL0 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL1 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL2 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL3 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL4 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL5 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL6 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL7 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL8 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL9 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL10 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL11 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL12 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL13 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL14 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL15 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL16 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL17 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL18 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL19 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL20 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL21 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL22 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL23 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL24 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL25 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL26 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL27 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL28 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL29 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL30 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL31 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL32 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL33 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL34 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL35 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL36 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL37 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL38 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); - FAST_CALL39 => if (FastIntTuning.useFastFunctions) System.error("validation error", "trying to validate FAST_CALL internal opcode"); CALL_INDIRECT => { var sig = parser.readSigRef(); var table = parser.readTableRef(); From 4c2953f34041384c6a8c10ef0815080f39ae55c8 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Fri, 24 Jul 2026 23:39:31 -0400 Subject: [PATCH 89/91] Only allow interpreter code region to be writable during module load (for fast function patching) --- src/engine/x86-64/X86_64PreGenStubs.v3 | 6 ++---- src/engine/x86-64/X86_64Target.v3 | 7 +++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/engine/x86-64/X86_64PreGenStubs.v3 b/src/engine/x86-64/X86_64PreGenStubs.v3 index cbc467a29..afe80d79f 100644 --- a/src/engine/x86-64/X86_64PreGenStubs.v3 +++ b/src/engine/x86-64/X86_64PreGenStubs.v3 @@ -222,10 +222,8 @@ component X86_64PreGenStubs { ic.header.probedDispatchTableOffset, ic.header.fastDispatchTableOffset); - var prot = Mmap.PROT_READ | Mmap.PROT_EXEC; - // Fast functions need the dispatch table writable to patch in the handler - if (FastIntTuning.useFastFunctions) prot |= Mmap.PROT_WRITE; - Mmap.protect(range.start + ic.header.codeStart, u64.!(ic.header.codeEnd - ic.header.codeStart), prot); + // Write-protect the executable code for security and debugging + Mmap.protect(range.start + ic.header.codeStart, u64.!(ic.header.codeEnd - ic.header.codeStart), Mmap.PROT_READ | Mmap.PROT_EXEC); // The host call stub is part of interpreter code (TODO: does it need to be?) hostCallStub.start = ic.start + ic.header.hostCallStubOffset; diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 29447941d..919d8602c 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -286,6 +286,11 @@ class X86_64ExecutionStrategy extends ExecutionStrategy { Target.copyInto(mapping.range, 0, w); // TODO: for security, move embedded references out of the code region and make it non-writable Mmap.protect(range.start, u64.!(range.end - range.start), Mmap.PROT_WRITE | Mmap.PROT_READ | Mmap.PROT_EXEC); + // Briefly relax the dispatch table to writable, then restore it below. + var ic = X86_64PreGenStubs.getInterpreterCode(); + var dispatchRegionSize = u64.!(ic.header.codeEnd - ic.header.codeStart); + Mmap.protect(ic.start + ic.header.codeStart, dispatchRegionSize, + Mmap.PROT_READ | Mmap.PROT_WRITE | Mmap.PROT_EXEC); for (i < bounds.length) { var b = bounds[i]; if (b.0 >= 0) { @@ -298,6 +303,8 @@ class X86_64ExecutionStrategy extends ExecutionStrategy { X86_64Spc.setInterpreterFallback(f); } } + Mmap.protect(ic.start + ic.header.codeStart, dispatchRegionSize, + Mmap.PROT_READ | Mmap.PROT_EXEC); // XXX: reduce duplication with {X86_64SpcModuleCode.appendCode}. var code = X86_64SpcModuleCode.new(mapping); if (masm.source_locs != null) { From 49f3c6e5ee1d0e716995c6f5dccbb02aca46b525 Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Mon, 27 Jul 2026 11:42:10 -0400 Subject: [PATCH 90/91] Throw error on duplicate fast exports, use interpreter fallback for compiler failure --- src/engine/BinParser.v3 | 7 ++++++- src/engine/x86-64/X86_64Target.v3 | 3 ++- src/util/ErrorGen.v3 | 5 +++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/engine/BinParser.v3 b/src/engine/BinParser.v3 index 672698898..08eadbc91 100644 --- a/src/engine/BinParser.v3 +++ b/src/engine/BinParser.v3 @@ -545,7 +545,12 @@ class BinParser(extensions: Extension.set, limits: Limits, err: ErrorGen, filena if (FastIntTuning.useFastFunctions && Strings.startsWith(name, "fast:") && FuncDecl.?(decl)) { def fdecl = FuncDecl.!(decl); def fast_funcs = module.fast_funcs; - if (fast_funcs.length < Opcodes.FAST_CALL_OPCODES) { + if (fdecl.fast_call_idx >= 0) { + err.rel(decoder, pt).DuplicateFastExport(fdecl.func_index); + } else if (fast_funcs.length >= Opcodes.FAST_CALL_OPCODES) { + // No fast-call slot available; fall back to a regular call for this function. + if (Trace.validation) Trace.OUT.put1(" dropping fast: export, no FAST_CALL slots remain (max %d)\n", Opcodes.FAST_CALL_OPCODES); + } else { fdecl.fast_call_idx = fast_funcs.length; fast_funcs.put(fdecl); } diff --git a/src/engine/x86-64/X86_64Target.v3 b/src/engine/x86-64/X86_64Target.v3 index 919d8602c..bc19ae0a1 100644 --- a/src/engine/x86-64/X86_64Target.v3 +++ b/src/engine/x86-64/X86_64Target.v3 @@ -300,7 +300,8 @@ class X86_64ExecutionStrategy extends ExecutionStrategy { } else { var f = module.functions[i]; if (Trace.compiler) Trace.OUT.put1("func[%d] initial compile failed", f.func_index).ln(); - X86_64Spc.setInterpreterFallback(f); + var addr = X86_64Spc.setInterpreterFallback(f); + Target.patchFastCallDispatch(f, addr); } } Mmap.protect(ic.start + ic.header.codeStart, dispatchRegionSize, diff --git a/src/util/ErrorGen.v3 b/src/util/ErrorGen.v3 index b1c2b7cba..87355ba27 100644 --- a/src/util/ErrorGen.v3 +++ b/src/util/ErrorGen.v3 @@ -178,6 +178,10 @@ class ErrorGen(filename: string) { setc(WasmError.DUPLICATE_EXPORT, Strings.format1("duplicate export %d", export_index)); } + def DuplicateFastExport(func_index: int) { + setc(WasmError.DUPLICATE_FAST_EXPORT, + Strings.format1("function %d already exported under a different fast: name", func_index)); + } // XXX: factor out commonality of zero-byte checks def ExpectedMemoryIndexZeroByte(memory_index: byte) { setc(WasmError.EXPECTED_ZERO_BYTE, @@ -632,6 +636,7 @@ enum WasmError { OUT_OF_ORDER_SECTION, DUPLICATE_SECTION, DUPLICATE_EXPORT, + DUPLICATE_FAST_EXPORT, EXCEEDED_LIMIT, OOB_INDEX, PARSE_ERROR, From 8a004547dee6d842aec0601f4be1a86ccab3d4cc Mon Sep 17 00:00:00 2001 From: Matthew Schneider Date: Tue, 28 Jul 2026 00:00:53 -0400 Subject: [PATCH 91/91] Separate regular function inlining from inlining in fast functions --- src/engine/Tuning.v3 | 3 ++- src/engine/compiler/CompilerOptions.v3 | 4 +++- src/engine/compiler/SinglePassCompiler.v3 | 4 ++-- test/fastcall/test21_inline_simple.wasm.flags | 2 +- test/fastcall/test22_inline_control.wasm.flags | 2 +- test/fastcall/test23_inline_with_locals.wasm.flags | 2 +- test/fastcall/test24_inline_depth2.wasm.flags | 2 +- test/fastcall/test25_outcall_depth0.wasm.flags | 2 +- test/fastcall/test26_outcall_depth1.wasm.flags | 2 +- test/fastcall/test27_outcall_stackframe.wasm.flags | 2 +- test/fastcall/test28_trap_mid_function.wasm.flags | 2 +- test/fastcall/test29_inline_then_outcall_trap.wasm.flags | 2 +- test/fastcall/test30_inline_depth2_outcall_trap.wasm.flags | 2 +- test/fastcall/test31_fast_below_spc_trap.wasm.flags | 2 +- test/fastcall/test32_inline_then_spc_trap.wasm.flags | 2 +- test/fastcall/test33_fast_self_trap.wasm.flags | 2 +- test/fastcall/test34_second_outcall_trap.wasm.flags | 2 +- test/fastcall/test41_inline_loop.wasm.flags | 2 +- test/fastcall/test42_inline_memory.wasm.flags | 2 +- test/fastcall/test43_inline_global.wasm.flags | 2 +- test/fastcall/test44_inline_depth3.wasm.flags | 2 +- test/fastcall/test48_large_inline.wasm.flags | 2 +- 22 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/engine/Tuning.v3 b/src/engine/Tuning.v3 index ca6200375..4ecd590e2 100644 --- a/src/engine/Tuning.v3 +++ b/src/engine/Tuning.v3 @@ -63,7 +63,8 @@ component SpcTuning { var inlineWhammProbes = true; // inline whamm probe functions var maxInlineBytecodeSize = 100; // max bytecode size to inline var maxInlineParams = 10; // max parameters to inline - var maxInlineDepth = 0; // max inlining nesting depth + var maxInlineDepth = 0; // max inlining nesting depth for regular (non-fast) functions + var maxFastInlineDepth = 0; // max inlining nesting depth for fast functions def probeCallFreesRegs = true; // probe calls frees registers in abstract state def runtimeCallFreesRegs = true; // runtime calls frees registers in abstract state var intrinsifyMemoryProbes = true; diff --git a/src/engine/compiler/CompilerOptions.v3 b/src/engine/compiler/CompilerOptions.v3 index 55c27f540..e645f3e3e 100644 --- a/src/engine/compiler/CompilerOptions.v3 +++ b/src/engine/compiler/CompilerOptions.v3 @@ -33,8 +33,10 @@ component CompilerOptions { .onSet(fun v => void(SpcTuning.maxInlineBytecodeSize = v)); group.newIntOption("inline-max-params", SpcTuning.maxInlineParams, "Maximum number of parameters of a function that can be inlined.") .onSet(fun v => void(SpcTuning.maxInlineParams = v)); - group.newIntOption("inline-max-depth", SpcTuning.maxInlineDepth, "Maximum inlining nesting depth.") + group.newIntOption("inline-max-depth", SpcTuning.maxInlineDepth, "Maximum inlining nesting depth for regular (non-fast) functions.") .onSet(fun v => void(SpcTuning.maxInlineDepth = v)); + group.newIntOption("fast-inline-max-depth", SpcTuning.maxFastInlineDepth, "Maximum inlining nesting depth for fast functions.") + .onSet(fun v => void(SpcTuning.maxFastInlineDepth = v)); } def printHelp(out: TraceBuilder) { diff --git a/src/engine/compiler/SinglePassCompiler.v3 b/src/engine/compiler/SinglePassCompiler.v3 index 22ba607ce..4fbc1a5be 100644 --- a/src/engine/compiler/SinglePassCompiler.v3 +++ b/src/engine/compiler/SinglePassCompiler.v3 @@ -2838,9 +2838,9 @@ class SinglePassCompiler(xenv: SpcExecEnv, masm: MacroAssembler, regAlloc: RegAl def shouldInline(func: FuncDecl) -> bool { if (Trace.compiler) OUT.put1("deciding on inlining call to func #%d: ", func.func_index); - if (FastIntTuning.useFastFunctions && !fast) return no("fast functions enabled and this is not a fast function"); if (func.imp != null) return no("imported"); - if (inlineDepth() >= SpcTuning.maxInlineDepth) return no("max inline depth exceeded"); + var maxDepth = if(fast, SpcTuning.maxFastInlineDepth, SpcTuning.maxInlineDepth); + if (inlineDepth() >= maxDepth) return no("max inline depth exceeded"); if (func.orig_bytecode.length > SpcTuning.maxInlineBytecodeSize) return no("func too large"); if (func.sig.params.length > SpcTuning.maxInlineParams) return no("too many parameters"); diff --git a/test/fastcall/test21_inline_simple.wasm.flags b/test/fastcall/test21_inline_simple.wasm.flags index 15e24ecd1..95334cb1b 100644 --- a/test/fastcall/test21_inline_simple.wasm.flags +++ b/test/fastcall/test21_inline_simple.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=1 +--fast-functions=true --fast-inline-max-depth=1 diff --git a/test/fastcall/test22_inline_control.wasm.flags b/test/fastcall/test22_inline_control.wasm.flags index 15e24ecd1..95334cb1b 100644 --- a/test/fastcall/test22_inline_control.wasm.flags +++ b/test/fastcall/test22_inline_control.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=1 +--fast-functions=true --fast-inline-max-depth=1 diff --git a/test/fastcall/test23_inline_with_locals.wasm.flags b/test/fastcall/test23_inline_with_locals.wasm.flags index 15e24ecd1..95334cb1b 100644 --- a/test/fastcall/test23_inline_with_locals.wasm.flags +++ b/test/fastcall/test23_inline_with_locals.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=1 +--fast-functions=true --fast-inline-max-depth=1 diff --git a/test/fastcall/test24_inline_depth2.wasm.flags b/test/fastcall/test24_inline_depth2.wasm.flags index d87b35653..3c975201d 100644 --- a/test/fastcall/test24_inline_depth2.wasm.flags +++ b/test/fastcall/test24_inline_depth2.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=2 +--fast-functions=true --fast-inline-max-depth=2 diff --git a/test/fastcall/test25_outcall_depth0.wasm.flags b/test/fastcall/test25_outcall_depth0.wasm.flags index 3920956e2..5af99f22a 100644 --- a/test/fastcall/test25_outcall_depth0.wasm.flags +++ b/test/fastcall/test25_outcall_depth0.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=0 +--fast-functions=true --fast-inline-max-depth=0 diff --git a/test/fastcall/test26_outcall_depth1.wasm.flags b/test/fastcall/test26_outcall_depth1.wasm.flags index 15e24ecd1..95334cb1b 100644 --- a/test/fastcall/test26_outcall_depth1.wasm.flags +++ b/test/fastcall/test26_outcall_depth1.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=1 +--fast-functions=true --fast-inline-max-depth=1 diff --git a/test/fastcall/test27_outcall_stackframe.wasm.flags b/test/fastcall/test27_outcall_stackframe.wasm.flags index 92df8e667..893da2d53 100644 --- a/test/fastcall/test27_outcall_stackframe.wasm.flags +++ b/test/fastcall/test27_outcall_stackframe.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=0 \ No newline at end of file +--fast-functions=true --fast-inline-max-depth=0 \ No newline at end of file diff --git a/test/fastcall/test28_trap_mid_function.wasm.flags b/test/fastcall/test28_trap_mid_function.wasm.flags index 3920956e2..5af99f22a 100644 --- a/test/fastcall/test28_trap_mid_function.wasm.flags +++ b/test/fastcall/test28_trap_mid_function.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=0 +--fast-functions=true --fast-inline-max-depth=0 diff --git a/test/fastcall/test29_inline_then_outcall_trap.wasm.flags b/test/fastcall/test29_inline_then_outcall_trap.wasm.flags index 15e24ecd1..95334cb1b 100644 --- a/test/fastcall/test29_inline_then_outcall_trap.wasm.flags +++ b/test/fastcall/test29_inline_then_outcall_trap.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=1 +--fast-functions=true --fast-inline-max-depth=1 diff --git a/test/fastcall/test30_inline_depth2_outcall_trap.wasm.flags b/test/fastcall/test30_inline_depth2_outcall_trap.wasm.flags index d87b35653..3c975201d 100644 --- a/test/fastcall/test30_inline_depth2_outcall_trap.wasm.flags +++ b/test/fastcall/test30_inline_depth2_outcall_trap.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=2 +--fast-functions=true --fast-inline-max-depth=2 diff --git a/test/fastcall/test31_fast_below_spc_trap.wasm.flags b/test/fastcall/test31_fast_below_spc_trap.wasm.flags index 3920956e2..5af99f22a 100644 --- a/test/fastcall/test31_fast_below_spc_trap.wasm.flags +++ b/test/fastcall/test31_fast_below_spc_trap.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=0 +--fast-functions=true --fast-inline-max-depth=0 diff --git a/test/fastcall/test32_inline_then_spc_trap.wasm.flags b/test/fastcall/test32_inline_then_spc_trap.wasm.flags index 15e24ecd1..95334cb1b 100644 --- a/test/fastcall/test32_inline_then_spc_trap.wasm.flags +++ b/test/fastcall/test32_inline_then_spc_trap.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=1 +--fast-functions=true --fast-inline-max-depth=1 diff --git a/test/fastcall/test33_fast_self_trap.wasm.flags b/test/fastcall/test33_fast_self_trap.wasm.flags index 3920956e2..5af99f22a 100644 --- a/test/fastcall/test33_fast_self_trap.wasm.flags +++ b/test/fastcall/test33_fast_self_trap.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=0 +--fast-functions=true --fast-inline-max-depth=0 diff --git a/test/fastcall/test34_second_outcall_trap.wasm.flags b/test/fastcall/test34_second_outcall_trap.wasm.flags index 3920956e2..5af99f22a 100644 --- a/test/fastcall/test34_second_outcall_trap.wasm.flags +++ b/test/fastcall/test34_second_outcall_trap.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=0 +--fast-functions=true --fast-inline-max-depth=0 diff --git a/test/fastcall/test41_inline_loop.wasm.flags b/test/fastcall/test41_inline_loop.wasm.flags index 15e24ecd1..95334cb1b 100644 --- a/test/fastcall/test41_inline_loop.wasm.flags +++ b/test/fastcall/test41_inline_loop.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=1 +--fast-functions=true --fast-inline-max-depth=1 diff --git a/test/fastcall/test42_inline_memory.wasm.flags b/test/fastcall/test42_inline_memory.wasm.flags index 15e24ecd1..95334cb1b 100644 --- a/test/fastcall/test42_inline_memory.wasm.flags +++ b/test/fastcall/test42_inline_memory.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=1 +--fast-functions=true --fast-inline-max-depth=1 diff --git a/test/fastcall/test43_inline_global.wasm.flags b/test/fastcall/test43_inline_global.wasm.flags index 15e24ecd1..95334cb1b 100644 --- a/test/fastcall/test43_inline_global.wasm.flags +++ b/test/fastcall/test43_inline_global.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=1 +--fast-functions=true --fast-inline-max-depth=1 diff --git a/test/fastcall/test44_inline_depth3.wasm.flags b/test/fastcall/test44_inline_depth3.wasm.flags index a0d56bcb0..bb0ce3e84 100644 --- a/test/fastcall/test44_inline_depth3.wasm.flags +++ b/test/fastcall/test44_inline_depth3.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=3 +--fast-functions=true --fast-inline-max-depth=3 diff --git a/test/fastcall/test48_large_inline.wasm.flags b/test/fastcall/test48_large_inline.wasm.flags index 15e24ecd1..95334cb1b 100644 --- a/test/fastcall/test48_large_inline.wasm.flags +++ b/test/fastcall/test48_large_inline.wasm.flags @@ -1 +1 @@ ---fast-functions=true --inline-max-depth=1 +--fast-functions=true --fast-inline-max-depth=1